Example #1
0
        public static IFlowState <TResult> SelectMany <TSource, TResult>(this IFlowState <TSource> state,
                                                                         Func <TSource, IFlowState <TResult> > valueSelector,
                                                                         Func <Exception, IFlowState <TResult> > errorSelector)
        {
            switch (state)
            {
            case Value <TSource> val:
                try
                {
                    return(valueSelector(val.Val));
                }
                catch (Exception e)
                {
                    return(new Error <TResult>(e));
                }

            case Error <TSource> err:
                try
                {
                    return(errorSelector(err.Ex));
                }
                catch (Exception e)
                {
                    return(new Error <TResult>(e));
                }

            default:
                return(new Pending <TResult>());
            }
        }
Example #2
0
 public static IFlowState <TResult> Select <TSource, TResult>(this IFlowState <TSource> state,
                                                              Func <TSource, TResult> valueSelector,
                                                              Func <Exception, TResult> errorSelector)
 {
     return(state.SelectMany(t => new Value <TResult>(valueSelector(t)),
                             e => new Value <TResult>(errorSelector(e))));
 }
Example #3
0
 public override void OnStreamClosed(IHttp2Stream stream)
 {
     try
     {
         // When a stream is closed, consume any remaining bytes so that they
         // are restored to the connection window.
         IFlowState state           = GetState(stream);
         int        unconsumedBytes = state.UnconsumedBytes;
         if (_ctx is object && unconsumedBytes > 0)
         {
             if (ConsumeAllBytes(state, unconsumedBytes))
             {
                 // As the user has no real control on when this callback is used we should better
                 // call flush() if we produced any window update to ensure we not stale.
                 _ = _ctx.Flush();
             }
         }
     }
     catch (Http2Exception)
     {
         throw;
     }
     finally
     {
         // Unconditionally reduce the amount of memory required for flow control because there is no
         // object allocation costs associated with doing so and the stream will not have any more
         // local flow control state to keep track of anymore.
         _ = stream.SetProperty(_stateKey, REDUCED_FLOW_STATE);
     }
 }
Example #4
0
        /// <summary>
        /// The window update ratio is used to determine when a window update must be sent. If the ratio
        /// of bytes processed since the last update has meet or exceeded this ratio then a window update will
        /// be sent. This window update ratio will only be applied to <c>streamId</c>.
        /// <para>Note it is the responsibly of the caller to ensure that the
        /// initial <c>SETTINGS</c> frame is sent before this is called. It would
        /// be considered a <see cref="Http2Error.ProtocolError"/> if a <c>WINDOW_UPDATE</c>
        /// was generated by this method before the initial <c>SETTINGS</c> frame is sent.</para>
        /// </summary>
        /// <param name="stream">the stream for which <paramref name="ratio"/> applies to.</param>
        /// <param name="ratio">the ratio to use when checking if a <c>WINDOW_UPDATE</c> is determined necessary.</param>
        /// <remarks>If a protocol-error occurs while generating <c>WINDOW_UPDATE</c> frames</remarks>
        public void WindowUpdateRatio(IHttp2Stream stream, float ratio)
        {
            Debug.Assert(_ctx is object && _ctx.Executor.InEventLoop);
            CheckValidRatio(ratio);
            IFlowState state = GetState(stream);

            state.WindowUpdateRatio(ratio);
            _ = state.WriteWindowUpdateIfNeeded();
        }
Example #5
0
        public void IncrementWindowSize(IHttp2Stream stream, int delta)
        {
            Debug.Assert(_ctx is object && _ctx.Executor.InEventLoop);
            IFlowState state = GetState(stream);

            // Just add the delta to the stream-specific initial window size so that the next time the window
            // expands it will grow to the new initial size.
            state.IncrementInitialStreamWindow(delta);
            _ = state.WriteWindowUpdateIfNeeded();
        }
Example #6
0
    public void SetFlowState(FlowState.State state)
    {
        if (_currentFlowState != null)
        {
            _currentFlowState.Exit();
        }

        if (_stateMachine.ContainsKey(state))
        {
            _currentFlowState = _stateMachine[state];
            _currentFlowState.Enter();
        }
        else
        {
            Debug.LogError("NO flow state: " + state + " exists in flow state map");
        }
    }
