hjwsm1989 opened a new pull request, #3690:
URL: https://github.com/apache/brpc/pull/3690

   ### What problem does this PR solve?
   
   Issue Number: Related to #3418 / #3430
   
   Problem Summary:
   PR #3430 implemented flow-control segmentation and deferred `WINDOW_UPDATE` 
flushing for HTTP/2 & gRPC **client requests** (`H2UnsentRequest`). However, 
**server responses** (`H2UnsentResponse`) still lacked HTTP/2 flow-control 
support:
   1. **No stream/connection flow-control check on server responses**: When a 
server sends a response body exceeding the peer's stream window 
(`sctx->_remote_window_left`) or connection window 
(`ctx->_remote_window_left`), `H2UnsentResponse::AppendAndDestroySelf` packs 
all `DATA` frames at once, causing standard gRPC/HTTP2 clients (or the server 
itself when window runs out) to fail with `FLOW_CONTROL_ERROR`.
   2. **Server-side `H2StreamContext` destroyed too early**: On the server 
side, `OnEndStream` removes `sctx` from `_pending_streams` as soon as the 
request finishes arriving, before the business bthread finishes executing and 
sends the response. Without retaining `sctx` in `_pending_streams` until the 
response is completely sent, incoming stream-level `WINDOW_UPDATE` frames for 
an in-flight response cannot find the stream context.
   3. **Deferred gRPC trailer HPACK dynamic table ordering**: When a gRPC 
response body is partially deferred due to flow control, the trailing `HEADERS` 
(`grpc-status`, `grpc-message`) must be sent only after all `DATA` frames are 
flushed. Pre-encoding trailers with the connection's dynamic HPACK table during 
`H2UnsentResponse::New` and sending them later upon `WINDOW_UPDATE` would 
corrupt the HPACK dynamic table state if other streams encode `HEADERS` in 
between.
   
   ### What is changed and the side effects?
   
   Changed:
   1. **Server-side `H2StreamContext` lifecycle retention (`Stage 1 + Stage 
2`)**:
      - Keep server-side `H2StreamContext` in `H2Context::_pending_streams` 
across `OnEndStream` (`_stream_ended = true`) until the server finishes sending 
all response frames (or the stream is reset via `RST_STREAM` / 
`ClearPendingStreamData`).
      - Protect against premature destruction during concurrent `OnResetStream` 
by holding a reference-counted `butil::intrusive_ptr<H2StreamContext>` in 
`H2HttpMessage`.
   2. **Stateless HPACK encoding for deferred gRPC trailers**:
      - Add `HPacker::EncodeWithoutDynamicTable` (`H2HeaderStatelessAppend` 
using RFC 7541 static table index when available + literal header field without 
indexing `0000xxxx`) so deferred gRPC trailing `HEADERS` never mutate the 
connection's HPACK dynamic table out of order.
   3. **Flow-controlled segmentation & deferred flushing in 
`H2UnsentResponse`**:
      - Split response `DATA` frames according to `min(stream_window, 
conn_window)` and `max_frame_size`.
      - Defer remaining `DATA` and trailing `HEADERS` in 
`sctx->_pending_response_data`, accounted under `Socket::_unwritten_bytes` with 
overcrowding protection (`FLAGS_socket_max_unwritten_bytes`).
      - Resume sending pending server responses upon stream-level or 
connection-level `WINDOW_UPDATE` via round-robin `H2Context::FlushPendingData` 
(`_last_flushed_stream_id`).
   4. **Improved client `RST_STREAM` diagnostics & release-mode `H2Bvars`**:
      - Include `stream_id` and `H2ErrorToString(frame_head.stream_id)` in 
client-side `OnResetStream` error message.
      - Enable `H2Bvars` outside `DEBUG` builds to provide observability into 
`h2_stream_context_count` and `h2_unsent_request_count`.
   5. **Unit tests**:
      - Added unit tests in `test/brpc_h2_unsent_message_unittest.cpp`, 
`test/brpc_grpc_protocol_unittest.cpp`, and 
`test/brpc_http_rpc_protocol_unittest.cpp` covering response window splitting, 
deferred gRPC trailers, cross-stream HPACK isolation, `RST_STREAM` cleanup, 
overcrowded buffer protection, round-robin flushing, and end-to-end 4MB gRPC 
response under a 64KB initial window.
   
   Side effects:
   - Performance effects: Negligible when window is sufficient (fast path sends 
headers/data/trailers in one pass without queuing); prevents 
`FLOW_CONTROL_ERROR` when responses exceed peer window.
   - Breaking backward compatibility: None.
   
   ---
   ### Check List:
   - Please make sure your changes are compilable.
   - When providing us with a new feature, it is best to add related tests.
   - Please follow [Contributor Covenant Code of 
Conduct](https://github.com/apache/brpc/blob/master/CODE_OF_CONDUCT.md).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to