Skip to content

Add MySQL client protocol (text protocol, transactions, prepared statements) on clean-room auth (#2093) - #3330

Merged
chenBright merged 21 commits into
apache:masterfrom
rajvarun77:mysql-text-protocol-clean-room
Jul 9, 2026
Merged

chenBright merged 21 commits into
apache:masterfrom
rajvarun77:mysql-text-protocol-clean-room

Conversation

@rajvarun77

@rajvarun77 rajvarun77 commented Jun 4, 2026 •

Copy link
Copy Markdown
Contributor

Implements a MySQL client protocol for brpc built on a clean-room authentication codec (no GPL lineage), addressing #2093.

Scope

  • Clean-room connection-phase auth — mysql_native_password and caching_sha2_password (fast-auth + full-auth RSA / secure-transport cleartext), derived from the public MySQL protocol documentation.
  • COM_QUERY text protocol — OK / ERR / EOF / text result-set parsing.
  • Interactive transactions via connection affinity (reserve/use a pooled connection; SINGLE rejected, auto-rollback on drop).
  • Prepared statements (binary protocol) with per-connection stmt_id caching and transparent re-prepare when a statement lands on a fresh connection.

Shared-core footprint (kept redis-like / minimal)

The only generic Controller/Socket additions are: a socket reserve/use hook and fd_version (ABA guard) for transaction/prepared-statement affinity, an auth empty-write guard for MySQL's server-greets-first handshake, and protocol registration. No protocol-specific type lives on the shared Controller (the prepared-statement pointer rides a generic opaque per-RPC slot).

Tests

Clean-room integration tests (transactions, prepared statements, pooled-connection concurrency, connection-type boundary) run against a self-spawned mysqld; 19/19 passing locally. Concurrency coverage includes per-transaction connection pinning under overlap, abort/auto-rollback under contention, and prepared re-prepare when a connection is stolen by a transaction.

rajvarun77 and others added 3 commits June 4, 2026 13:07
Clean-room implementation of the MySQL connection-phase authentication handshake,
derived from the public MySQL protocol documentation with no GPL lineage:
mysql_native_password and caching_sha2_password scrambles, HandshakeV10/
HandshakeResponse41 codec, and length-encoded integer/string plus packet-header
wire helpers. Handles the lenenc NULL (0xFB) marker and rejects an oversize
auth_response.
…statements

Port the MySQL protocol client (issue apache#2093) onto the clean-room auth codec and
protobuf 3.21 (NonreflectableMessage): COM_QUERY text protocol, interactive
transactions via connection affinity, and prepared statements. Wire
caching_sha2_password (fast-auth, full-auth RSA, and secure-transport cleartext)
into the live client. Fix the lenenc 9-byte length marker in pack_encode_length
(0xFD -> 0xFE) per the MySQL protocol spec.
… Controller cleanup

- Add clean-room integration tests (transactions, prepared statements, pooled
  connection concurrency, connection-type) run against a self-spawned mysqld.
- Fix: a failed COM_STMT_PREPARE now returns the ERR packet to the caller and keeps
  the connection alive, instead of closing the socket.
- Warn when a prepared statement runs on a 'short' connection (re-prepares on every
  execute; prefer 'pooled').
- Replace Controller's mysql-specific _mysql_stmt with a generic opaque per-RPC slot
  so no protocol type leaks onto the shared Controller.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rajvarun77
rajvarun77 force-pushed the mysql-text-protocol-clean-room branch from b598971 to a292dbc Compare June 4, 2026 19:37
…ted images

Move all MySQL sources (mysql.*, mysql_command/reply/common/transaction/
statement*, mysql_protocol.*, mysql_authenticator.*) into src/brpc/policy/mysql/
alongside the clean-room auth codec; update all includes, build globs, and
install rules. Remove three benchmark images inherited from the apache#2093 port and
the doc section referencing them.

No behavior change: full build green; all 19 mysql unit/integration tests pass;
a 30-case standalone end-to-end run was independently verified against mysqld.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rajvarun77
rajvarun77 force-pushed the mysql-text-protocol-clean-room branch 5 times, most recently from d3989c8 to be457a0 Compare June 4, 2026 22:09
… cases) + ASF headers

- Binary DATETIME/TIME: gate the microsecond bytes on the packet length, not the
  column's declared decimals (over-read / result-set desync).
- COM_STMT_SEND_LONG_DATA: frame stmt_id/param_id inside the packet; fix chunk offset.
- COM_STMT_EXECUTE: emit the trailing 0-length packet for 16MiB-aligned payloads.
- OK/EOF status & warnings: decode via mysql_uint2korr (big-endian safe).
- Row NULL-bitmap: arena-allocate instead of a stack VLA; cap column_count.
- Auth: bounds-check the parsed auth string; size-bound StringPiece uses.
- Prepared stmt: prune stale per-socket stmt_id map entries; count only real '?'
  placeholders (skip quotes/comments).
- MysqlResponse::Clear and MysqlRequest copy/Swap: reset/copy all members.
- Controller::ResetPods: release _bind_sock on controller reuse.
- Standardize mysql file license headers to the ASF form; clarify auth comment.

All 19 unit/integration tests still pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rajvarun77
rajvarun77 force-pushed the mysql-text-protocol-clean-room branch from be457a0 to 0bb55ee Compare June 4, 2026 22:16
@rajvarun77
rajvarun77 marked this pull request as ready for review June 4, 2026 22:20
@rajvarun77

Copy link
Copy Markdown
Contributor Author

@chenBright @wwbmmm — marking this ready for review.

Full MySQL client protocol for brpc — COM_QUERY text protocol, interactive transactions, and prepared statements — built on a clean-room authentication codec (no GPL lineage), addressing #2093.

  • Auth (clean-room): mysql_native_password + caching_sha2_password (fast-auth + full-auth RSA / secure-transport cleartext), derived from the public MySQL protocol docs.
  • Minimal shared-core footprint (redis-like): the only generic Controller/Socket additions are a socket reserve/use hook + fd_version (ABA guard) for transaction/prepared-statement affinity, an auth empty-write guard for the server-greets-first handshake, and protocol registration. No protocol-specific type lives on the shared Controller.
  • Tests: clean-room integration tests (transactions, prepared statements, pooled-connection concurrency, connection-type, binary TIME/DATETIME) run against a self-spawned mysqld — 20/20 passing locally; a standalone 30-case end-to-end run was independently verified.

The clean-room auth codec is also up as a smaller, focused PR (#3310, Stage 1a) if you'd prefer to review that foundation first.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a first-class MySQL client protocol implementation to brpc, including clean-room authentication, text protocol querying, transaction connection-affinity, and prepared statements support, along with new integration/unit tests and examples.

Changes:

  • Introduce PROTOCOL_MYSQL and register a MySQL client protocol stack (pack/parse/process) with connection-phase authentication handling.
  • Add MySQL client APIs (MysqlRequest, MysqlResponse, prepared statements, transactions) and supporting wire/protocol utilities.
  • Add MySQL-focused tests, docs, and examples; extend build/test integration (CMake/Bazel/Makefile).

Reviewed changes

Copilot reviewed 50 out of 50 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test/mysql/README.md Documents auth-handshake integration test modes and setup.
test/mysql/brpc_mysql_connection_type_unittest.cpp Adds integration test for SHORT connection behavior with prepared statements and plain queries.
test/mysql/brpc_mysql_auth_packet_unittest.cpp Adds unit tests for MySQL auth packet wire helpers (lenenc ints/strings, headers).
test/CMakeLists.txt Ensures MySQL unit tests are included in the CMake test glob.
test/BUILD.bazel Adds a Bazel cc_test target covering MySQL unit tests.
src/brpc/socket.h Exposes fd_version() for ABA-guarding per-connection statement caching.
src/brpc/socket.cpp Increments fd version on fd reset; allows empty writes for auth-handshake flows.
src/brpc/policy/mysql/mysql.h Introduces MySQL request/response message types and statement stub plumbing.
src/brpc/policy/mysql/mysql.cpp Implements MysqlRequest/MysqlResponse serialization and parsing entrypoints.
src/brpc/policy/mysql/mysql_transaction.h Adds MySQL transaction API and options for connection-affinity usage.
src/brpc/policy/mysql/mysql_transaction.cpp Implements transaction start/commit/rollback with socket reserve/use semantics.
src/brpc/policy/mysql/mysql_statement.h Adds prepared statement API and statement-id caching interface.
src/brpc/policy/mysql/mysql_statement.cpp Implements stmt-id cache keyed by socket id + fd version; placeholder counting.
src/brpc/policy/mysql/mysql_statement_inl.h Provides DBD map helpers for stmt-id caching and related gflag.
src/brpc/policy/mysql/mysql_protocol.h Declares MySQL protocol functions (parse/process/serialize/pack).
src/brpc/policy/mysql/mysql_protocol.cpp Implements client-side MySQL protocol codec, including auth handshake and prepare/execute flows.
src/brpc/policy/mysql/mysql_common.h Adds MySQL constants/types and collation mapping used by the client implementation.
src/brpc/policy/mysql/mysql_common.cpp Defines common MySQL defaults and type-to-string helper.
src/brpc/policy/mysql/mysql_command.h Declares MySQL command packet builders for query/prepare/execute/long-data.
src/brpc/policy/mysql/mysql_command.cpp Implements MySQL packetization and prepared statement wire builders.
src/brpc/policy/mysql/mysql_authenticator.h Adds MysqlAuthenticator carrying user/password/schema/params/collation.
src/brpc/policy/mysql/mysql_authenticator.cpp Implements credential serialization and clean-room scrambles (native + caching_sha2 fast path).
src/brpc/policy/mysql/mysql_auth_scramble.h Declares clean-room auth scramble and RSA/cleartext helpers.
src/brpc/policy/mysql/mysql_auth_scramble.cpp Implements native and caching_sha2 scrambles + RSA-OAEP encryption with OpenSSL EVP.
src/brpc/policy/mysql/mysql_auth_packet.h Adds wire helpers for lenenc ints/strings, packet headers, NUL strings.
src/brpc/policy/mysql/mysql_auth_packet.cpp Implements the MySQL wire-format helpers used by handshake parsing/building.
src/brpc/policy/mysql/mysql_auth_handshake.h Declares clean-room handshake packet codecs (greeting/response/switch/more-data).
src/brpc/policy/mysql/mysql_auth_handshake.cpp Implements parsing/building for connection-phase handshake payloads.
src/brpc/options.proto Adds PROTOCOL_MYSQL enum value.
src/brpc/global.cpp Registers the MySQL protocol with the global protocol registry.
src/brpc/details/controller_private_accessor.h Adds private controller hooks for socket reserve/use and opaque session data.
src/brpc/controller.h Introduces bind-socket actions/state to support MySQL transaction affinity and session data.
src/brpc/controller.cpp Implements socket reserve/use behavior across RPCs for pooled/short connection types.
Makefile Includes src/brpc/policy/mysql in the build directories list.
example/mysql_c++/mysqlclient_press.cpp Adds libmysqlclient-based press tool (comparison baseline).
example/mysql_c++/mysql_tx.cpp Adds brpc MySQL transaction example.
example/mysql_c++/mysql_stmt.cpp Adds brpc MySQL prepared statement example.
example/mysql_c++/mysql_press.cpp Adds brpc MySQL press example for CRUD.
example/mysql_c++/mysql_go_press.go Adds Go MySQL press example (comparison baseline).
example/mysql_c++/mysql_cli.cpp Adds brpc-based interactive MySQL CLI example.
example/mysql_c++/CMakeLists.txt Adds CMake build for MySQL examples and dependency discovery.
docs/cn/mysql_client.md Adds/updates Chinese documentation describing brpc MySQL client usage.
Comments suppressed due to low confidence (1)

src/brpc/policy/mysql/mysql_authenticator.h:92

  • The trailing #endif comment refers to COUCHBASE, which doesn’t match this header guard and is confusing when grepping/include-debugging. Update it to BRPC_POLICY_MYSQL_AUTHENTICATOR_H.
}  // namespace policy
}  // namespace brpc