Example #7
0
            public bool Visit(IHttp2Stream stream)
            {
                try
                {
                    // Increment flow control window first so state will be consistent if overflow is detected.
                    IFlowState state = _controller.GetState(stream);
                    state.IncrementFlowControlWindows(_delta);
                    state.IncrementInitialStreamWindow(_delta);
                }
                catch (StreamException e)
                {
                    if (_compositeException is null)
                    {
                        _compositeException = new CompositeStreamException(e.Error, 4);
                    }

                    _compositeException.Add(e);
                }

                return(true);
            }
Example #8
0
        /// <summary>
        /// Constructs a controller with the given settings.
        /// </summary>
        /// <param name="connection">the connection state.</param>
        /// <param name="windowUpdateRatio">the window percentage below which to send a <c>WINDOW_UPDATE</c>.</param>
        /// <param name="autoRefillConnectionWindow">if <c>true</c>, effectively disables the connection window
        /// in the flow control algorithm as they will always refill automatically without requiring the
        /// application to consume the bytes. When enabled, the maximum bytes you must be prepared to
        /// queue is proportional to <c>maximum number of concurrent streams * the initial window
        /// size per stream</c>
        /// (<a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_CONCURRENT_STREAMS</a>
        /// <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_INITIAL_WINDOW_SIZE</a>).
        /// </param>
        public DefaultHttp2LocalFlowController(IHttp2Connection connection, float windowUpdateRatio, bool autoRefillConnectionWindow)
        {
            if (connection is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.connection);
            }

            _connection = connection;
            WindowUpdateRatio(windowUpdateRatio);

            // Add a flow state for the connection.
            _stateKey = connection.NewKey();
            IFlowState connectionState = autoRefillConnectionWindow
                ? new AutoRefillState(this, connection.ConnectionStream, _initialWindowSize)
                : new DefaultState(this, connection.ConnectionStream, _initialWindowSize);

            _ = connection.ConnectionStream.SetProperty(_stateKey, connectionState);

            // Register for notification of new streams.
            connection.AddListener(this);
        }
Example #9
0
        public void ReceiveFlowControlledFrame(IHttp2Stream stream, IByteBuffer data, int padding, bool endOfStream)
        {
            Debug.Assert(_ctx is object && _ctx.Executor.InEventLoop);
            int dataLength = data.ReadableBytes + padding;

            // Apply the connection-level flow control
            IFlowState connectionState = ConnectionState();

            connectionState.ReceiveFlowControlledFrame(dataLength);

            if (stream is object && !IsClosed(stream))
            {
                // Apply the stream-level flow control
                IFlowState state = GetState(stream);
                state.EndOfStream(endOfStream);
                state.ReceiveFlowControlledFrame(dataLength);
            }
            else if (dataLength > 0)
            {
                // Immediately consume the bytes for the connection window.
                _ = connectionState.ConsumeBytes(dataLength);
            }
        }
Example #10
0
 public bool Equals(IFlowState <FlowState> other)
 {
     return(Equals(other as FlowState));
 }
Example #11
0
 public static IFlowState <TResult> Select <TSource, TResult>(this IFlowState <TSource> state,
                                                              Func <TSource, TResult> selector)
 {
     return(state.SelectMany(t => new Value <TResult>(selector(t))));
 }
Example #12
0
 public static IFlowState <TResult> SelectMany <TSource, TFlow, TResult>(this IFlowState <TSource> source,
                                                                         Func <TSource, IFlowState <TFlow> > flowSelector, Func <TSource, TFlow, TResult> resultSelector)
 {
     return(source.SelectMany(s => flowSelector(s).Select(t => resultSelector(s, t))));
 }
Example #13
0
 public static IFlowState <TResult> SelectMany <TSource, TResult>(this IFlowState <TSource> state,
                                                                  Func <TSource, IFlowState <TResult> > selector)
 {
     return(state.SelectMany(selector, e => new Error <TResult>(e)));
 }
Example #14
0
 public static IFlowState <T> Flatten <T>(this IFlowState <IFlowState <T> > state)
 {
     return(state.SelectMany(t => t));
 }
Example #15
0
 private bool ConsumeAllBytes(IFlowState state, int numBytes)
 {
     return(ConnectionState().ConsumeBytes(numBytes) | state.ConsumeBytes(numBytes));
 }