private void WriteResponseInOrder(IChannelHandlerContext ctx, ThriftMessage response, long responseSequenceId) { // Ensure responses to requests are written in the same order the requests // were received. lock (_responseMap) { long currentResponseId = Interlocked.Read(ref _lastResponseWrittenId) + 1; if (responseSequenceId != currentResponseId) { // This response is NOT next in line of ordered responses, save it to // be sent later, after responses to all earlier requests have been // sent. _responseMap[responseSequenceId] = response; } else { // This response was next in line, write this response now, and see if // there are others next in line that should be sent now as well. do { ctx.Channel.WriteAndFlushAsync(response).GetAwaiter().GetResult(); Interlocked.Increment(ref _lastResponseWrittenId); ++currentResponseId; response = _responseMap.RemoveAndGet(currentResponseId); } while (null != response); // Now that we've written some responses, check if reads should be unblocked if (DispatcherContext.IsChannelReadBlocked(ctx)) { long lastRequestSequenceId = Interlocked.Read(ref _dispatcherSequenceId); if (lastRequestSequenceId <= Interlocked.Read(ref _lastResponseWrittenId) + _queuedResponseLimit) { DispatcherContext.UnblockChannelReads(ctx); } } } } }
private long BlockReadingForOrderReponse(IChannelHandlerContext ctx) { long requestSequenceId = Interlocked.Increment(ref _dispatcherSequenceId); if (DispatcherContext.IsResponseOrderingRequired(ctx)) { lock (_responseMap) { // Limit the number of pending responses (responses which finished out of order, and are // waiting for previous requests to be finished so they can be written in order), by // blocking further channel reads. Due to the way Netty frame decoders work, this is more // of an estimate than a hard limit. Netty may continue to decode and process several // more requests that were in the latest read, even while further reads on the channel // have been blocked. if (requestSequenceId > Interlocked.Read(ref _lastResponseWrittenId) + _queuedResponseLimit && !DispatcherContext.IsChannelReadBlocked(ctx)) { DispatcherContext.BlockChannelReads(ctx); } } } return(requestSequenceId); }