private async Task GetPendingCounterData(Counter counter)
        {
            this.UpdateCounterWithLatestTimestamps(counter);

            DateTimeOffset lastPending = DateTimeOffset.MinValue;
            PendingData    pendingData = counter.DataSet.GetNextPendingData(lastPending);

            if (pendingData == null)
            {
                return;
            }

            do
            {
                if (this.disposed)
                {
                    return;
                }

                lastPending = pendingData.StartTime;

                // TODO: Move below method to DateTimeOffset too.
                using (var aggregator =
                           PersistedDataProtocol.CreateAggregatorForSampleType((MetricSystem.PersistedDataType)counter.DataSet.PersistedDataType,
                                                                               counter.Name,
                                                                               counter.DataSet.DimensionSet,
                                                                               pendingData.Sources,
                                                                               new DateTime(
                                                                                   pendingData.StartTime.DateTime.Ticks,
                                                                                   DateTimeKind.Utc),
                                                                               new DateTime(pendingData.EndTime.DateTime.Ticks,
                                                                                            DateTimeKind.Utc),
                                                                               this.dataManager.MemoryStreamManager))
                {
                    var timeout = TimeoutTiers[ServerCountTiers.Length - 1];
                    for (var i = 0; i < ServerCountTiers.Length; ++i)
                    {
                        if (pendingData.Sources.Count <= ServerCountTiers[i])
                        {
                            timeout = TimeoutTiers[i];
                            break;
                        }
                    }
                    aggregator.MaxFanout = MaxFanout;
                    aggregator.Timeout   = timeout;

                    Events.Write.BeginRetrieveCounterData(counter.Name, pendingData.StartTime, pendingData.EndTime,
                                                          timeout, pendingData.Sources);
                    var success = await aggregator.Run();

                    if (success)
                    {
                        counter.DataSet.UpdateFromAggregator(aggregator, pendingData.StartTime, pendingData.EndTime);
                    }

                    Events.Write.EndRetrieveCounterData(counter.Name, success);
                }

                this.UpdateCounterWithLatestTimestamps(counter);
            } while ((pendingData = counter.DataSet.GetNextPendingData(lastPending)) != null);

            lock (this.activeWorkers)
            {
                this.activeWorkers.Remove(counter.Name);
            }
        }
        public override async Task <Response> ProcessRequest(Request request)
        {
            var counterName = request.Path;

            if (string.IsNullOrEmpty(counterName))
            {
                return(request.CreateErrorResponse(HttpStatusCode.BadRequest, "Path or command is invalid."));
            }

            if (request.QueryParameters.Count != 2 ||
                !request.QueryParameters.ContainsKey(ReservedDimensions.StartTimeDimension) ||
                !request.QueryParameters.ContainsKey(ReservedDimensions.EndTimeDimension))
            {
                return(request.CreateErrorResponse(HttpStatusCode.BadRequest,
                                                   "Invalid query parameters. Must specify only start and end time."));
            }

            DateTime start, end;

            if (!DateTime.TryParse(request.QueryParameters[ReservedDimensions.StartTimeDimension], out start))
            {
                return(request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid start time."));
            }
            if (!DateTime.TryParse(request.QueryParameters[ReservedDimensions.EndTimeDimension], out end))
            {
                return(request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid end time."));
            }

            var message = new TransferRequest();

            if (request.HasInputBody)
            {
                message = await request.ReadInputBody <TransferRequest>();
            }

            var ms = request.GetStream();

            // This is a tiered aggregation request, handle it separately.
            if (message.Sources != null && message.Sources.Count > 1)
            {
                try
                {
                    using (var aggregator =
                               PersistedDataProtocol.CreateAggregatorForSampleType(message.DataType, counterName,
                                                                                   message.Sources, start, end,
                                                                                   dataManager.MemoryStreamManager))
                    {
                        if (message.Timeout > 0)
                        {
                            aggregator.Timeout = TimeSpan.FromSeconds(message.Timeout);
                        }
                        if (message.MaxFanout > 0)
                        {
                            aggregator.MaxFanout = (int)message.MaxFanout;
                        }

                        // This shouldn't happen, given that one of the servers we want to talk to is.. us.
                        if (!await aggregator.Run())
                        {
                            ms.Dispose();
                            return(request.CreateErrorResponse(HttpStatusCode.InternalServerError,
                                                               "All child requests failed."));
                        }
                        if (!aggregator.WriteToStream(ms))
                        {
                            // TODO: If we have no results but none of our queries failed we can definitively 404,
                            //       for now lazy.
                            ms.Dispose();
                            return(request.CreateErrorResponse(HttpStatusCode.InternalServerError,
                                                               "No cntent matched."));
                        }
                    }
                }
                catch (ArgumentException)
                {
                    ms.Dispose();
                    return(request.CreateErrorResponse(HttpStatusCode.BadRequest, "Request parameters are invalid."));
                }
            }
            else
            {
                var counter = this.dataManager.GetCounter <Counter>(counterName);
                if (counter == null || !counter.SerializeData(start, end, ms))
                {
                    ms.Dispose();
                    return(request.CreateErrorResponse(HttpStatusCode.NotFound, "The requested data is not available."));
                }
            }

            // after writing the response the server will handle disposing the stream for us.
            return(new Response(request, HttpStatusCode.OK, ms)
            {
                ContentType = ResponseType
            });
        }