public static ActionBlock <StatsdMessage> CreateBlock(ITargetBlock <CounterBucket> target, string rootNamespace, IIntervalService intervalService, ILog log) { var sets = new ConcurrentDictionary <string, ConcurrentDictionary <string, int> >(); var windows = new ConcurrentDictionary <string, ConcurrentDictionary <string, bool> >(); var root = rootNamespace; var ns = String.IsNullOrEmpty(rootNamespace) ? "" : rootNamespace + "."; var timeWindow = new TimeWindow(); var incoming = new ActionBlock <StatsdMessage>(p => { var set = p as Set; var metricName = set.Name + METRIC_IDENTIFIER_SEPARATOR + set.Value; foreach (var period in timeWindow.AllPeriods) { windows.AddOrUpdate(period, (key) => { var window = new ConcurrentDictionary <string, bool>(); window.AddOrUpdate(metricName, (key2) => true, (key2, oldValue) => true); return(window); }, (key, window) => { window.AddOrUpdate(metricName, (key2) => true, (key2, oldValue) => true); return(window); } ); } }, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded }); intervalService.Elapsed += (sender, e) => { if (sets.Count == 0) { return; } var currentTimeWindow = new TimeWindow(); var periodsNotPresent = currentTimeWindow.GetDifferences(timeWindow); // Make the current time window the one we use to manage the collections timeWindow = currentTimeWindow; CounterBucket bucket; // (Parallel) For each period that was measured (Day, Week, Month etc) // for every unique metric + value // Count the number of entries that start with the metric name // Add that metric to the list foreach (var period in periodsNotPresent) { ConcurrentDictionary <String, bool> window; // Take this window out of the dictionary if (windows.TryRemove(period, out window)) { var parts = period.Split(UNDERSCORE); var qualifier = "." + parts[0] + "." + parts[1]; var metricsAndValues = window.ToArray(); var metrics = new Dictionary <String, double>(); for (int index = 0; index < metricsAndValues.Length; index++) { var metricName = metricsAndValues[index].Key.Split(METRIC_IDENTIFIER_SEPARATOR_SPLITTER, StringSplitOptions.RemoveEmptyEntries)[0] + qualifier; if (metrics.ContainsKey(metricName)) { metrics[metricName] += 1; } else { metrics[metricName] = 1; } } var metricList = metrics.Select(metric => { return(new KeyValuePair <string, double>( metric.Key, metric.Value )); }).ToArray(); bucket = new CounterBucket(metricList, e.Epoch, ns); target.Post(bucket); break; } } }; incoming.Completion.ContinueWith(p => { // Tell the upstream block that we're done target.Complete(); }); return(incoming); }