Today (correct, by design)
A pessimistic get_for_update / lock_keys that waits on another transaction's
lock and is then woken by TiKV gets a genuine WriteConflict
(reason: PessimisticRetry) whenever the key was committed by another
transaction at a commit_ts greater than this request's for_update_ts.
client-rust surfaces it as
PessimisticLockError { inner: MultipleKeyErrors([KeyError { .. WriteConflict }]), .. }
with no retry (Transaction::pessimistic_lock in src/transaction/transaction.rs;
new_pessimistic_lock_request in src/transaction/requests.rs always uses the
default WakeUpModeNormal).
This is correct and matches client-go's default LockKeys, which likewise
returns ErrWriteConflict to the caller — so it is not a bug. The caller is
expected to restart at a fresh for_update_ts. (For completeness: the
"transparent retry with a new for_update_ts" often attributed to the Go client
actually lives one layer up in TiDB — pkg/executor/adapter.go: handlePessimisticLockError — not in client-go itself.)
Gap (a missing feature)
client-rust has no equivalent of client-go's opt-in fair / aggressive
locking: StartAggressiveLocking(), which for a single-key LockKeys sends
WakeUpModeForceLock (tikv/client-go txnkv/transaction/txn.go). In that mode
TiKV acquires the lock despite the conflict and returns the latest value plus
LockedWithConflictTS instead of an error, so the caller can proceed at the
higher timestamp without abandoning the lock attempt.
client-rust already carries the generated proto for this
(PessimisticLockWakeUpMode_WakeUpModeForceLock, and the response
results / locked_with_conflict_ts fields, in src/generated/kvrpcpb.rs) but
never sets wake_up_mode and never reads results.
Proposal
- Add opt-in fair/aggressive locking: allow sending
WakeUpModeForceLock and
decode the results / locked_with_conflict_ts fields, so a single-key
pessimistic lock can lock-with-conflict rather than surface an error.
- (Optional) Provide a small retry-on-
WriteConflict helper for
WakeUpModeNormal users, since the equivalent driver logic lives in TiDB and
is absent from the pure-Rust stack.
This is a feature-parity enhancement; the current default behavior would be
unchanged.
Related
Today (correct, by design)
A pessimistic
get_for_update/lock_keysthat waits on another transaction'slock and is then woken by TiKV gets a genuine
WriteConflict(
reason: PessimisticRetry) whenever the key was committed by anothertransaction at a
commit_tsgreater than this request'sfor_update_ts.client-rust surfaces it as
PessimisticLockError { inner: MultipleKeyErrors([KeyError { .. WriteConflict }]), .. }with no retry (
Transaction::pessimistic_lockinsrc/transaction/transaction.rs;new_pessimistic_lock_requestinsrc/transaction/requests.rsalways uses thedefault
WakeUpModeNormal).This is correct and matches client-go's default
LockKeys, which likewisereturns
ErrWriteConflictto the caller — so it is not a bug. The caller isexpected to restart at a fresh
for_update_ts. (For completeness: the"transparent retry with a new
for_update_ts" often attributed to the Go clientactually lives one layer up in TiDB —
pkg/executor/adapter.go: handlePessimisticLockError— not in client-go itself.)Gap (a missing feature)
client-rust has no equivalent of client-go's opt-in fair / aggressive
locking:
StartAggressiveLocking(), which for a single-keyLockKeyssendsWakeUpModeForceLock(tikv/client-go txnkv/transaction/txn.go). In that modeTiKV acquires the lock despite the conflict and returns the latest value plus
LockedWithConflictTSinstead of an error, so the caller can proceed at thehigher timestamp without abandoning the lock attempt.
client-rust already carries the generated proto for this
(
PessimisticLockWakeUpMode_WakeUpModeForceLock, and the responseresults/locked_with_conflict_tsfields, insrc/generated/kvrpcpb.rs) butnever sets
wake_up_modeand never readsresults.Proposal
WakeUpModeForceLockanddecode the
results/locked_with_conflict_tsfields, so a single-keypessimistic lock can lock-with-conflict rather than surface an error.
WriteConflicthelper forWakeUpModeNormalusers, since the equivalent driver logic lives in TiDB andis absent from the pure-Rust stack.
This is a feature-parity enhancement; the current default behavior would be
unchanged.
Related
WriteConflict" (root cause discussed there; thisissue tracks the missing fair-locking feature specifically, not the FAQ).
WriteConflict-under-pessimistic question.Failed to resolve lockError. #328 —lock_keysblocking /Failed to resolve lockergonomics (tangential).