Skip to content

request: treat an undetermined apply outcome as terminal at commit points#555

Open
eduralph wants to merge 3 commits into
tikv:masterfrom
getwyrd:undetermined-result
Open

request: treat an undetermined apply outcome as terminal at commit points#555
eduralph wants to merge 3 commits into
tikv:masterfrom
getwyrd:undetermined-result

Conversation

@eduralph

@eduralph eduralph commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Stacked on #550 — please review the second commit only. Until #550 merges, the diff below also
contains its re-vendor.

Why: the re-vendored kvproto exposes errorpb.UndeterminedResult — the server telling us the
raft apply outcome is UNKNOWN. Today it falls through to the generic region-error arm and is retried
like any transient failure. For most requests that's right; for a commit point it isn't. "Failed"
must never be claimed for a transaction that may already be durable.

What: follow client-go's shape. Its transport never retries UndeterminedResult ("should not
retry … processed by the caller", region_request.go) and each action decides. So the plan layer
keeps retry as the default — replaying an idempotent request resolves the uncertainty, and on
backoff exhaustion the error escapes unchanged so callers can still classify it — while plans for
which a replay is unsafe opt in to terminal-on-first-sight:

  • raw CAS — a replay would compare against its own effect and report succeed = false for a
    write that happened.
  • the primary commit — client-go returns ErrResultUndetermined here (commit.go) rather than
    retrying.
  • async-commit / 1PC prewrites — the prewrite is the commit point. Stricter than client-go, in
    the safe direction.

Shard aggregation is fixed alongside: collect::<Result<_>>() returns the first error by shard
index
, so a lower-index shard's determinate error could mask a higher-index shard's
UndeterminedResult and tell the caller the request definitely failed. An undetermined error from
any shard now wins.

Commit paths classify the surfaced error as UndeterminedError. Two places are deliberately
conservative and say so in comments: a 1PC prewrite that sharding downgraded to 2PC, and an
undetermined error arriving from the commit plan's resolve_lock layer rather than the commit
dispatch. Both only over-report uncertainty, which makes the caller verify instead of replay.

Verification: 4 new tests — terminal for opted-in plans under a generous backoff (proving
terminal, not merely retry-exhausted), preserved unchanged on retry exhaustion, recognizer
positive/negative, and the shard-masking hazard. 71 lib tests; make check green; txn/raw/failpoint
integration suites green against a local api-v2 cluster.

Summary by CodeRabbit

  • New Features

    • Added support for snapshot backup preparation, batch downloads, region bucket streaming, keyspace loading, and immediate log-backup flushing.
    • Expanded transaction, coprocessor, resource management, encryption, health feedback, GC barrier, and region-query capabilities.
    • Added support for pipelined flush and batch-get operations.
    • Improved metadata for tracing, routing, usage reporting, and encryption.
  • Bug Fixes

    • Improved handling of indeterminate transaction outcomes, preventing unsafe retries and preserving accurate error reporting.

…revision

