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 }); }