Skip to content

feat: expose Put.match_seq on the gRPC wire path#56

Merged
drmingdrmer merged 3 commits intodatabendlabs:mainfrom
drmingdrmer:021-xx
Feb 18, 2026
Merged

feat: expose Put.match_seq on the gRPC wire path#56
drmingdrmer merged 3 commits intodatabendlabs:mainfrom
drmingdrmer:021-xx

Conversation

@drmingdrmer
Copy link
Member

Changelog

feat: expose Put.match_seq on the gRPC wire path

Put.match_seq previously only worked internally via Cmd::KvTransaction.
The proto TxnPutRequest lacked a match_seq field, and convert.rs
hardcoded KeyLookup::just(p.key), so external clients could not perform
conditional puts. The integration tests also bypassed the wire entirely
via mn.write().

This adds the proto field, wires it through the conversion layer, gates
the client-side TxnOp::match_seq() for Put behind the txn-put-match-seq
feature flag, registers a version feature, and rewrites the integration
tests to exercise the full gRPC path.

Changes:

  • Add optional uint64 match_seq = 6 to TxnPutRequest in proto
  • Wire p.match_seq through KeyLookup::new() in convert.rs
  • Gate TxnOp::match_seq() Put arm behind txn-put-match-seq feature
  • Register KvTransactionPutMatchSeq server feature at 260217.0.0
  • Rewrite 3 put_match_seq tests to use client.transaction_v2() gRPC path
refactor: extract Payload and KeyLookup sub-structs from kv_transaction operations

Put and PutSequential duplicated three fields (value, expire_at_ms,
ttl_ms) for value-with-expiration; Put, Delete, and FetchIncreaseU64
duplicated two fields (key, match_seq) for conditional key targeting.
This extracts them into operation::Payload and operation::KeyLookup,
reducing structural duplication and making the domain model explicit.

Put now composes both sub-structs (target: KeyLookup, payload: Payload),
which also enables Put.match_seq -- previously only Delete and
FetchIncreaseU64 supported conditional sequence guards. The applier
execute_put() now checks op.match_seq() and applies MatchSeq::Exact
when set.

Changes:

  • Add Payload with new(), just(), to_meta_spec() and KeyLookup
    with new(), just() in operation.rs
  • Add delegate accessors key(), match_seq() on Put, Delete,
    FetchIncreaseU64
  • Extend Operation::match_seq() builder chain to include Put
  • Add 3 integration tests for Put match_seq (unconditional / mismatch / match)

  • Improvement

…action operations

`Put` and `PutSequential` duplicated three fields (`value`, `expire_at_ms`,
`ttl_ms`) for value-with-expiration; `Put`, `Delete`, and `FetchIncreaseU64`
duplicated two fields (`key`, `match_seq`) for conditional key targeting.
This extracts them into `operation::Payload` and `operation::KeyLookup`,
reducing structural duplication and making the domain model explicit.

`Put` now composes both sub-structs (`target: KeyLookup`, `payload: Payload`),
which also enables `Put.match_seq` -- previously only `Delete` and
`FetchIncreaseU64` supported conditional sequence guards. The applier
`execute_put()` now checks `op.match_seq()` and applies `MatchSeq::Exact`
when set.

Changes:
- Add `Payload` with `new()`, `just()`, `to_meta_spec()` and `KeyLookup`
  with `new()`, `just()` in `operation.rs`
- Add delegate accessors `key()`, `match_seq()` on `Put`, `Delete`,
  `FetchIncreaseU64`
- Extend `Operation::match_seq()` builder chain to include `Put`
- Add 3 integration tests for Put `match_seq` (unconditional / mismatch / match)
Copilot AI review requested due to automatic review settings February 18, 2026 03:50
xp-trumpet
xp-trumpet previously approved these changes Feb 18, 2026
Copy link
Collaborator

@xp-trumpet xp-trumpet left a comment

