private AggregationPeriodSummary CycleAggregators(
            ref AggregatorCollection aggregators,
            DateTimeOffset tactTimestamp,
            IMetricSeriesFilter futureFilter,
            bool stopAggregators)
        {
            if (aggregators == _aggregatorsForPersistent)
            {
                throw new InvalidOperationException("Invernal SDK bug. Please report. Cannot cycle persistent aggregators.");
            }

            tactTimestamp = Util.RoundDownToSecond(tactTimestamp);

            // For non-persistent aggregators: create empty holder for the next aggregation period and swap for the previous holder:
            AggregatorCollection prevAggregators;

            if (stopAggregators)
            {
                prevAggregators = Interlocked.Exchange(ref aggregators, null);
            }
            else
            {
                AggregatorCollection nextAggregators = new AggregatorCollection(tactTimestamp, futureFilter);
                prevAggregators = Interlocked.Exchange(ref aggregators, nextAggregators);
            }

            List <MetricAggregate> persistentValsAggregations = GetPersistentAggregations(tactTimestamp, prevAggregators?.Filter);
            List <MetricAggregate> nonpersistentAggregations  = GetNonpersistentAggregations(tactTimestamp, prevAggregators);

            var summary = new AggregationPeriodSummary(persistentValsAggregations, nonpersistentAggregations);

            return(summary);
        }
 /// <summary>
 ///
 /// </summary>
 /// <param name="metricManager"></param>
 /// <param name="aggregationCycleKind"></param>
 /// <param name="tactTimestamp"></param>
 /// <param name="futureFilter"></param>
 /// <returns></returns>
 public static AggregationPeriodSummary StartOrCycleAggregators(
     this MetricManager metricManager,
     MetricAggregationCycleKind aggregationCycleKind,
     DateTimeOffset tactTimestamp,
     IMetricSeriesFilter futureFilter)
 {
     Util.ValidateNotNull(metricManager, nameof(metricManager));
     return(metricManager.AggregationManager.StartOrCycleAggregators(aggregationCycleKind, tactTimestamp, futureFilter));
 }
 public static bool FilterWillConsume(IMetricSeriesFilter seriesFilter, MetricSeries series, out IMetricValueFilter valueFilter)
 {
     valueFilter = null;
     try
     {
         return((seriesFilter == null) || seriesFilter.WillConsume(series, out valueFilter));
     }
     catch
     {
         // Protect against errors in user's implementation of IMetricSeriesFilter.WillConsume(..).
         // If it throws, assume that the filter is not functional and accept all values.
         return(true);
     }
 }
        internal bool IsCycleActive(MetricAggregationCycleKind aggregationCycleKind, out IMetricSeriesFilter filter)
        {
            switch (aggregationCycleKind)
            {
            case CycleKind.Default:
                filter = null;
                return(true);

            case CycleKind.QuickPulse:
            case CycleKind.Custom:
                AggregatorCollection aggs = (aggregationCycleKind == CycleKind.QuickPulse) ? _aggregatorsForQuickPulse : _aggregatorsForCustom;
                filter = aggs?.Filter;
                return(aggs != null);

            default:
                throw new ArgumentException($"Unexpected value of {nameof(aggregationCycleKind)}: {aggregationCycleKind}.");
            }
        }
        private static bool AddAggregator(IMetricSeriesAggregator aggregator, AggregatorCollection aggregatorCollection)
        {
            if (aggregatorCollection == null)
            {
                return(false);
            }

            IMetricSeriesFilter seriesFilter = aggregatorCollection.Filter;
            IMetricValueFilter  valueFilter  = null;

            if (seriesFilter != null && !seriesFilter.WillConsume(aggregator.DataSeries, out valueFilter))
            {
                return(false);
            }

            aggregator.Reset(aggregatorCollection.PeriodStart, valueFilter);
            aggregatorCollection.Aggregators.Add(aggregator);

            return(true);
        }
        private static bool AddAggregator(IMetricSeriesAggregator aggregator, AggregatorCollection aggregatorCollection)
        {
            if (aggregatorCollection == null)
            {
                return(false);
            }

            IMetricSeriesFilter seriesFilter = aggregatorCollection.Filter;
            IMetricValueFilter  valueFilter;

            if (false == Util.FilterWillConsume(seriesFilter, aggregator.DataSeries, out valueFilter))
            {
                return(false);
            }

            // @ToDo
            // @PublicExposureCandidate
            // aggregator.Reset(aggregatorCollection.PeriodStart, valueFilter);
            aggregator.Reset(aggregatorCollection.PeriodStart);

            aggregatorCollection.Aggregators.Add(aggregator);

            return(true);
        }
        public AggregationPeriodSummary StartOrCycleAggregators(MetricAggregationCycleKind aggregationCycleKind, DateTimeOffset tactTimestamp, IMetricSeriesFilter futureFilter)
        {
            switch (aggregationCycleKind)
            {
            case CycleKind.Default:
                if (futureFilter != null)
                {
                    throw new ArgumentException($"Cannot specify non-null {nameof(futureFilter)} when {nameof(aggregationCycleKind)} is {aggregationCycleKind}.");
                }

                return(CycleAggregators(ref _aggregatorsForDefault, tactTimestamp, futureFilter, stopAggregators: false));

            case CycleKind.QuickPulse:
                return(CycleAggregators(ref _aggregatorsForQuickPulse, tactTimestamp, futureFilter, stopAggregators: false));

            case CycleKind.Custom:
                return(CycleAggregators(ref _aggregatorsForCustom, tactTimestamp, futureFilter, stopAggregators: false));

            default:
                throw new ArgumentException($"Unexpected value of {nameof(aggregationCycleKind)}: {aggregationCycleKind}.");
            }
        }
 public AggregatorCollection(DateTimeOffset periodStart, IMetricSeriesFilter filter)
 {
     this.PeriodStart = periodStart;
     this.Aggregators = new GrowingCollection <IMetricSeriesAggregator>();
     this.Filter      = filter;
 }
        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 = _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 = (previousFilter == null)
                                               ||
                                               (previousFilter.WillConsume(aggregator.DataSeries, out unusedValueFilter));
                        if (satisfiesFilter)
                        {
                            MetricAggregate aggregate = aggregator.CompleteAggregation(tactTimestamp);

                            if (aggregate != null)
                            {
                                persistentValsAggregations.Add(aggregate);
                            }
                        }
                    }
                }
            }
            finally
            {
                persistentValsAggregators.Dispose();
            }

            return(persistentValsAggregations);
        }