#endif  // BRPC_POLICY_COUCHBASE_AUTHENTICATOR_H


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/brpc/policy/mysql/mysql_common.h Resolved
Comment thread src/brpc/policy/mysql/mysql.cpp Resolved
Comment thread docs/cn/mysql_client.md Resolved
rajvarun77 and others added 2 commits June 5, 2026 22:01
…er-global, doc/comment drift

- example/mysql_c++/mysql_go_press.go: add ASF Apache-2.0 license header
  (the last file failing the License Check; other 6 already had headers).
- mysql_common.{h,cpp}: move the MysqlCollations map definition out of the
  header into the .cpp behind an `extern` declaration, so each translation
  unit no longer gets its own copy (C++11-safe; avoids the header-defined
  global flagged in review).
- mysql_statement.{cpp,inl.h}: rename the misspelled gflag
  mysql_statment_map_size -> mysql_statement_map_size (user-facing name).
- docs/cn/mysql_client.md: prepared statements ARE supported now — drop the
  stale "不支持Prepared statement".
- brpc_mysql_connection_type_unittest.cpp: rewrite the stale header comment
  that described a removed "MustError" test; the prepared-statement path now
  transparently re-prepares under CONNECTION_TYPE_SHORT and succeeds, matching
  the actual PreparedStatementUnderShortRePreparesAndSucceeds test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…iles