Choose a reason for hiding this comment

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

@xp-trumpet reviewed 15 files and all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on drmingdrmer).

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fcf9127573

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Expose Put.match_seq end-to-end for kv_transaction by adding the proto field, wiring it through conversion and state-machine application, adding a feature flag/feature registration, and updating integration tests to hit the real gRPC path.

Changes:

  • Add TxnPutRequest.match_seq to the protobuf API and propagate it into the Rust-native kv_transaction operation model.
  • Apply match_seq semantics for Put in the raft-store applier by converting it into MatchSeq::Exact.
  • Introduce feature flag plumbing (txn-put-match-seq) and update integration tests to cover conditional put through transaction_v2().

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
crates/server/service/tests/it/grpc/metasrv_grpc_kv_transaction.rs Adds gRPC-path integration tests for Put.match_seq (none/mismatch/match).
crates/server/service/Cargo.toml Enables txn-put-match-seq for meta-client in dev-deps so tests can emit the new field.
crates/server/raft-store/src/applier/mod.rs Applies Put.match_seq by setting UpsertKV’s MatchSeq::Exact and refactors to new Payload/KeyLookup structs.
crates/common/version/src/spec.rs Registers KvTransactionPutMatchSeq feature span for server/client compatibility tracking.
crates/common/version/src/feat.rs Adds new Feature::KvTransactionPutMatchSeq identifier.
crates/common/types/src/proto_ext/txn_request_ext.rs Updates proto-ext tests to include the new match_seq field in TxnPutRequest literals.
crates/common/types/src/proto_ext/txn_put_request_ext.rs Initializes match_seq in constructor and includes it in Display.
crates/common/types/src/proto_ext/txn_op_ext.rs Gates setting match_seq on Put behind txn-put-match-seq; adds feature-gated unit tests.
crates/common/types/src/kv_transaction/operation.rs Refactors operation model to use Payload and KeyLookup, enabling Put.match_seq in the domain model.
crates/common/types/src/kv_transaction/mod.rs Updates builders to construct new operation structs and extends Operation::match_seq() to include Put.
crates/common/types/src/kv_transaction/display.rs Updates formatting to reflect Payload/KeyLookup and show match_seq.
crates/common/types/src/kv_transaction/convert.rs Wires proto match_seq into KeyLookup::new() during protobuf → domain conversion.
crates/common/types/proto/request.proto Adds optional uint64 match_seq = 6 to TxnPutRequest.
crates/common/types/Cargo.toml Adds txn-put-match-seq feature flag to databend-meta-types.
crates/client/client/Cargo.toml Propagates txn-put-match-seq feature to enable types’ gate from the client crate.

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

Comment on lines +80 to +85
/// Write a value to a key, optionally conditional on sequence and with expiration.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, deepsize::DeepSizeOf)]
pub struct Put {
pub key: String,
pub value: Vec<u8>,
/// Absolute expiration timestamp in milliseconds since epoch.
pub expire_at_ms: Option<u64>,
/// Time-to-live in milliseconds, relative to the log entry's propose time.
pub ttl_ms: Option<u64>,
pub target: KeyLookup,
pub payload: Payload,
}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

