internal void ClearAggregator(MetricAggregationCycleKind aggregationCycleKind) { if (this.requiresPersistentAggregator) { return; } WeakReference <IMetricSeriesAggregator> aggregatorWeakRef; switch (aggregationCycleKind) { case CycleKind.Default: aggregatorWeakRef = Interlocked.Exchange(ref this.aggregatorDefault, null); this.aggregatorRecycleCacheDefault = UnwrapAggregator(aggregatorWeakRef); break; case CycleKind.QuickPulse: aggregatorWeakRef = Interlocked.Exchange(ref this.aggregatorQuickPulse, null); this.aggregatorRecycleCacheQuickPulse = UnwrapAggregator(aggregatorWeakRef); break; case CycleKind.Custom: aggregatorWeakRef = Interlocked.Exchange(ref this.aggregatorCustom, null); this.aggregatorRecycleCacheCustom = UnwrapAggregator(aggregatorWeakRef); break; default: throw new ArgumentException(Invariant($"Unexpected value of {nameof(aggregationCycleKind)}: {aggregationCycleKind}.")); } }
// @PublicExposureCandidate internal MetricAggregate GetCurrentAggregateUnsafe(MetricAggregationCycleKind aggregationCycleKind, DateTimeOffset dateTime) { IMetricSeriesAggregator aggregator = null; if (this.requiresPersistentAggregator) { aggregator = this.aggregatorPersistent; } else { switch (aggregationCycleKind) { case CycleKind.Default: aggregator = UnwrapAggregator(this.aggregatorDefault); break; case CycleKind.QuickPulse: aggregator = UnwrapAggregator(this.aggregatorQuickPulse); break; case CycleKind.Custom: aggregator = UnwrapAggregator(this.aggregatorCustom); break; default: throw new ArgumentException(Invariant($"Unexpected value of {nameof(aggregationCycleKind)}: {aggregationCycleKind}.")); } } dateTime = Util.RoundDownToSecond(dateTime); MetricAggregate aggregate = aggregator?.CreateAggregateUnsafe(dateTime); return(aggregate); }
/// <summary> /// /// </summary> /// <param name="metricManager"></param> /// <param name="aggregationCycleKind"></param> /// <param name="tactTimestamp"></param> /// <returns></returns> public static AggregationPeriodSummary StopAggregators( this MetricManager metricManager, MetricAggregationCycleKind aggregationCycleKind, DateTimeOffset tactTimestamp) { Util.ValidateNotNull(metricManager, nameof(metricManager)); return(metricManager.AggregationManager.StopAggregators(aggregationCycleKind, tactTimestamp)); }
public NaiveDistinctCountMetricSeriesAggregator( MetricSeriesConfigurationForNaiveDistinctCount configuration, MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) : base(MetricValuesBufferFactory, configuration, dataSeries, aggregationCycleKind) { _caseSensitive = configuration.IsCaseSensitiveDistinctions; }
/// <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 DataSeriesAggregatorBase(IMetricSeriesConfiguration configuration, MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) { Util.ValidateNotNull(configuration, nameof(configuration)); _dataSeries = dataSeries; _aggregationCycleKind = aggregationCycleKind; _isPersistent = configuration.RequiresPersistentAggregation; Reset(default(DateTimeOffset), default(IMetricValueFilter)); }
private static MetricAggregationCycleKind SafeConvertMetricAggregationCycleKind(int aggregationCycleKind) { MetricAggregationCycleKind cycle = (MetricAggregationCycleKind)aggregationCycleKind; if (cycle == MetricAggregationCycleKind.Default || cycle == MetricAggregationCycleKind.QuickPulse || cycle == MetricAggregationCycleKind.Custom) { return(cycle); } throw new ArgumentException($"The specified number '{aggregationCycleKind}' is not a valid value for the {nameof(MetricAggregationCycleKind)} enumeration."); }
StopAggregators( object metricManager, int aggregationCycleKind, DateTimeOffset tactTimestamp) { MetricManager manager = (MetricManager)metricManager; MetricAggregationCycleKind cycle = SafeConvertMetricAggregationCycleKind(aggregationCycleKind); AggregationPeriodSummary summary = MetricManagerExtensions.StopAggregators(manager, cycle, tactTimestamp); var result = Tuple.Create(summary.NonpersistentAggregates, summary.PersistentAggregates); return(result); }
public AggregationPeriodSummary StopAggregators(MetricAggregationCycleKind aggregationCycleKind, DateTimeOffset tactTimestamp) { switch (aggregationCycleKind) { case CycleKind.QuickPulse: return(CycleAggregators(ref _aggregatorsForQuickPulse, tactTimestamp, futureFilter: null, stopAggregators: true)); case CycleKind.Custom: return(CycleAggregators(ref _aggregatorsForCustom, tactTimestamp, futureFilter: null, stopAggregators: true)); case CycleKind.Default: throw new ArgumentException($"Cannot invoke {nameof(StopAggregators)} for Default {nameof(MetricAggregationCycleKind)}: Default aggregators are always active."); default: throw new ArgumentException($"Unexpected value of {nameof(aggregationCycleKind)}: {aggregationCycleKind}."); } }
public MetricSeriesAggregatorBase( Func <MetricValuesBufferBase <TBufferedValue> > metricValuesBufferFactory, IMetricSeriesConfiguration configuration, MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) { Util.ValidateNotNull(metricValuesBufferFactory, nameof(metricValuesBufferFactory)); Util.ValidateNotNull(configuration, nameof(configuration)); _dataSeries = dataSeries; _aggregationCycleKind = aggregationCycleKind; _isPersistent = configuration.RequiresPersistentAggregation; _metricValuesBufferFactory = metricValuesBufferFactory; _metricValuesBuffer = InvokeMetricValuesBufferFactory(); Reset(default(DateTimeOffset), default(IMetricValueFilter)); }
StartOrCycleAggregators( object metricManager, int aggregationCycleKind, DateTimeOffset tactTimestamp, Func <Tuple <bool, Tuple <Func <object, double, bool>, Func <object, object, bool> > > > metricSeriesFilter) { MetricManager manager = (MetricManager)metricManager; MetricAggregationCycleKind cycle = SafeConvertMetricAggregationCycleKind(aggregationCycleKind); var filter = new MetricSeriesFilterAdapter(metricSeriesFilter); AggregationPeriodSummary summary = MetricManagerExtensions.StartOrCycleAggregators(manager, cycle, tactTimestamp, filter); var result = Tuple.Create(summary.NonpersistentAggregates, summary.PersistentAggregates); return(result); }
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}."); } }
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}."); } }
/// <summary> /// The lifetime of an aggragator can easily be a minute or so. So, it is a relatively small object that can easily get into Gen-2 GC heap, /// but then will need to be reclaimed from there relatively quickly. This can lead to a fragmentation of Gen-2 heap. To avoid this we employ /// a simple form of object pooling: Each data series keeps an instance of a past aggregator and tries to reuse it. /// Aggregator implementations which believe that they are too expensive to recycle for this, can opt out of this strategy by returning FALSE from /// their CanRecycle property. /// </summary> /// <param name="aggregationCycleKind">The kind of the metric aggregation cycle.</param> /// <returns>An empty aggregator.</returns> private IMetricSeriesAggregator GetRecycledAggregatorInstance(MetricAggregationCycleKind aggregationCycleKind) { if (this.requiresPersistentAggregator) { return(null); } IMetricSeriesAggregator aggregator = null; switch (aggregationCycleKind) { case CycleKind.Default: aggregator = Interlocked.Exchange(ref this.aggregatorRecycleCacheDefault, null); break; case CycleKind.QuickPulse: aggregator = Interlocked.Exchange(ref this.aggregatorRecycleCacheQuickPulse, null); break; case CycleKind.Custom: aggregator = Interlocked.Exchange(ref this.aggregatorRecycleCacheCustom, null); break; } if (aggregator == null) { return(null); } if (aggregator.TryRecycle()) { return(aggregator); } return(null); }
internal bool AddAggregator(IMetricSeriesAggregator aggregator, MetricAggregationCycleKind aggregationCycleKind) { Util.ValidateNotNull(aggregator, nameof(aggregator)); if (aggregator.DataSeries._configuration.RequiresPersistentAggregation) { return(AddAggregator(aggregator, _aggregatorsForPersistent)); } switch (aggregationCycleKind) { case CycleKind.Default: return(AddAggregator(aggregator, _aggregatorsForDefault)); case CycleKind.QuickPulse: return(AddAggregator(aggregator, _aggregatorsForQuickPulse)); case CycleKind.Custom: return(AddAggregator(aggregator, _aggregatorsForCustom)); default: throw new ArgumentException($"Unexpected value of {nameof(aggregationCycleKind)}: {aggregationCycleKind}."); } }
public SimpleUInt32DataSeriesAggregator(IMetricSeriesConfiguration configuration, MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) : base(configuration, dataSeries, aggregationCycleKind) { Util.ValidateNotNull(configuration, nameof(configuration)); SimpleMetricSeriesConfiguration simpleSeriesConfig = configuration as SimpleMetricSeriesConfiguration; if (simpleSeriesConfig == null) { throw new ArgumentException( $"{nameof(SimpleUInt32DataSeriesAggregator)} expects a configuration of type {nameof(SimpleMetricSeriesConfiguration)}," + $" however the specified configuration is {configuration?.GetType()?.FullName ?? Util.NullString}.", nameof(configuration)); } if (false == simpleSeriesConfig.RestrictToUInt32Values) { throw new ArgumentException( $"{nameof(SimpleUInt32DataSeriesAggregator)} expects a configuration of type {nameof(SimpleMetricSeriesConfiguration)}" + $" where 'RestrictToUInt32Values' is TRUE, however it is False.", nameof(configuration)); } }
public GaugeAggregator(MetricSeriesConfigurationForGauge configuration, MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) : base(MetricValuesBufferFactory, configuration, dataSeries, aggregationCycleKind) { Util.ValidateNotNull(configuration, nameof(configuration)); _restrictToUInt32Values = configuration.RestrictToUInt32Values; ResetAggregate(); }
private static void StartOrCycleAggregatorsTest(MetricAggregationCycleKind cycleKind, bool supportsSettingFilters) { DateTimeOffset dto = new DateTimeOffset(2017, 10, 2, 17, 5, 0, TimeSpan.FromHours(-7)); var aggregationManager = new MetricAggregationManager(); var measurementMetric = new MetricSeries( aggregationManager, "Measurement Metric", null, new MetricSeriesConfigurationForMeasurement(restrictToUInt32Values: false)); var accumulatorMetric = new MetricSeries( aggregationManager, "Accumulator Metric", null, new MetricSeriesConfigurationForAccumulator(restrictToUInt32Values: false)); // Cycle once, get nothing: AggregationPeriodSummary period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(0, period.NonpersistentAggregates.Count); Assert.AreEqual(0, period.PersistentAggregates.Count); // Record something, cycle, check for it: measurementMetric.TrackValue(1); accumulatorMetric.TrackValue(2); period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(1, period.NonpersistentAggregates.Count); Assert.AreEqual(1, period.PersistentAggregates.Count); Assert.IsNotNull(period.NonpersistentAggregates[0]); Assert.IsNotNull(period.PersistentAggregates[0]); Assert.AreEqual("Measurement Metric", period.NonpersistentAggregates[0].MetricId); Assert.AreEqual(1, period.NonpersistentAggregates[0].Data["Count"]); Assert.AreEqual(1.0, period.NonpersistentAggregates[0].Data["Sum"]); Assert.AreEqual("Accumulator Metric", period.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, period.PersistentAggregates[0].Data["Sum"]); // Now we should be empty again for non-persistent. Persistent stays: period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(0, period.NonpersistentAggregates.Count); Assert.AreEqual(1, period.PersistentAggregates.Count); Assert.IsNotNull(period.PersistentAggregates[0]); Assert.AreEqual("Accumulator Metric", period.PersistentAggregates[0].MetricId); Assert.AreEqual(2.0, period.PersistentAggregates[0].Data["Sum"]); // Now set a deny filter. Track. Expect to get nothng. // Note: for persistent, values tracked under Deny filter should persist for the future, for non-persistent they are just discarded. if (false == supportsSettingFilters) { Assert.ThrowsException <ArgumentException>(() => aggregationManager.StartOrCycleAggregators( cycleKind, dto, futureFilter: new AcceptAllFilter())); } else { period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: new DenyAllFilter()); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); measurementMetric.TrackValue(3); accumulatorMetric.TrackValue(4); period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(0, period.NonpersistentAggregates.Count); Assert.AreEqual(0, period.PersistentAggregates.Count); period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(0, period.NonpersistentAggregates.Count); Assert.AreEqual(1, period.PersistentAggregates.Count); Assert.IsNotNull(period.PersistentAggregates[0]); Assert.AreEqual("Accumulator Metric", period.PersistentAggregates[0].MetricId); Assert.AreEqual(6.0, period.PersistentAggregates[0].Data["Sum"]); // Validate that deny filter was removed: measurementMetric.TrackValue(5); accumulatorMetric.TrackValue(6); period = aggregationManager.StartOrCycleAggregators(cycleKind, dto, futureFilter: null); Assert.IsNotNull(period); Assert.IsNotNull(period.NonpersistentAggregates); Assert.IsNotNull(period.PersistentAggregates); Assert.AreEqual(1, period.NonpersistentAggregates.Count); Assert.AreEqual(1, period.PersistentAggregates.Count); Assert.IsNotNull(period.PersistentAggregates[0]); Assert.IsNotNull(period.NonpersistentAggregates[0]); Assert.AreEqual("Accumulator Metric", period.PersistentAggregates[0].MetricId); Assert.AreEqual(12.0, period.PersistentAggregates[0].Data["Sum"]); Assert.AreEqual("Measurement Metric", period.NonpersistentAggregates[0].MetricId); Assert.AreEqual(5.0, period.NonpersistentAggregates[0].Data["Sum"]); } }
public MeasurementAggregator(MetricSeriesConfigurationForMeasurement configuration, MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) : base(MetricValuesBufferFactory, configuration, dataSeries, aggregationCycleKind) { Util.ValidateNotNull(configuration, nameof(configuration)); this.restrictToUInt32Values = configuration.RestrictToUInt32Values; this.ResetAggregate(); }
private IMetricSeriesAggregator GetNewOrRecycledAggregatorInstance(MetricAggregationCycleKind aggregationCycleKind) { IMetricSeriesAggregator aggregator = this.GetRecycledAggregatorInstance(aggregationCycleKind); return(aggregator ?? this.configuration.CreateNewAggregator(this, aggregationCycleKind)); }
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. } }
public Aggregator(MetricSeriesConfigurationForTestingAccumulatorBehavior configuration, MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) : base(MetricValuesBufferFactory, configuration, dataSeries, aggregationCycleKind) { Util.ValidateNotNull(configuration, nameof(configuration)); ResetAggregate(); }
public IMetricSeriesAggregator CreateNewAggregator(MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) { return(new MetricSeriesConfigurationForTestingAccumulatorBehavior.Aggregator(this, dataSeries, aggregationCycleKind)); }
/// <summary /> /// <param name="dataSeries"></param> /// <param name="aggregationCycleKind"></param> /// <returns></returns> public IMetricSeriesAggregator CreateNewAggregator(MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) { IMetricSeriesAggregator aggregator = new GaugeAggregator(this, dataSeries, aggregationCycleKind); return(aggregator); }
/// <summary> /// </summary> /// <param name="dataSeries"></param> /// <param name="aggregationCycleKind"></param> /// <returns></returns> public IMetricSeriesAggregator CreateNewAggregator(MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) { IMetricSeriesAggregator aggregator = new NaiveDistinctCountMetricSeriesAggregator(this, dataSeries, aggregationCycleKind); return(aggregator); }
public SimpleNumberSeriesAggregatorBase(IMetricSeriesConfiguration configuration, MetricSeries dataSeries, MetricAggregationCycleKind aggregationCycleKind) : base(configuration, dataSeries, aggregationCycleKind) { }