The new MySQL example sources and brpc_mysql_unittest.cpp carried the old
"Copyright (c) Baidu, Inc." Apache-2.0 header, which skywalking-eyes (the
repo's License Check, configured copyright-owner = Apache Software Foundation)
does not accept — so all 7 files failed the gate. Replace with the canonical
ASF header used by the other 549 sources in the tree, and drop the stale
Baidu copyright/date attribution lines. Verified locally with
`license-eye -c .licenserc.yaml header check`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/brpc/policy/mysql/mysql.h Resolved
Comment thread src/brpc/policy/mysql/mysql.h Resolved
Comment thread src/brpc/socket.cpp Resolved
Comment thread src/brpc/controller.h Resolved
rajvarun77 and others added 6 commits June 8, 2026 21:20
Extend the failure-path logging from the auth codec to the full client
protocol. Parsers and request/response handlers returned false/0/nullptr
silently on malformed wire data, truncated packets, bad state, or missing
prepared statements, giving no clue why a query/connection failed. Add a
LOG(ERROR) at each silent failure path naming the function and the concrete
cause.

- mysql_auth_handshake/packet.cpp: handshake + lenenc codec failure paths
  (truncated <field>, pre-4.1 server, reserved 0xFF marker, length mismatch).
- mysql.cpp: request command/param guards.
- mysql_reply.cpp: result-set parse (column/row/error packet truncation,
  arena alloc failure, bad binary-row header).
- mysql_protocol.cpp: serialize/process type + serialization failures.
- mysql_statement.cpp: statement-id lookup misses (not-prepared / stale conn).

Logic unchanged — logs inserted only. Normal control-flow returns
(need-more-data, lenenc NULL 0xFB, short-connection no-cache) are not logged.
mysql_authenticator.cpp and mysql_transaction.cpp already logged every
failure path and were left unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tune the severity of the failure-path logs. LOG(ERROR) is reserved for
total failures — handshake/connection corruption, authentication failure,
out-of-memory, and fundamental request/response type or serialization
misuse. Operational and statement-data failures are demoted to
LOG(WARNING):

- mysql_auth_packet.cpp: lenenc int/string/header decode failures (these
  fire during normal resultset parsing).
- mysql.cpp: request command/param API guards.
- mysql_reply.cpp: column/row/field/ERR-packet truncation (statement data).
  The arena out-of-memory and Auth::Parse auth-plugin failures stay ERROR.
- mysql_statement.cpp: prepared-statement-id lookup misses (recoverable,
  trigger a re-prepare).

handshake parsing and the protocol serialize/process type checks remain
LOG(ERROR). Severity-only change; messages and logic unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI compiles unittests with -std=c++0x (C++11), where a class with a default
member initializer is not an aggregate, so g_auth_cases.push_back({...})
fails to compile. Drop the default member initializer on AuthCase::use_ssl;
all init sites pass it explicitly. Mirrors the same fix on the apache#3310 codec
branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sqld

The MySQL integration tests were not exercising a live server in CI:

- Merge master to pick up apache#3323, which installs mysql-server in the
  install-essential-dependencies action used by the unittest lanes, so the
  mysqld binary is present for the self-spawning test/mysql/* suites.
- Delete the legacy test/brpc_mysql_unittest.cpp: it hardcoded an external
  host (db4free.net) with embedded credentials and asserted on connect
  failure (no skip), so it timed out and hard-failed in CI. The
  test/mysql/*_integration suites supersede it, spawning a throwaway local
  mysqld and GTEST_SKIP-ing when none is available (the redis precedent).
- Build the test/mysql/* suites in the make lane: extend test/Makefile's
  source glob and add a mysql/-prefixed link rule; add the subdir to
  run_tests.sh with nullglob so it runs them.
- Bazel: build one cc_test per mysql test file via generate_unittests
  instead of globbing them all into a single brpc_mysql_test target, which
  duplicated main() and the FLAGS_mysql_* definitions (ld: duplicate
  symbol). Drop the per-file main()s so every suite relies on gtest_main,
  matching brpc_redis_unittest; tag the server-spawning suites
  external+local so bazel runs them unsandboxed with the real mysqld.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Controller: store the mysql-transaction BindSockAction in two bits of
  _flags (FLAGS_BIND_SOCK_RESERVE / FLAGS_BIND_SOCK_USE) via
  set_bind_sock_action()/bind_sock_action(), instead of a dedicated member,
  per review. No behavior change.
- MysqlResponse: make it explicitly non-copyable (= delete copy ctor and
  assignment) and turn the previously no-op MergeFrom into a hard
  CHECK-failure, so an accidental copy/CopyFrom is caught instead of
  silently dropping parsed replies.
- MysqlRequest: rename the trivial getters get_tx()/get_stmt() to
  tx()/stmt() per review.
- ControllerPrivateAccessor: add set_mysql_statement_type() as a clearly
  named alias over the pipelined_count slot the mysql protocol reuses, and
  call it from the mysql protocol instead of set_pipelined_count() directly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rajvarun77

Copy link
Copy Markdown
Contributor Author

@wwbmmm @chenBright — pushed a revision addressing the review feedback and fixing the integration-test setup. Summary:

Review comments

  • Stored the mysql-transaction BindSockAction in two Controller::_flags bits instead of a dedicated member.
  • Made MysqlResponse explicitly non-copyable and turned the previously no-op MergeFrom into a hard CHECK-failure (so an accidental copy is caught instead of silently dropping replies).
  • Renamed get_tx()/get_stmt() to tx()/stmt().
  • Added a clearly named ControllerPrivateAccessor::set_mysql_statement_type() alias over the pipelined_count slot the mysql protocol reuses.
  • The MysqlCollations ODR note, the gflag spelling, and the two doc/comment mismatches were already addressed in the current revision.
  • On _fd_version: I left a reply explaining why it needs to stay atomic — it is written in ResetFileDescriptor (reconnect path, no lock) and read lock-free from another thread via fd_version() in the prepared-statement path, so a non-atomic field would be a data race. It mirrors how _fd itself is handled. Happy to discuss further.

Integration tests now run against a real MySQL server

  • The suites previously did not exercise a live server in CI: a legacy test pointed at an external host and hard-failed, and the make/bazel wiring built it as a single globbed target. I removed the legacy test, switched the test/mysql/* suites to the redis-style self-spawning + skip-if-absent pattern, build one cc_test per file, and merged master so the CI image installs mysql-server. The suites now spawn a local throwaway mysqld and run.

Local verification
I built and ran all seven mysql suites locally against a live MySQL 9.6 server: 110 tests, 0 skipped, 0 failed — covering caching_sha2_password auth, the text and binary (prepared-statement) protocols, transactions, and connection pooling. (MySQL 9.x removed mysql_native_password, so this also exercises the caching_sha2 path end-to-end.)

CI is running on the latest revision. Could you take another look when you have a chance? Thanks for the reviews.

@rajvarun77

Copy link
Copy Markdown
Contributor Author

@wwbmmm @chenBright — heads-up on CI: the two *-unittest-with-bazel lanes show one failure, and it is an unrelated flake, not a regression from this PR.

  • The failing target is //test:brpc_channel_unittest, and within it a single timing-sensitive case, ChannelTest.backup_request, hung and blew the 300s test timeout (the timeout stack trace points at ChannelTest::TestBackupRequest()). It is a timeout, not an assertion failure.
  • The same commit passes that test in the make lanes (clang-unittest and clang-unittest-asan are green), and all seven //test:mysql/* targets pass in the bazel lanes.
  • It is independent of this change: the new flags use _flags bits 14/15 while backup-request uses FLAGS_BACKUP_REQUEST (bit 5) — no collision — and the backup-request path never touches bind_sock_action().

A re-run of the failed jobs should clear it (I cannot trigger re-runs as an outside contributor).

This PR is ready for another look whenever you have time: all review threads are addressed (I left one reply on _fd_version explaining why it stays atomic), the mysql integration suites now run against a real CI-provisioned mysqld, and I verified all seven suites locally against a live MySQL 9.6 (110 tests, 0 skipped, 0 failed). Thanks!

@rajvarun77

Copy link
Copy Markdown
Contributor Author

Moved all seven MySQL unittests from test/mysql/ into test/ (following the review on #3310), so the existing brpc_*_unittest glob picks them up. test/Makefile, test/CMakeLists.txt, and test/run_tests.sh revert to master with no mysql-specific lines. In test/BUILD.bazel the files join the brpc_unittests glob; the five tests that fork a real mysqld keep their ["external", "local"] tags by folding those entries into that target's per_test_tags (rather than a separate mysql target).

All seven tests compile and run green in the unittest jobs — auth handshake 28 / packet 27 / scramble 35, plus connection-type, pool-concurrency, prepared, and txn integration. Any remaining red is a pre-existing unrelated flake (brpc_channel_unittest/brpc_load_balancer_unittest timeouts, SocketTest, EventDispatcherTest under ASan), not this change.

…-clean-room

# Conflicts:
#	test/brpc_mysql_auth_handshake_unittest.cpp
@rajvarun77

Copy link
Copy Markdown
Contributor Author

Merged the latest master (which now includes the merged #3310) into this branch and resolved the add/add conflict on test/brpc_mysql_auth_handshake_unittest.cpp by keeping master's version — it is identical to this branch's copy plus the explicit main() that #3310 landed (parses the -mysql_* flags for the running-server mode). The branch is mergeable again and CI is re-running.

@wwbmmm @yanglimingcn — ready for another look when you have a moment.

@rajvarun77

Copy link
Copy Markdown
Contributor Author

This is ready for review and merge. The branch is up to date with master (the #3310 merge conflict is resolved) and mergeable.

The only failing checks are the three bazel unittest jobs, all on the same unrelated target //test:brpc_channel_unittest (78/79 pass in each):

  • clang-unittest-with-bazel / gcc-unittest-with-bazel — brpc_channel_unittest TIMEOUT at 300s
  • clang-unittest-bazel-with-babylon-and-new-pb — ChannelTest.backup_request_policy failed

This is a pre-existing timing flake, not related to this PR's diff. The failing assertion is test/brpc_channel_unittest.cpp:2208 — a 100 ms hang-guard on socket teardown — which overshot by <1 ms (100,896 µs) under bazel's parallel execution + 300 s per-test cap on the 2-vCPU runner. The same test passes in the serial make/cmake unittest jobs (clang-unittest and clang-unittest-asan are green), and the MySQL tests this PR touches all run and pass there (auth handshake 28 / packet 27 / scramble 35).

@chenBright @wwbmmm @yanglimingcn — could you take a look and merge when you have a moment? Happy to open a separate follow-up for the brpc_channel_unittest flake/timeout if useful.

@rajvarun77

Copy link
Copy Markdown
Contributor Author

Restructured for easier review: the generic Controller/Socket connection-affinity primitives (and the ChannelTest.backup_request uninitialized-bind_sock_action fix) are split into a small standalone PR #3348. This PR is now stacked on top of #3348 and contains only the MySQL-specific code (protocol codec, registration, PROTOCOL_MYSQL, accessor wrappers, tests, docs).

The diff here will show the core changes too until #3348 merges into master, after which it auto-reduces to MySQL-only. No functional change from the previous revision — the combined tree is byte-identical.

@rajvarun77
rajvarun77 force-pushed the mysql-text-protocol-clean-room branch from 749a22a to 6840404 Compare June 15, 2026 17:15
@rajvarun77

Copy link
Copy Markdown
Contributor Author

Update: reverted the split — the core/MySQL separation isn't warranted for a one-line fix. #3330 is again the single self-contained PR (MySQL protocol + the generic affinity primitives), and the ChannelTest.backup_request fix (uninitialized bind_sock_action in the Call(Call*) copy constructor) is folded directly into it. #3348 is closed. No functional change.

The new bind_sock_action member of Controller::Call had no in-class default,
and the Call(Call*) copy constructor used for backup requests and retries did
not initialize it in its member-init list. The backup call therefore read an
indeterminate value in Controller::Call::OnComplete, which branches on it
before the normal pool-return / SetFailed path; when the garbage matched
BIND_SOCK_RESERVE/BIND_SOCK_USE the backup call's socket was diverted to
_bind_sock or held instead of returned, leaving the in-flight RPC unconcluded
and hanging ChannelTest.backup_request until the test timeout (nondeterministic,
hence flaky-looking).

Give the member an in-class default initializer (BIND_SOCK_NONE) so every Call
construction path inherits it; a backup/retry never inherits transaction
connection-affinity. This closes the whole class of "new init path forgets the
member" rather than the single copy-ctor instance.
@rajvarun77
rajvarun77 force-pushed the mysql-text-protocol-clean-room branch from 6840404 to 1f1852f Compare June 15, 2026 17:29
@rajvarun77

Copy link
Copy Markdown
Contributor Author

@wwbmmm @yanglimingcn @chenBright — this is green on all lanes and ready for another look.

The earlier brpc_channel_unittest failure that I'd thought was an unrelated flake turned out to be a real bug this PR introduced: the new bind_sock_action member of Controller::Call was not default-initialized, so the backup/retry call (built via the Call copy constructor) read an indeterminate value in Call::OnComplete, which branches on it before the normal pool-return / SetFailed path. When the garbage happened to match BIND_SOCK_RESERVE/BIND_SOCK_USE, the backup call's socket was diverted instead of returned, leaving the in-flight RPC unconcluded and hanging ChannelTest.backup_request (nondeterministically, hence the flaky appearance). Fixed by giving the member an in-class default initializer (BIND_SOCK_NONE) so every Call construction path is safe; a backup/retry never inherits transaction affinity. ChannelTest.backup_request now passes in under a second.

All prior review comments are addressed. The one remaining open thread — whether per-Socket _fd_version needs to be atomic — has a reply explaining why: it is written on the reconnect path with no socket lock held and read from another thread, so the relaxed atomic is there to make that cross-thread access race-free, independent of the global counter's uniqueness. Happy to adjust if you'd prefer a different framing. Could you take another pass when you have a moment?

@rajvarun77
rajvarun77 requested a review from wwbmmm June 16, 2026 10:05
@rajvarun77

Copy link
Copy Markdown
Contributor Author

@chenBright — could you review this PR when you have a chance? It's green on all CI lanes and mergeable. All earlier review threads are addressed, and the previous brpc_channel_unittest failure is fixed (it was an uninitialized bind_sock_action in the Call copy constructor, now default-initialized). Would value your eyes on the MySQL protocol codec and the core Controller/Socket affinity primitives. Thanks!

@chenBright

Copy link
Copy Markdown
Contributor

Okay, I'll review it when I have time.

@chenBright

Copy link
Copy Markdown
Contributor

The MySQL protocol was originally developed by @yanglimingcn, who is most familiar with it. @yanglimingcn Please review it when you have time.

@wwbmmm

wwbmmm commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

LGTM

Comment thread src/brpc/controller.h Resolved
Comment thread src/brpc/socket.h Resolved
Per review: drop the in-class default initializer for Call::bind_sock_action
and set it explicitly in each Call constructor (the copy ctor used for
backup/retry) and Call::Reset(). Leaving it uninitialized was the cause of the
backup/retry-request hang; explicit per-constructor init keeps every path safe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rajvarun77

Copy link
Copy Markdown
Contributor Author

@wwbmmm @yanglimingcn @chenBright — addressed the ResetPods/bind_sock_action comment in 530e1124; all 15 CI lanes green (incl. the bazel lanes that flaked on ChannelTest.backup_request). PTAL and merge if it looks good. Thanks!

@rajvarun77

Copy link
Copy Markdown
Contributor Author

@wwbmmm @yanglimingcn @chenBright — gentle follow-up: this has been green on all CI lanes for a couple of days (the bind_sock_action/ResetPods comment is addressed in 530e1124). Could you take another look and merge if it looks good? Thanks!

@rajvarun77

Copy link
Copy Markdown
Contributor Author

@chenBright — checking in on the path to merge here. It has been three weeks since the handoff to @yanglimingcn (Jun 16) with no activity, and the PR has been merge-ready throughout: 15/15 CI lanes green, all review threads resolved (your ResetPods/bind_sock_action comment addressed in 530e1124), and @wwbmmm's LGTM. Would @wwbmmm's approval be sufficient to merge, or is @yanglimingcn's review a hard requirement?

@yanglimingcn — happy to walk through any part of the implementation (clean-room auth handshake, prepared-statement/transaction connection affinity, binary protocol) if that would make the review easier. And if you don't have bandwidth right now, no problem at all — just let us know how you'd like to proceed. Thanks!

@rajvarun77
rajvarun77 force-pushed the mysql-text-protocol-clean-room branch from 530e112 to 14d06b0 Compare July 7, 2026 05:15
Comment thread src/brpc/policy/mysql/mysql.cpp Resolved
Comment thread src/brpc/policy/mysql/mysql.cpp Resolved
Comment thread src/brpc/policy/mysql/mysql.cpp Resolved
Comment thread src/brpc/policy/mysql/mysql.cpp Resolved
Comment thread src/brpc/controller.cpp Resolved
Comment thread src/brpc/controller.cpp Resolved

@chenBright chenBright left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@chenBright
chenBright merged commit 7684356 into apache:master Jul 9, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants