예제 #1
0
        private void CalculateRoutingTables()
        {
            long startTime = DateTime.UtcNow.Ticks;
            Time elapsedTime;

            IInputAdapter[]  inputAdapterCollection  = null;
            IActionAdapter[] actionAdapterCollection = null;
            IOutputAdapter[] outputAdapterCollection = null;
            bool             retry = true;

            OnStatusMessage("Starting measurement route calculation...");

            // Attempt to cache input, action, and output adapters for routing table calculation.
            // This could fail if another thread modifies the collections while caching is in
            // progress (rare), so retry if the caching fails.
            //
            // We don't attempt to lock here because we don't own the collections.
            while (retry)
            {
                try
                {
                    if ((object)m_inputAdapters != null)
                    {
                        inputAdapterCollection = m_inputAdapters.ToArray <IInputAdapter>();
                    }

                    if ((object)m_actionAdapters != null)
                    {
                        actionAdapterCollection = m_actionAdapters.ToArray <IActionAdapter>();
                    }

                    if ((object)m_outputAdapters != null)
                    {
                        outputAdapterCollection = m_outputAdapters.ToArray <IOutputAdapter>();
                    }

                    retry = false;
                }
                catch (InvalidOperationException)
                {
                    // Attempt to catch "Collection was modified; enumeration operation may not execute."
                }
                catch (NullReferenceException)
                {
                    // Catch rare exceptions where IaonSession is disposed during a context switch
                    inputAdapterCollection  = null;
                    actionAdapterCollection = null;
                    outputAdapterCollection = null;
                    retry = false;
                }
            }

            try
            {
                HashSet <IAdapter> consumerAdapters;
                HashSet <IAdapter> producerAdapters;

                // Get a full list of all producer (input/action) adapters
                producerAdapters = new HashSet <IAdapter>((inputAdapterCollection ?? Enumerable.Empty <IAdapter>())
                                                          .Concat(actionAdapterCollection ?? Enumerable.Empty <IAdapter>()));

                // Get a full list of all consumer (action/output) adapters
                consumerAdapters = new HashSet <IAdapter>((actionAdapterCollection ?? Enumerable.Empty <IAdapter>())
                                                          .Concat(outputAdapterCollection ?? Enumerable.Empty <IAdapter>()));

                var producerChanges = new RoutingTablesAdaptersList(m_prevCalculatedProducers, producerAdapters);
                var consumerChanges = new RoutingTablesAdaptersList(m_prevCalculatedConsumers, consumerAdapters);

                m_routeMappingTables.PatchRoutingTable(producerChanges, consumerChanges);
                m_prevCalculatedProducers = producerAdapters;
                m_prevCalculatedConsumers = consumerAdapters;

                // Start or stop any connect on demand adapters
                HandleConnectOnDemandAdapters(new HashSet <MeasurementKey>(m_inputMeasurementKeysRestriction ?? Enumerable.Empty <MeasurementKey>()), inputAdapterCollection, actionAdapterCollection, outputAdapterCollection);

                elapsedTime = Ticks.ToSeconds(DateTime.UtcNow.Ticks - startTime);

                int routeCount       = m_routeMappingTables.RouteCount;
                int destinationCount = consumerAdapters.Count;

                OnStatusMessage("Calculated {0} route{1} for {2} destination{3} in {4}.", routeCount, (routeCount == 1) ? "" : "s", destinationCount, (destinationCount == 1) ? "" : "s", elapsedTime.ToString(2));
            }
            catch (ObjectDisposedException)
            {
                // Ignore this error. Seems to happen during normal
                // operation and does not affect the result.
            }
            catch (Exception ex)
            {
                OnProcessException(new InvalidOperationException("Routing tables calculation error: " + ex.Message, ex));
            }
        }
