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)); } }
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)); } }