802 lines · 37.6 KB · C#
RawDownload
//******************************************************************************************************//  RoutingTables.cs - Gbtc////  Copyright © 2010, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may//  not use this file except in compliance with the License. You may obtain a copy of the License at:////      http://www.opensource.org/licenses/eclipse-1.0.php////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  06/30/2011 - J. Ritchie Carroll//       Generated original version of source code.//  07/25/2011 - J. Ritchie Carroll//       Added code to handle connect on demand adapters (i.e., where AutoStart = false).////****************************************************************************************************** using GSF.Collections;using System;using System.Collections.Generic;using System.Linq;using System.Threading; namespace GSF.TimeSeries.Adapters{    /// <summary>    /// Represents the routing tables for the Iaon adapters.    /// </summary>    public class RoutingTables : IDisposable    {        #region [ Members ]         // Events         /// <summary>        /// Event is raised when there is an exception encountered while processing.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the exception that was thrown.        /// </remarks>        public event EventHandler<EventArgs<Exception>> ProcessException;         // Fields        private InputAdapterCollection m_inputAdapters;        private ActionAdapterCollection m_actionAdapters;        private OutputAdapterCollection m_outputAdapters;        private Dictionary<MeasurementKey, List<IActionAdapter>> m_actionRoutes;        private Dictionary<MeasurementKey, List<IOutputAdapter>> m_outputRoutes;        private List<IActionAdapter> m_actionBroadcastRoutes;        private List<IOutputAdapter> m_outputBroadcastRoutes;        private ReaderWriterLockSlim m_adapterRoutesCacheLock;        private AutoResetEvent m_calculationComplete;        private object m_queuedCalculationPending;        private bool m_disposed;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new instance of the <see cref="RoutingTables"/> class.        /// </summary>        public RoutingTables()        {            m_adapterRoutesCacheLock = new ReaderWriterLockSlim();            m_calculationComplete = new AutoResetEvent(true);            m_queuedCalculationPending = new object();        }         /// <summary>        /// Releases the unmanaged resources before the <see cref="RoutingTables"/> object is reclaimed by <see cref="GC"/>.        /// </summary>        ~RoutingTables()        {            Dispose(false);        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets or sets the active <see cref="InputAdapterCollection"/>.        /// </summary>        public InputAdapterCollection InputAdapters        {            get            {                return m_inputAdapters;            }            set            {                m_inputAdapters = value;            }        }         /// <summary>        /// Gets or sets the active <see cref="ActionAdapterCollection"/>.        /// </summary>        public ActionAdapterCollection ActionAdapters        {            get            {                return m_actionAdapters;            }            set            {                m_actionAdapters = value;            }        }         /// <summary>        /// Gets or sets the active <see cref="OutputAdapterCollection"/>.        /// </summary>        public OutputAdapterCollection OutputAdapters        {            get            {                return m_outputAdapters;            }            set            {                m_outputAdapters = value;            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Releases all the resources used by the <see cref="RoutingTables"/> object.        /// </summary>        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }         /// <summary>        /// Releases the unmanaged resources used by the <see cref="RoutingTables"/> object and optionally releases the managed resources.        /// </summary>        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>        protected virtual void Dispose(bool disposing)        {            if (!m_disposed)            {                try                {                    if (disposing)                    {                        m_actionRoutes = null;                        m_outputRoutes = null;                        m_actionBroadcastRoutes = null;                        m_outputBroadcastRoutes = null;                        m_inputAdapters = null;                        m_actionAdapters = null;                        m_outputAdapters = null;                         if ((object)m_adapterRoutesCacheLock != null)                            m_adapterRoutesCacheLock.Dispose();                         m_adapterRoutesCacheLock = null;                         if ((object)m_calculationComplete != null)                        {                            // Release any waiting threads before disposing wait handle                            m_calculationComplete.Set();                            m_calculationComplete.Close();                        }                         m_calculationComplete = null;                    }                }                finally                {                    m_disposed = true;  // Prevent duplicate dispose.                }            }        }         /// <summary>        /// Spawn routing tables recalculation.        /// </summary>        /// <param name="inputMeasurementKeysRestriction">Input measurement keys restriction.</param>        /// <remarks>        /// Set the <paramref name="inputMeasurementKeysRestriction"/> to null to use full adapter I/O routing demands.        /// </remarks>        public virtual void CalculateRoutingTables(MeasurementKey[] inputMeasurementKeysRestriction)        {            try            {                ThreadPool.QueueUserWorkItem(QueueRoutingTableCalculation, inputMeasurementKeysRestriction);            }            catch (Exception ex)            {                // Process exception for logging                OnProcessException(new InvalidOperationException("Failed to queue routing table calculation: " + ex.Message, ex));            }        }         private void QueueRoutingTableCalculation(object state)        {            try            {                // Queue up a routing table calculation unless another thread has already requested one                if (!m_disposed && Monitor.TryEnter(m_queuedCalculationPending))                {                    try                    {                        // Queue new routing table calculation after waiting for any prior calculation to complete                        if (m_calculationComplete.WaitOne())                            ThreadPool.QueueUserWorkItem(CalculateRoutingTables, state);                    }                    finally                    {                        Monitor.Exit(m_queuedCalculationPending);                    }                }            }            catch (Exception ex)            {                // Process exception for logging                OnProcessException(new InvalidOperationException("Failed to queue routing table calculation: " + ex.Message, ex));            }        }         private void CalculateRoutingTables(object state)        {            try            {                // Pre-calculate internal routes to improve performance                Dictionary<MeasurementKey, List<IActionAdapter>> actionRoutes = new Dictionary<MeasurementKey, List<IActionAdapter>>();                Dictionary<MeasurementKey, List<IOutputAdapter>> outputRoutes = new Dictionary<MeasurementKey, List<IOutputAdapter>>();                List<IActionAdapter> actionAdapters, actionBroadcastRoutes = new List<IActionAdapter>();                List<IOutputAdapter> outputAdapters, outputBroadcastRoutes = new List<IOutputAdapter>();                MeasurementKey[] measurementKeys;                 if ((object)m_actionAdapters != null)                {                    lock (m_actionAdapters)                    {                        foreach (IActionAdapter actionAdapter in m_actionAdapters)                        {                            // Make sure adapter is initialized before calculating route                            if (actionAdapter.WaitForInitialize(actionAdapter.InitializationTimeout))                            {                                measurementKeys = actionAdapter.InputMeasurementKeys;                                 if ((object)measurementKeys != null)                                {                                    foreach (MeasurementKey key in measurementKeys)                                    {                                        if (!actionRoutes.TryGetValue(key, out actionAdapters))                                        {                                            actionAdapters = new List<IActionAdapter>();                                            actionRoutes.Add(key, actionAdapters);                                        }                                         if (!actionAdapters.Contains(actionAdapter))                                            actionAdapters.Add(actionAdapter);                                    }                                }                                else                                    actionBroadcastRoutes.Add(actionAdapter);                            }                            else                                actionBroadcastRoutes.Add(actionAdapter);                        }                    }                }                 if ((object)m_outputAdapters != null)                {                    lock (m_outputAdapters)                    {                        foreach (IOutputAdapter outputAdapter in m_outputAdapters)                        {                            // Make sure adapter is initialized before calculating route                            if (outputAdapter.WaitForInitialize(outputAdapter.InitializationTimeout))                            {                                measurementKeys = outputAdapter.InputMeasurementKeys;                                 if ((object)measurementKeys != null)                                {                                    foreach (MeasurementKey key in measurementKeys)                                    {                                        if (!outputRoutes.TryGetValue(key, out outputAdapters))                                        {                                            outputAdapters = new List<IOutputAdapter>();                                            outputRoutes.Add(key, outputAdapters);                                        }                                         if (!outputAdapters.Contains(outputAdapter))                                            outputAdapters.Add(outputAdapter);                                    }                                }                                else                                    outputBroadcastRoutes.Add(outputAdapter);                            }                            else                                outputBroadcastRoutes.Add(outputAdapter);                        }                    }                }                 // Synchronously update adapter routing cache                m_adapterRoutesCacheLock.EnterWriteLock();                 try                {                    m_actionRoutes = actionRoutes;                    m_outputRoutes = outputRoutes;                    m_actionBroadcastRoutes = actionBroadcastRoutes;                    m_outputBroadcastRoutes = outputBroadcastRoutes;                }                finally                {                    m_adapterRoutesCacheLock.ExitWriteLock();                }                 // Start or stop any connect on demand adapters                HandleConnectOnDemandAdapters((MeasurementKey[])state);            }            catch (Exception ex)            {                OnProcessException(new InvalidOperationException("Routing tables calculation error: " + ex.Message, ex));            }            finally            {                if ((object)m_calculationComplete != null)                    m_calculationComplete.Set();            }        }         /// <summary>        /// Event handler for distributing new measurements in a routed fashion.        /// </summary>        /// <param name="sender">Event source reference to adapter that generated new measurements.</param>        /// <param name="e">Event arguments containing a collection of new measurements.</param>        /// <remarks>        /// Time-series framework uses this handler to directly route new measurements to the action and output adapters.        /// </remarks>        public virtual void RoutedMeasurementsHandler(object sender, EventArgs<ICollection<IMeasurement>> e)        {            RoutedMeasurementsHandler(e.Argument);        }         /// <summary>        /// Method for distributing new measurements in a routed fashion.        /// </summary>        /// <param name="newMeasurements">Collection of new measurements.</param>        /// <remarks>        /// Time-series framework uses this handler to directly route new measurements to the action and output adapters.        /// </remarks>        public virtual void RoutedMeasurementsHandler(IEnumerable<IMeasurement> newMeasurements)        {            if ((object)m_actionRoutes == null || (object)m_outputRoutes == null)                return;             List<IActionAdapter> actionRoutes;            List<IOutputAdapter> outputRoutes;            Dictionary<IActionAdapter, List<IMeasurement>> actionMeasurements = new Dictionary<IActionAdapter, List<IMeasurement>>();            Dictionary<IOutputAdapter, List<IMeasurement>> outputMeasurements = new Dictionary<IOutputAdapter, List<IMeasurement>>();            List<IMeasurement> measurements;            MeasurementKey key;             m_adapterRoutesCacheLock.EnterReadLock();             try            {                // Loop through each new measurement and look for destination routes                foreach (IMeasurement measurement in newMeasurements)                {                    key = measurement.Key;                     if (m_actionRoutes.TryGetValue(key, out actionRoutes))                    {                        // Add measurements for each destination action adapter route                        foreach (IActionAdapter actionAdapter in actionRoutes)                        {                            if (!actionMeasurements.TryGetValue(actionAdapter, out measurements))                            {                                measurements = new List<IMeasurement>();                                actionMeasurements.Add(actionAdapter, measurements);                            }                             measurements.Add(measurement);                        }                    }                     if (m_outputRoutes.TryGetValue(key, out outputRoutes))                    {                        // Add measurements for each destination output adapter route                        foreach (IOutputAdapter outputAdapter in outputRoutes)                        {                            if (!outputMeasurements.TryGetValue(outputAdapter, out measurements))                            {                                measurements = new List<IMeasurement>();                                outputMeasurements.Add(outputAdapter, measurements);                            }                             measurements.Add(measurement);                        }                    }                }                 // Send broadcast action measurements                foreach (IActionAdapter actionAdapter in m_actionBroadcastRoutes)                {                    if (actionAdapter.Enabled)                        actionAdapter.QueueMeasurementsForProcessing(newMeasurements);                }                 // Send broadcast output measurements                foreach (IOutputAdapter outputAdapter in m_outputBroadcastRoutes)                {                    if (outputAdapter.Enabled)                        outputAdapter.QueueMeasurementsForProcessing(newMeasurements);                }            }            finally            {                m_adapterRoutesCacheLock.ExitReadLock();            }             // Send routed action measurements            foreach (KeyValuePair<IActionAdapter, List<IMeasurement>> actionAdapterMeasurements in actionMeasurements)            {                IActionAdapter actionAdapter = actionAdapterMeasurements.Key;                 if (actionAdapter.Enabled)                    actionAdapter.QueueMeasurementsForProcessing(actionAdapterMeasurements.Value);            }             // Send routed output measurements            foreach (KeyValuePair<IOutputAdapter, List<IMeasurement>> outputAdapterMeasurements in outputMeasurements)            {                IOutputAdapter outputAdapter = outputAdapterMeasurements.Key;                 if (outputAdapter.Enabled)                    outputAdapter.QueueMeasurementsForProcessing(outputAdapterMeasurements.Value);            }        }         /// <summary>        /// Event handler for distributing new measurements in a broadcast fashion.        /// </summary>        /// <param name="sender">Event source reference to adapter that generated new measurements.</param>        /// <param name="e">Event arguments containing a collection of new measurements.</param>        /// <remarks>        /// Time-series framework uses this handler to route new measurements to the action and output adapters; adapter will handle filtering.        /// </remarks>        public virtual void BroadcastMeasurementsHandler(object sender, EventArgs<ICollection<IMeasurement>> e)        {            ICollection<IMeasurement> newMeasurements = e.Argument;             m_actionAdapters.QueueMeasurementsForProcessing(newMeasurements);            m_outputAdapters.QueueMeasurementsForProcessing(newMeasurements);        }         /// <summary>        /// Raises <see cref="ProcessException"/> event.        /// </summary>        /// <param name="ex">Processing <see cref="Exception"/>.</param>        protected virtual void OnProcessException(Exception ex)        {            if ((object)ProcessException != null)                ProcessException(this, new EventArgs<Exception>(ex));        }         /// <summary>        /// Starts or stops connect on demand adapters based on current state of demanded input or output measurements.        /// </summary>        /// <param name="inputMeasurementKeysRestriction">Input measurement keys restriction.</param>        /// <remarks>        /// Set the <paramref name="inputMeasurementKeysRestriction"/> to null to use full adapter routing demands.        /// </remarks>        protected virtual void HandleConnectOnDemandAdapters(MeasurementKey[] inputMeasurementKeysRestriction)        {            IEnumerable<MeasurementKey> outputMeasurementKeys = null;            IEnumerable<MeasurementKey> inputMeasurementKeys = null;            MeasurementKey[] requestedOutputMeasurementKeys, requestedInputMeasurementKeys, emptyKeys = new MeasurementKey[0];             if ((object)inputMeasurementKeysRestriction != null && inputMeasurementKeysRestriction.Any())            {                // When an input measurement keys restriction has been defined, extract the needed input and output measurement keys by                // walking the dependency chain of the restriction                TraverseMeasurementKeyDependencyChain(inputMeasurementKeysRestriction, out outputMeasurementKeys, out inputMeasurementKeys);            }            else            {

Lines 1–500 of 802.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t