Repository navigation
Conversation
The gRPC transport dialed a new ClientConn (TCP, plus TLS when enabled) for every query and closed it afterwards. Keep one connection per broker address and multiplex queries over it as HTTP/2 streams instead. - A connection whose query fails with codes.Unavailable is evicted and closed once its in-flight queries finish; the next query redials. - Each query's context is now always canceled when execute returns, so a stream abandoned on an early return does not linger on the shared connection. - Dial options are built once and cached only on success, so TLS config errors still surface at query time. - Connection.Close releases the cached connections (no-op for HTTP). Adds tests for reuse, per-broker connections, redial after Unavailable, deferred close of evicted connections, stream cancellation and Close, plus a loopback benchmark (BenchmarkGrpcBrokerTransport).
|
Independent maintenance review (not a GitHub-approving review). Validation on head
Correctness / concurrency / API review: No blocking issues.
Non-blocking note — Coveralls: the Merge gate: This PR requires a GitHub approving review covering the current head ( |
Close the cached connection out from under the transport so releaseConn and Close hit the conn.Close error branches, and check that Close still clears the cache and marks the transport closed.
|
Thanks for the review. I added the small test in abd8286: |
|
Updated independent maintenance review for the new head Scope since my last review: the only change on top of Validation on head
Coverage note from last review — resolved. The −0.07% Coveralls dip is gone; the new test covers both previously-uncovered Independent correctness re-check (separate reviewer): No blocking issues. Confirmed again:
Merge gate: This PR still requires a GitHub approving review covering the current head ( |
The gRPC broker transport dials a new
ClientConnfor every query and closes it when the query finishes, so every query pays a TCP handshake (and a full TLS handshake whenTLSConfigis enabled) before the request is sent. gRPC connections are meant to be long-lived and multiplex concurrent RPCs as HTTP/2 streams, so this change keeps one connection per broker address and reuses it.What changed:
grpcBrokerClientTransportcaches a*grpc.ClientConnper broker address. Concurrent queries share it.codes.Unavailable(broker restarted, connection broken), that connection is evicted from the cache and closed once its in-flight queries finish. The next query to that broker dials fresh. Other errors (bad SQL, deadline exceeded, decode errors) keep the connection.executereturns, so a stream abandoned on an early return (for example a decode error) is torn down instead of lingering on the shared connection.Connection.Close()releases the cached connections. It is a no-op for the HTTP transport, which does not own itshttp.Client. Documented indocs/grpc.mdand the README.Benchmark (
BenchmarkGrpcBrokerTransport, added in this PR): in-process broker on loopback, small result (2 rows),go test ./pinot -run '^$' -bench BenchmarkGrpcBrokerTransport -benchmem -count 5, run twice onmasterand twice on this branch, median of 10 runs each, Apple Silicon arm64:The machine was shared with other jobs, so absolute latencies are noisy; the allocation numbers are stable across runs. Over a real network the savings per query grow with round-trip time, since the TCP and TLS handshakes are what gets skipped.
Tests (
pinot/grpcBrokerConnReuse_test.go), using a real gRPC server on loopback with a listener that counts accepted connections:Unavailablecauses a redial on the next queryUnavailablekeep the connectionClosecloses connections and later queries fail;Connection.Closeworks for both transportsRan
go build ./...,go vet ./...,gofmt -l,golangci-lintv2.12.2 (0 issues) andgo test -raceon all non-example packages (pass;pinotcoverage 99.7%). I did not run the integration tests against a live Pinot quickstart.I used AI assistance while writing this; I reviewed and tested the changes.