The vendored protos were an unrecorded late-2023/early-2024 vintage (errorpb
and pdpb untouched since tikv#324, one hand-patched addition from tikv#519). Nothing
recorded which kvproto revision they came from, and the staleness now blocks
real features.

Re-vendor everything at pingcap/kvproto b41e86365ce0 — the revision client-go
currently pins — and add proto/VERSION so the vintage is never again guesswork.
Regenerated with the existing tonic-build pipeline (21 files). One mechanical
source fix: pdpb.RequestHeader gained caller_component/caller_id, so the TSO
stream's header construction now defaults the new fields.

This commit is the re-vendor and nothing else. Newly available surface includes
KvFlush / KvBufferBatchGet (pipelined DML), HealthFeedback, and
pdpb.BatchScanRegions.

Two new protocol semantics become VISIBLE with the refresh —
errorpb.UndeterminedResult (an unknown raft apply outcome) and shared locks
(SharedLock / SharedPessimisticLock, whose real holders live in
shared_lock_infos). Handling them is deliberately left to follow-up PRs so this
one stays a pure re-vendor. Neither is a regression introduced here:

- UndeterminedResult falls through to the generic region-error arm, which
  backs off and retries — the same default the follow-up keeps for every plan
  that is not a commit point.
- A shared-lock wrapper carries no key bytes on the wire regardless of which
  proto vintage parses it, so the keyspace truncation hazard predates this
  commit; the refresh only makes the wrapper identifiable.

Tests: make check green; 67 lib tests; txn/raw/failpoint integration suites
green against a local api-v2 cluster.

Signed-off-by: Eduard R. <eduard@ralphovi.net>
@ti-chi-bot ti-chi-bot Bot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. dco-signoff: yes Indicates the PR's author has signed the dco. labels Jul 25, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 25, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign yujuncen for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This refreshes vendored kvproto definitions and code-generation options, adds multiple protocol messages and RPCs, and changes multi-region retry handling so selected CAS and transaction operations surface undetermined outcomes without replaying them.

Changes

Protocol and vendoring refresh

Layer / File(s) Summary
Vendored kvproto contracts and generation options
proto/*.proto, proto/include/*, proto/VERSION
Updates protobuf options and formatting, adds new protocol messages/RPCs, extends error, encryption, resource, PD, TiKV, coprocessor, and transaction contracts, and records the new kvproto revision.

Undetermined retry handling

Layer / File(s) Summary
Undetermined multi-region retry handling
src/request/plan.rs
Detects UndeterminedResult, propagates terminal retry behavior, prioritizes undetermined shard errors, and adds tests.
Retry policy entry points
src/request/plan_builder.rs, src/raw/client.rs
Adds terminal-on-undetermined plan construction and applies it to compare-and-swap requests.
Transaction undetermined outcome propagation
src/transaction/transaction.rs, src/pd/timestamp.rs
Uses terminal retry plans for selected commit paths and classifies qualifying outcomes as undetermined transaction errors; simplifies default request-header initialization.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested labels: lgtm, approved

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main behavioral change around terminal handling of undetermined outcomes at commit points.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ti-chi-bot ti-chi-bot Bot added contribution This PR is from a community contributor. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jul 25, 2026
@eduralph
eduralph force-pushed the undetermined-result branch from 81249dd to eddb093 Compare July 25, 2026 13:49
…ints

The re-vendored kvproto exposes errorpb.UndeterminedResult: the server telling
us the raft apply outcome is UNKNOWN. Today it falls through to the generic
region-error arm and is retried like any transient failure. For most requests
that is right, but not for a commit point, where "failed" must never be claimed
for a transaction that may already be durable.

Follow client-go's shape: its transport never retries UndeterminedResult
("should not retry ... processed by the caller", region_request.go) and each
ACTION decides. So the plan layer keeps RETRY as the default — replaying an
idempotent request resolves the uncertainty, and on backoff exhaustion the
error escapes UNCHANGED so callers can still classify it — while plans for
which a replay is unsafe opt in to terminal-on-first-sight via
retry_multi_region_terminal_on_undetermined:

- raw CAS: a replay would compare against its OWN effect and report
  succeed = false for a write that happened.
- the primary commit: client-go returns ErrResultUndetermined here (commit.go)
  rather than retrying.
- async-commit / 1PC prewrites: the prewrite IS the commit point. Stricter
  than client-go, in the safe direction.

Shard aggregation is fixed alongside: collect::<Result<_>>() returns the first
error BY SHARD INDEX, so a lower-index shard's determinate error could mask a
higher-index shard's UndeterminedResult and tell the caller the request
definitely failed. An undetermined error from any shard now wins.

Commit paths classify the surfaced error as UndeterminedError. Two places are
deliberately conservative and say so in comments: a 1PC prewrite that sharding
downgraded to 2PC, and an undetermined error arriving from the commit plan's
resolve_lock layer rather than the commit dispatch. Both only over-report
uncertainty, which makes the caller verify instead of replay.

Split out of the kvproto re-vendor at pingyu's suggestion (tikv#550).

Tests: 4 new — terminal for opted-in plans under a generous backoff (proving
terminal, not retry-exhausted), preserved unchanged on retry exhaustion,
recognizer positive/negative, and the shard-masking hazard. 71 lib tests green.

Signed-off-by: Eduard R. <eduard@ralphovi.net>
@eduralph
eduralph force-pushed the undetermined-result branch from eddb093 to 4f0c54c Compare July 25, 2026 22:03
@eduralph
eduralph marked this pull request as ready for review July 25, 2026 22:12
@ti-chi-bot ti-chi-bot Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jul 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
proto/encryptionpb.proto (1)

12-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Buf compile errors here are an include-path artifact, not a file defect.

gogoproto/gogo.proto and rustproto.proto live under proto/include/; Buf resolves imports relative to its module root, so every vendored file reports the same unresolvable-option/import errors. Consider adding a buf.yaml/buf.work.yaml that registers proto and proto/include as roots (or excluding vendored protos from Buf) so CI signal isn't drowned in false positives.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@proto/encryptionpb.proto` around lines 12 - 18, Update the Buf configuration
rather than proto/encryptionpb.proto: register both proto and proto/include as
module roots so imports of gogoproto/gogo.proto and rustproto.proto resolve, or
exclude the vendored protos from Buf validation. Ensure CI no longer reports
false-positive compile errors for these vendored files.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@proto/encryptionpb.proto`:
- Around line 12-18: Update the Buf configuration rather than
proto/encryptionpb.proto: register both proto and proto/include as module roots
so imports of gogoproto/gogo.proto and rustproto.proto resolve, or exclude the
vendored protos from Buf validation. Ensure CI no longer reports false-positive
compile errors for these vendored files.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ff4ddb26-826e-403b-b41f-609a275ef6b7

📥 Commits

Reviewing files that changed from the base of the PR and between 2c0f2f3 and 4f0c54c.

⛔ Files ignored due to path filters (21)
  • src/generated/backup.rs is excluded by !**/generated/**
  • src/generated/cdcpb.rs is excluded by !**/generated/**
  • src/generated/coprocessor.rs is excluded by !**/generated/**
  • src/generated/deadlock.rs is excluded by !**/generated/**
  • src/generated/encryptionpb.rs is excluded by !**/generated/**
  • src/generated/errorpb.rs is excluded by !**/generated/**
  • src/generated/import_sstpb.rs is excluded by !**/generated/**
  • src/generated/keyspacepb.rs is excluded by !**/generated/**
  • src/generated/kvrpcpb.rs is excluded by !**/generated/**
  • src/generated/logbackup.rs is excluded by !**/generated/**
  • src/generated/meta_storagepb.rs is excluded by !**/generated/**
  • src/generated/metapb.rs is excluded by !**/generated/**
  • src/generated/mpp.rs is excluded by !**/generated/**
  • src/generated/pdpb.rs is excluded by !**/generated/**
  • src/generated/raft_cmdpb.rs is excluded by !**/generated/**
  • src/generated/raft_serverpb.rs is excluded by !**/generated/**
  • src/generated/resource_manager.rs is excluded by !**/generated/**
  • src/generated/resource_usage_agent.rs is excluded by !**/generated/**
  • src/generated/schedulingpb.rs is excluded by !**/generated/**
  • src/generated/tikvpb.rs is excluded by !**/generated/**
  • src/generated/tsopb.rs is excluded by !**/generated/**
📒 Files selected for processing (42)
  • proto/VERSION
  • proto/autoid.proto
  • proto/brpb.proto
  • proto/cdcpb.proto
  • proto/configpb.proto
  • proto/coprocessor.proto
  • proto/deadlock.proto
  • proto/debugpb.proto
  • proto/diagnosticspb.proto
  • proto/disaggregated.proto
  • proto/disk_usage.proto
  • proto/encryptionpb.proto
  • proto/enginepb.proto
  • proto/errorpb.proto
  • proto/gcpb.proto
  • proto/import_kvpb.proto
  • proto/import_sstpb.proto
  • proto/include/eraftpb.proto
  • proto/include/gogoproto/gogo.proto
  • proto/include/rustproto.proto
  • proto/keyspacepb.proto
  • proto/kvrpcpb.proto
  • proto/logbackuppb.proto
  • proto/meta_storagepb.proto
  • proto/metapb.proto
  • proto/mpp.proto
  • proto/pdpb.proto
  • proto/raft_cmdpb.proto
  • proto/raft_serverpb.proto
  • proto/recoverdatapb.proto
  • proto/replication_modepb.proto
  • proto/resource_manager.proto
  • proto/resource_usage_agent.proto
  • proto/schedulingpb.proto
  • proto/tikvpb.proto
  • proto/tracepb.proto
  • proto/tsopb.proto
  • src/pd/timestamp.rs
  • src/raw/client.rs
  • src/request/plan.rs
  • src/request/plan_builder.rs
  • src/transaction/transaction.rs

@ti-chi-bot ti-chi-bot Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution This PR is from a community contributor. dco-signoff: yes Indicates the PR's author has signed the dco. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants