ss77892 opened a new pull request, #11874:
URL: https://github.com/apache/ozone/pull/11874

   ## What changes were proposed in this pull request?
   
   `XceiverClientGrpc` serves blocking calls (`sendCommand`, used by 
`ReadChunk`, `GetBlock`, `PutBlock` from the standalone client, etc.) on top of 
the async gRPC stub. Two costs come with that on every request:
   
   1. The reply is delivered on gRPC's shared executor. The response is parsed 
and the `CompletableFuture` is completed on a pool thread, which then has to 
wake up the caller blocked in `get()`. Every request pays a thread hand-off and 
the context switches that go with it.
   2. A new bi-directional stream is opened and closed for each request, which 
adds HTTP/2 stream setup and teardown (HEADERS / END_STREAM frames, call object 
allocation) to every round trip.
   
   This PR removes both for the common case: an untraced blocking call (tracing 
is off by default in production).
   
   **Reply on the waiting thread.** A new `CallerRunsReplyFuture` is both the 
reply future and the gRPC call executor. gRPC queues the call's callbacks on 
it, and the thread waiting in `get()` runs them, so the response is parsed and 
the future completed on the caller. This is the same approach gRPC's own 
blocking stubs use (`ThreadlessExecutor`). Once the waiter returns (reply, 
timeout, interrupt), queued and later callbacks run directly, so nothing is 
left behind.
   
   **Pooled streams.** Untraced blocking calls lease a `PooledStream` from a 
per-channel pool instead of opening a new stream. A stream carries one request 
at a time; the datanode serves the requests of a stream in order and replies to 
each, so the next reply always belongs to the current request and no request 
IDs are needed. After the reply the stream goes back to the pool before the 
semaphore permit is released.
   - The pool never holds more streams than the requests in flight, which the 
client semaphore already bounds.
   - A pooled stream has no gRPC deadline, so the waiter enforces the request 
timeout itself and fails the call with `DEADLINE_EXCEEDED`, as a per-call 
deadline would.
   - A request that times out, whose waiter is interrupted, or that fails, 
cancels its stream; the stream is dropped from the pool.
   - Idle streams are half-closed when the channel leaves `READY` (e.g. the 
datanode sends GOAWAY on shutdown), so they do not hold up the datanode's 
graceful shutdown.
   
   ## What is the link to the Apache JIRA
   
   https://issues.apache.org/jira/browse/HDDS-17561
   
   ## How was this patch tested?
   UT
   Benchmark result:
   
[build_comparison_20261030_211225.pdf](https://github.com/user-attachments/files/34209863/build_comparison_20261030_211225.pdf)
   


-- 
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