private static bool AddAggregator(IMetricSeriesAggregator aggregator, AggregatorCollection aggregatorCollection) { if (aggregatorCollection == null) { return(false); } IMetricSeriesFilter seriesFilter = aggregatorCollection.Filter; IMetricValueFilter valueFilter; if (!Util.FilterWillConsume(seriesFilter, aggregator.DataSeries, out valueFilter)) { return(false); } aggregator.Reset(aggregatorCollection.PeriodStart, valueFilter); aggregatorCollection.Aggregators.Add(aggregator); return(true); }
private List <MetricAggregate> GetPersistentAggregations(DateTimeOffset tactTimestamp, IMetricSeriesFilter previousFilter) { // Complete each persistent aggregator: // The Enumerator of GrowingCollection is a thread-safe lock-free implementation that operates on a "snapshot" of a collection taken at the // time when the enumerator is created. We expand the foreach statement (like the compiler normally does) so that we can use the typed // enumerator's Count property which is constsent with the data in the snapshot. GrowingCollection <IMetricSeriesAggregator> .Enumerator persistentValsAggregators = this.aggregatorsForPersistent.Aggregators.GetEnumerator(); List <MetricAggregate> persistentValsAggregations = new List <MetricAggregate>(capacity: persistentValsAggregators.Count); try { while (persistentValsAggregators.MoveNext()) { IMetricSeriesAggregator aggregator = persistentValsAggregators.Current; if (aggregator != null) { // Persistent aggregators are always active, regardless of filters for a particular cycle. // But we can apply the cycle's filters to determine whether or not to pull the aggregator // for a aggregate at this time. Of course, only series filters, not value filters, can be considered. IMetricValueFilter unusedValueFilter; bool satisfiesFilter = Util.FilterWillConsume(previousFilter, aggregator.DataSeries, out unusedValueFilter); if (satisfiesFilter) { MetricAggregate aggregate = aggregator.CompleteAggregation(tactTimestamp); if (aggregate != null) { persistentValsAggregations.Add(aggregate); } } } } } finally { persistentValsAggregators.Dispose(); } return(persistentValsAggregations); }
private IMetricSeriesAggregator GetOrCreateAggregator(MetricAggregationCycleKind aggregationCycleKind, ref WeakReference <IMetricSeriesAggregator> aggregatorWeakRef) { while (true) { // Local cache for the reference in case of concurrnet updates: WeakReference <IMetricSeriesAggregator> currentAggregatorWeakRef = aggregatorWeakRef; // Try to dereference the weak reference: IMetricSeriesAggregator aggregatorHardRef = UnwrapAggregator(currentAggregatorWeakRef); if (aggregatorHardRef != null) { return(aggregatorHardRef); } // END OF FAST PATH. Could not dereference aggregator. Will attempt to create it... // So aggretator is NULL. For non-default cycle kinds, see if the there is even a cycle hooked up: if (aggregationCycleKind != CycleKind.Default) { IMetricSeriesFilter dataSeriesFilter; if (false == this.aggregationManager.IsCycleActive(aggregationCycleKind, out dataSeriesFilter)) { return(null); } // Ok, a cycle is, indeed, acgive up. See if the cycle's filter is interested in this series: // Respect the filter. Note: Filter may be user code. If user code is broken, assume we accept the series. IMetricValueFilter valuesFilter; if (false == Util.FilterWillConsume(dataSeriesFilter, this, out valuesFilter)) { return(null); } } // Ok, they want to consume us. Create new aggregator and a weak reference to it: IMetricSeriesAggregator newAggregator = this.GetNewOrRecycledAggregatorInstance(aggregationCycleKind); WeakReference <IMetricSeriesAggregator> newAggregatorWeakRef = new WeakReference <IMetricSeriesAggregator>(newAggregator, trackResurrection: false); // Store the weak reference to the aggregator. However, there is a race on doing it, so check for it: WeakReference <IMetricSeriesAggregator> prevAggregatorWeakRef = Interlocked.CompareExchange(ref aggregatorWeakRef, newAggregatorWeakRef, currentAggregatorWeakRef); if (prevAggregatorWeakRef == currentAggregatorWeakRef) { // We won the race and stored the aggregator. Now tell the manager about it and go on using it. // Note that the status of IsCycleActive and the dataSeriesFilter may have changed concurrently. // So it is essential that we do this after the above interlocked assignment of aggregator. // It ensures that only objects are added to the aggregator collection that are also referenced by the data series. // In addition, AddAggregator(..) always uses the current value of the aggregator-collection in a thread-safe manner. // Becasue the aggregator collection reference is always updated before telling the aggregators to cycle, // we know that any aggregator added will be eventually cycled. // If adding succeeds, AddAggregator(..) will have set the correct filter. bool added = this.aggregationManager.AddAggregator(newAggregator, aggregationCycleKind); // If the manager does not accept the addition, it means that the aggregationCycleKind is disabled or that the filter is not interested in this data series. // Either way we need to give up. if (added) { return(newAggregator); } else { // We could have accepted some values into this aggregator in the short time it was set in this series. We will loose those values. Interlocked.CompareExchange(ref aggregatorWeakRef, null, newAggregatorWeakRef); return(null); } } // We lost the race and a different aggregator was used. Loop again. Doing so will attempt to dereference the latest aggregator reference. } }