예제 #2
0
        private void CalculateRoutingTables()
        {
            long startTime = DateTime.UtcNow.Ticks;
            Time elapsedTime;

            int destinationCount = 0;
            int routeCount;

            IInputAdapter[]  inputAdapterCollection  = null;
            IActionAdapter[] actionAdapterCollection = null;
            IOutputAdapter[] outputAdapterCollection = null;
            bool             retry = true;

            OnStatusMessage("Starting measurement route calculation...");

            // Attempt to cache input, action, and output adapters for routing table calculation.
            // This could fail if another thread modifies the collections while caching is in
            // progress (rare), so retry if the caching fails.
            //
            // We don't attempt to lock here because we don't own the collections.
            while (retry)
            {
                try
                {
                    if ((object)m_inputAdapters != null)
                    {
                        inputAdapterCollection = m_inputAdapters.ToArray <IInputAdapter>();
                    }

                    if ((object)m_actionAdapters != null)
                    {
                        actionAdapterCollection = m_actionAdapters.ToArray <IActionAdapter>();
                    }

                    if ((object)m_outputAdapters != null)
                    {
                        outputAdapterCollection = m_outputAdapters.ToArray <IOutputAdapter>();
                    }

                    retry = false;
                }
                catch (InvalidOperationException)
                {
                    // Attempt to catch "Collection was modified; enumeration operation may not execute."
                }
                catch (NullReferenceException)
                {
                    // Catch rare exceptions where IaonSession is disposed during a context switch
                    inputAdapterCollection  = null;
                    actionAdapterCollection = null;
                    outputAdapterCollection = null;
                    retry = false;
                }
            }

            try
            {
                GlobalCache globalCache;

                Dictionary <Guid, List <Consumer> > globalSignalLookup;
                Dictionary <IAdapter, Consumer>     globalDestinationLookup;
                List <Consumer> broadcastConsumers;

                HashSet <IAdapter> producerAdapters;
                IInputAdapter      inputAdapter;

                IEnumerable <IAdapter> consumerAdapters;
                Consumer consumer;

                // Get the global cache from the last routing tables calculation
                globalCache = Interlocked.CompareExchange(ref m_globalCache, null, null);

                // Create collections to be entered into the new global cache
                globalSignalLookup      = new Dictionary <Guid, List <Consumer> >();
                globalDestinationLookup = new Dictionary <IAdapter, Consumer>();
                broadcastConsumers      = new List <Consumer>();

                // Get a full list of all producer (input/action) adapters
                producerAdapters = new HashSet <IAdapter>((inputAdapterCollection ?? Enumerable.Empty <IAdapter>())
                                                          .Concat(actionAdapterCollection ?? Enumerable.Empty <IAdapter>()));

                // Attach to NewMeasurements event of all producer adapters
                foreach (IAdapter producerAdapter in producerAdapters)
                {
                    if ((object)globalCache == null || !globalCache.ProducerAdapters.Contains(producerAdapter))
                    {
                        inputAdapter = producerAdapter as IInputAdapter;

                        if ((object)inputAdapter != null)
                        {
                            inputAdapter.NewMeasurements += GetRoutedMeasurementsHandler();
                        }
                        else
                        {
                            ((IActionAdapter)producerAdapter).NewMeasurements += GetRoutedMeasurementsHandler();
                        }
                    }
                }

                // Get a full list of all consumer (action/output) adapters
                consumerAdapters = (actionAdapterCollection ?? Enumerable.Empty <IAdapter>())
                                   .Concat(outputAdapterCollection ?? Enumerable.Empty <IAdapter>());

                // Generate routes for all signals received by each consumer adapter
                foreach (IAdapter consumerAdapter in consumerAdapters)
                {
                    // Search the old global cache for an existing consumer for this adapter
                    if ((object)globalCache == null || !globalCache.GlobalDestinationLookup.TryGetValue(consumerAdapter, out consumer))
                    {
                        consumer = new Consumer(consumerAdapter, OnProcessException);
                    }

                    if ((object)consumerAdapter.InputMeasurementKeys != null)
                    {
                        // Create routes for each of the consumer's input signals
                        foreach (Guid signalID in consumerAdapter.InputMeasurementKeys.Select(key => key.SignalID))
                        {
                            globalSignalLookup.GetOrAdd(signalID, id => new List <Consumer>()).Add(consumer);
                        }
                    }
                    else
                    {
                        // Add this consumer to the broadcast routes to begin receiving all measurements
                        broadcastConsumers.Add(consumer);
                    }

                    // Add this adapter to the global destinations lookup
                    globalDestinationLookup.Add(consumerAdapter, consumer);
                    destinationCount++;
                }

                // Broadcast consumers receive all measurements, so add them to every signal route
                foreach (List <Consumer> consumerList in globalSignalLookup.Values)
                {
                    consumerList.AddRange(broadcastConsumers);
                }

                // Swap the new global cache with the old one and increment the version number
                Interlocked.Exchange(ref m_globalCache, new GlobalCache()
                {
                    ProducerAdapters        = producerAdapters,
                    GlobalSignalLookup      = globalSignalLookup,
                    GlobalDestinationLookup = globalDestinationLookup,
                    BroadcastConsumers      = broadcastConsumers,
                    Version = (object)globalCache != null ? globalCache.Version + 1 : 0
                });

                // Start or stop any connect on demand adapters
                HandleConnectOnDemandAdapters(new HashSet <MeasurementKey>(m_inputMeasurementKeysRestriction ?? Enumerable.Empty <MeasurementKey>()), inputAdapterCollection, actionAdapterCollection, outputAdapterCollection);

                elapsedTime = Ticks.ToSeconds(DateTime.UtcNow.Ticks - startTime);
                routeCount  = globalSignalLookup.Count;

                OnStatusMessage("Calculated {0} route{1} for {2} destination{3} in {4}.", routeCount, (routeCount == 1) ? "" : "s", destinationCount, (destinationCount == 1) ? "" : "s", elapsedTime.ToString(2));
            }
            catch (ObjectDisposedException)
            {
                // Ignore this error. Seems to happen during normal
                // operation and does not affect the result.
            }
            catch (Exception ex)
            {
                OnProcessException(new InvalidOperationException("Routing tables calculation error: " + ex.Message, ex));
            }
        }