private void AdjustWindowDynamic(int bytesConsumed, Http2Stream stream) { _deliveredBytes += bytesConsumed; if (_deliveredBytes < StreamWindowThreshold) { return; } int windowUpdateIncrement = _deliveredBytes; long currentTime = Stopwatch.GetTimestamp(); Http2Connection connection = stream.Connection; TimeSpan rtt = connection._rttEstimator.MinRtt; if (rtt > TimeSpan.Zero && _streamWindowSize < MaxStreamWindowSize) { TimeSpan dt = Stopwatch.GetElapsedTime(_lastWindowUpdate, currentTime); // We are detecting bursts in the amount of data consumed within a single 'dt' window update period. // The value "_deliveredBytes / dt" correlates with the bandwidth of the connection. // We need to extend the window, if the bandwidth-delay product grows over the current window size. // To enable empirical fine tuning, we apply a configurable multiplier (_windowScaleThresholdMultiplier) to the window size, which defaults to 1.0 // // The condition to extend the window is: // (_deliveredBytes / dt) * rtt > _streamWindowSize * _windowScaleThresholdMultiplier // // Which is reordered into the form below, to avoid the division: if (_deliveredBytes * (double)rtt.Ticks > _streamWindowSize * dt.Ticks * WindowScaleThresholdMultiplier) { int extendedWindowSize = Math.Min(MaxStreamWindowSize, _streamWindowSize * 2); windowUpdateIncrement += extendedWindowSize - _streamWindowSize; _streamWindowSize = extendedWindowSize; if (NetEventSource.Log.IsEnabled()) { stream.Trace($"[FlowControl] Updated Stream Window. StreamWindowSize: {StreamWindowSize}, StreamWindowThreshold: {StreamWindowThreshold}"); } Debug.Assert(_streamWindowSize <= MaxStreamWindowSize); if (_streamWindowSize == MaxStreamWindowSize) { if (NetEventSource.Log.IsEnabled()) { stream.Trace($"[FlowControl] StreamWindowSize reached the configured maximum of {MaxStreamWindowSize}."); } } } } _deliveredBytes = 0; Task sendWindowUpdateTask = connection.SendWindowUpdateAsync(stream.StreamId, windowUpdateIncrement); connection.LogExceptions(sendWindowUpdateTask); _lastWindowUpdate = currentTime; }
public Http2StreamWindowManager(Http2Connection connection, Http2Stream stream) { HttpConnectionSettings settings = connection._pool.Settings; _streamWindowSize = settings._initialHttp2StreamWindowSize; _deliveredBytes = 0; _lastWindowUpdate = default; if (NetEventSource.Log.IsEnabled()) { stream.Trace($"[FlowControl] InitialClientStreamWindowSize: {StreamWindowSize}, StreamWindowThreshold: {StreamWindowThreshold}, WindowScaleThresholdMultiplier: {WindowScaleThresholdMultiplier}"); } }