From ddd10633ef0b107f0fd66475e9b0d685dee13403 Mon Sep 17 00:00:00 2001 From: Dinakaran Date: Sun, 27 Sep 2026 17:38:22 +0530 Subject: [PATCH] proto: make the generated kvproto modules public The generated protobuf messages and gRPC clients were private, so an application that needed an RPC this crate does not wrap had to vendor kvproto and generate its own copy of the same types: TiCDC's `ChangeData/EventFeed`, PD's GC safe point RPCs (`GetGCSafePoint`, `UpdateServiceGCSafePoint`), keyspace management, and so on. A few generated types already leak through the public API (`ProtoLockInfo`, `ProtoKeyError`, `ProtoRegionError`), but not the modules they live in. `tikv_client::proto` is now public, and it re-exports the `tonic` and `prost` versions the clients are generated for, so callers can build a `Channel` and use `Message` without pinning matching versions themselves. The module docs say that the generated code follows kvproto rather than the rest of the API, and show a PD GC safe point call. Rustdoc lints are allowed on the generated code, as clippy lints already are. Tests: `tests/proto_tests.rs` (no cluster) encodes a generated message with the re-exported prost and builds PD and ChangeData clients on a lazy channel from the re-exported tonic; the module doc example is compile-tested. Signed-off-by: Dinakaran --- src/lib.rs | 2 +- src/proto.rs | 38 ++++++++++++++++++++++++++++++++++++++ tests/proto_tests.rs | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 tests/proto_tests.rs diff --git a/src/lib.rs b/src/lib.rs index 89b25f45..838eed11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ mod compat; mod config; mod kv; mod pd; -mod proto; +pub mod proto; mod region; mod region_cache; mod stats; diff --git a/src/proto.rs b/src/proto.rs index f0dee9af..fb959105 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -1,14 +1,52 @@ // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. +//! The protobuf messages and gRPC clients generated from [kvproto], the TiKV, PD and +//! TiCDC protocol definitions this crate is built on. +//! +//! They let applications call RPCs this crate does not wrap, over the same message types: +//! for example TiCDC's `cdcpb::change_data_client::ChangeDataClient` or PD's GC safe +//! point RPCs on `pdpb::pd_client::PdClient`. The clients are [tonic] clients; build +//! their channels with the [`tonic`] re-exported here, which is the version the clients +//! are generated for (and [`prost`] for the message traits). +//! +//! ```no_run +//! use tikv_client::proto::pdpb; +//! use tikv_client::proto::tonic::transport::Channel; +//! +//! # async fn f() -> Result<(), Box> { +//! let channel = Channel::from_static("http://127.0.0.1:2379").connect().await?; +//! let mut pd = pdpb::pd_client::PdClient::new(channel); +//! let members = pd.get_members(pdpb::GetMembersRequest::default()).await?; +//! let cluster_id = members.into_inner().header.unwrap().cluster_id; +//! let request = pdpb::GetGcSafePointRequest { +//! header: Some(pdpb::RequestHeader { +//! cluster_id, +//! ..Default::default() +//! }), +//! }; +//! let safe_point = pd.get_gc_safe_point(request).await?.into_inner().safe_point; +//! # let _ = safe_point; +//! # Ok(()) +//! # } +//! ``` +//! +//! These modules are generated code and follow kvproto: they change when the vendored +//! protos are updated, independently of the rest of the API. +//! +//! [kvproto]: https://github.com/pingcap/kvproto + #![allow(clippy::large_enum_variant)] #![allow(clippy::enum_variant_names)] +pub use prost; pub use protos::*; +pub use tonic; // Rust 1.93's clippy::all flags many protobuf-generated wire types as dead code. // Prior toolchain (1.84.1) did not fail on these generated definitions. #[allow(clippy::doc_lazy_continuation)] #[allow(dead_code)] +#[allow(rustdoc::all)] mod protos { include!("generated/mod.rs"); } diff --git a/tests/proto_tests.rs b/tests/proto_tests.rs new file mode 100644 index 00000000..84f9393c --- /dev/null +++ b/tests/proto_tests.rs @@ -0,0 +1,38 @@ +//! The generated kvproto modules are public: applications can name the messages and +//! build the gRPC clients this crate does not wrap. No cluster is needed. + +use tikv_client::proto::cdcpb; +use tikv_client::proto::kvrpcpb; +use tikv_client::proto::pdpb; +use tikv_client::proto::prost::Message; +use tikv_client::proto::tonic::transport::Channel; +use tikv_client::proto::tonic::transport::Endpoint; + +#[test] +fn generated_messages_are_public_and_encode_with_the_reexported_prost() { + let request = pdpb::UpdateServiceGcSafePointRequest { + header: Some(pdpb::RequestHeader { + cluster_id: 7, + ..Default::default() + }), + service_id: b"gc_worker".to_vec(), + ttl: i64::MAX, + safe_point: 42, + }; + let decoded = + pdpb::UpdateServiceGcSafePointRequest::decode(request.encode_to_vec().as_slice()).unwrap(); + assert_eq!(decoded, request); + + // The re-exported `ProtoLockInfo` is the same type as the generated one. + let lock: tikv_client::ProtoLockInfo = kvrpcpb::LockInfo::default(); + assert!(lock.secondaries.is_empty()); +} + +#[tokio::test] +async fn generated_clients_build_on_the_reexported_tonic() { + // A lazy channel never dials, so this needs no server. + let channel: Channel = Endpoint::from_static("http://127.0.0.1:1").connect_lazy(); + let _pd = pdpb::pd_client::PdClient::new(channel.clone()); + let _cdc = cdcpb::change_data_client::ChangeDataClient::new(channel) + .max_decoding_message_size(64 << 20); +}