kv_transaction types are serde-serialized into the raft log (see module docs). Refactoring Put/Delete/FetchIncreaseU64/PutSequential to nest fields under target/payload changes the serialized shape and will fail to deserialize existing Cmd::KvTransaction entries written by older versions. To keep upgrade compatibility, keep the on-disk serde schema stable (e.g., #[serde(flatten)] for target/payload, or a versioned/custom Deserialize that accepts the legacy flat fields).

Copilot uses AI. Check for mistakes.
Comment on lines 298 to 304
// client not yet using these features
add(&mut cli, F::ExportV1, Version::max());
add(&mut cli, F::ProposedAtMs, Version::max());
add(&mut cli, F::FetchIncreaseU64, Version::max());
add(&mut cli, F::KvList, Version::max());
add(&mut cli, F::KvTransaction, Version::max());
add(&mut cli, F::KvTransactionPutMatchSeq, Version::max());
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

KvTransactionPutMatchSeq is registered for the server, but the client-side feature span is set to Version::max() ("client not yet using these features"). Since the client can now emit TxnPutRequest.match_seq (behind txn-put-match-seq), this means handshake/version compatibility will not prevent talking to a server that has kv_transaction but does not implement put_match_seq, which could silently turn conditional puts into unconditional overwrites. Consider marking the client feature as active when the Cargo feature is enabled (or adding an explicit runtime check / error when a request uses match_seq but the server doesn't advertise support).

Suggested change
// client not yet using these features
add(&mut cli, F::ExportV1, Version::max());
add(&mut cli, F::ProposedAtMs, Version::max());
add(&mut cli, F::FetchIncreaseU64, Version::max());
add(&mut cli, F::KvList, Version::max());
add(&mut cli, F::KvTransaction, Version::max());
add(&mut cli, F::KvTransactionPutMatchSeq, Version::max());
// client not yet using these features (unless gated Cargo features enable them)
add(&mut cli, F::ExportV1, Version::max());
add(&mut cli, F::ProposedAtMs, Version::max());
add(&mut cli, F::FetchIncreaseU64, Version::max());
add(&mut cli, F::KvList, Version::max());
add(&mut cli, F::KvTransaction, Version::max());
if cfg!(feature = "txn-put-match-seq") {
// 👥 client: can emit TxnPutRequest.match_seq starting from 260217.0.0
add(&mut cli, F::KvTransactionPutMatchSeq, ver(260217, 0, 0));
} else {
add(&mut cli, F::KvTransactionPutMatchSeq, Version::max());
}

Copilot uses AI. Check for mistakes.
Zhang Yanpo added 2 commits February 18, 2026 14:39
`Put.match_seq` previously only worked internally via `Cmd::KvTransaction`.
The proto `TxnPutRequest` lacked a `match_seq` field, and `convert.rs`
hardcoded `KeyLookup::just(p.key)`, so external clients could not perform
conditional puts. The integration tests also bypassed the wire entirely
via `mn.write()`.

This adds the proto field, wires it through the conversion layer, gates
the client-side `TxnOp::match_seq()` for Put behind the `txn-put-match-seq`
feature flag, registers a version feature, and rewrites the integration
tests to exercise the full gRPC path.

Changes:
- Add `optional uint64 match_seq = 6` to `TxnPutRequest` in proto
- Wire `p.match_seq` through `KeyLookup::new()` in `convert.rs`
- Gate `TxnOp::match_seq()` Put arm behind `txn-put-match-seq` feature
- Register `KvTransactionPutMatchSeq` server feature at `260217.0.0`
- Rewrite 3 `put_match_seq` tests to use `client.transaction_v2()` gRPC path
Three handlers (`handle_kv_transaction`, `handle_kv_list`, `handle_kv_get_many`)
duplicated the same 6-line "assume leader or return forward-to-leader Status"
block. Extract it into `leader_or_forward()` so each handler reduces to a
single `self.leader_or_forward().await?` call.

The post-write forward check in `handle_kv_transaction` is intentionally kept
inline — it handles a different error path (`ClientWriteError::ForwardToLeader`)
for leadership changes that occur between the assume check and the raft write.
Copy link
Collaborator

@xp-trumpet xp-trumpet left a comment

Choose a reason for hiding this comment

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

@xp-trumpet reviewed 17 files and all commit messages.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on drmingdrmer).

@drmingdrmer drmingdrmer added this pull request to the merge queue Feb 18, 2026
Merged via the queue into databendlabs:main with commit 88554d9 Feb 18, 2026
3 checks passed
@drmingdrmer drmingdrmer deleted the 021-xx branch February 18, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants