Skip to content

Conversation

@you06
Copy link
Contributor

@you06 you06 commented Jan 8, 2026

ref tikv/tikv#19087

Support shared lock for client-go with some limitations:

  • Shared lock cannot be PK (shared locks cannot being acquired when there is a PK choosed)
  • Txn with shared lock cannot lock keys with aggressive mode
  • Txn with shared lock cannot commit with 1pc/async commit protocol

Summary by CodeRabbit

  • New Features

    • Introduced shared lock mode for pessimistic transactions (concurrent read-oriented locks)
    • Added metrics/observers to report shared-lock usage
  • Behavior Changes

    • Shared locks interact with exclusive locks (mutual blocking), require a selected primary in shared pessimistic flows, and cannot be upgraded to exclusive
    • Lock scanning and GC/TTL handling refined to account for shared-lock entries
  • Tests

    • Comprehensive integration and unit tests covering shared/exclusive interactions, blocking, resolution, scanning, TTL GC, commit/rollback

✏️ Tip: You can customize this high-level summary in your review settings.

zyguan and others added 5 commits December 19, 2025 17:20
* *: add basic support for shared lock

Signed-off-by: zyguan <zhongyangguan@gmail.com>

* update kvproto

Signed-off-by: zyguan <zhongyangguan@gmail.com>

* make some minor updates

Signed-off-by: zyguan <zhongyangguan@gmail.com>

* add basic tests for LockKeys

Signed-off-by: zyguan <zhongyangguan@gmail.com>

* bump kvproto

Signed-off-by: zyguan <zhongyangguan@gmail.com>

* shared lock: support rollback/resolve, add tests (tikv#2)

* implement resolve lock

Signed-off-by: you06 <you1474600@gmail.com>

* remote comment code

Signed-off-by: you06 <you1474600@gmail.com>

* add license

Signed-off-by: you06 <you1474600@gmail.com>

* add test for gc shared lock

Signed-off-by: you06 <you1474600@gmail.com>

* address comment

Signed-off-by: you06 <you1474600@gmail.com>

---------

Signed-off-by: you06 <you1474600@gmail.com>

* fix test (tikv#3)

Signed-off-by: you06 <you1474600@gmail.com>

* txnkv: prevent shared locks from being resolved by accidently

Signed-off-by: zyguan <zhongyangguan@gmail.com>

---------

Signed-off-by: zyguan <zhongyangguan@gmail.com>
Signed-off-by: you06 <you1474600@gmail.com>
Co-authored-by: you06 <you1474600@gmail.com>
* add metrics for shared lock

Signed-off-by: you06 <you1474600@gmail.com>

* remove SharedLockKeysDuration

Signed-off-by: you06 <you1474600@gmail.com>

* add  span in tracing

Signed-off-by: you06 <you1474600@gmail.com>

---------

Signed-off-by: you06 <you1474600@gmail.com>
* update tests

Signed-off-by: you06 <you1474600@gmail.com>

* stabilize test

Signed-off-by: you06 <you1474600@gmail.com>

---------

Signed-off-by: you06 <you1474600@gmail.com>
Signed-off-by: you06 <you1474600@gmail.com>
@ti-chi-bot ti-chi-bot bot added the dco-signoff: yes Indicates the PR's author has signed the dco. label Jan 8, 2026
@ti-chi-bot ti-chi-bot bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jan 8, 2026
@you06 you06 requested review from cfzjywxk and zyguan January 8, 2026 05:06
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems txn_test.go is removed by 36a8441 , may I known the reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, I thought it was a conflict and removed it by mistake.
36a8441 reverted.

you06 added 3 commits January 20, 2026 15:44
Signed-off-by: you06 <you1474600@gmail.com>
@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 20, 2026

[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 zyguan 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
Copy link

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Walkthrough

Adds shared-lock support across transaction, pessimistic lock, and lock-resolution paths; introduces key flags and metrics, expands GC/scan behavior, updates 2PC and aggressive-locking logic, and adds extensive unit and integration tests plus test stubs and a small exported test helper.

Changes

Cohort / File(s) Summary
Integration tests
integration_tests/shared_lock_test.go
New integration test suite covering shared vs exclusive lock interactions, blocking/unblocking, resolution, TTL/GC, scanning, and lifecycle helpers.
Key flags & Lock context
kv/keyflags.go, kv/kv.go
Adds share-mode key flag accessors and ops (HasLockedInShareMode, SetKeyLockedInShareMode, SetKeyLockedInExclusiveMode) and adds InShareMode bool to LockCtx.
Pessimistic locking & lock flow
txnkv/transaction/pessimistic.go, txnkv/transaction/txn.go
Pessimistic ops choose shared vs exclusive variants when InShareMode; lock acquisition, aggressive-lock exit, primary selection, flag updates, upgrade guards, tracing and metrics adjusted for shared-mode.
Two-phase commit (2PC)
txnkv/transaction/2pc.go
Tracks hasSharedLocks, maps key flags to shared vs normal lock ops, and disables async/1PC commit paths when shared locks are present.
Lock resolution & GC
txnkv/txnlock/lock_resolver.go, tikv/gc.go
Adds Lock.IsPessimistic() and Lock.IsShared() helpers; lock resolution expanded to handle multiple shared-lock entries; ScanLocks/GC expands shared-lock wrappers into individual locks.
Metrics & shortcuts
metrics/metrics.go, metrics/shortcuts.go
Adds LblSharedLockKeys label and two histogram observers for shared-lock instrumentation.
Tests & test utilities
txnkv/transaction/test_util.go, txnkv/transaction/txn_test.go
Adds unimplemented test stubs to satisfy interfaces and unit tests covering optimistic/pessimistic shared/exclusive behaviors, upgrade/error cases, and in-memory flag assertions.
Test helper export
internal/locate/region_cache.go, internal/locate/region_cache_test.go
newTestRegionCache() made exported as NewTestRegionCache() and initializes txn-mode codec; tests updated to call exported constructor.

Sequence Diagram(s)

sequenceDiagram
    participant Client as KVTxn
    participant Pess as PessimisticHandler
    participant Store as KVStore
    participant Resolver as LockResolver

    Client->>Client: lockKeys(ctx, lockCtx)
    alt lockCtx.InShareMode == true
        Client->>Pess: build mutation with Op_SharedPessimisticLock
    else
        Client->>Pess: build mutation with Op_PessimisticLock
    end

    Pess->>Store: send pessimistic lock request
    Store-->>Pess: reply (acquired or lock error)
    alt reply contains shared-lock infos / conflict
        Pess->>Resolver: handleKeyErrorForResolve(keyError)
        Resolver->>Resolver: expand shared-lock infos → individual locks
        Resolver->>Resolver: apply TTL/threshold filtering
        Resolver-->>Pess: resolved locks or skip wrapper
    end
    Pess-->>Client: result
    Client->>Client: UpdateFlags(key, SetKeyLockedInShareMode / SetKeyLockedInExclusiveMode)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

lgtm, size/XL

Suggested reviewers

  • cfzjywxk
  • lhy1024
  • tiancaiamao

Poem

🐇 I nibble tests and weave a patch,

Shared locks hop in, a synchronized batch.
Goroutines wait, then leap and cheer,
Keys release worries, the paths are clear.
Hooray—locks now share the care!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'txn: support shared lock' directly and clearly summarizes the main change: adding shared lock support to the transaction layer.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@kv/keyflags.go`:
- Around line 81-86: The code allows flagKeyLockedInShareMode to be set without
flagKeyLocked; update ApplyFlagsOps to enforce the invariant by rejecting or
asserting when SetKeyLockedInShareMode or SetKeyLockedInExclusiveMode is applied
unless SetKeyLocked is also present, and modify DelKeyLocked to clear both
flagKeyLocked and flagKeyLockedInShareMode (i.e., ensure origin &=
^(flagKeyLocked | flagKeyLockedInShareMode)) so the share flag cannot persist
after unlocking; reference ApplyFlagsOps, DelKeyLocked, SetKeyLocked,
SetKeyLockedInShareMode, SetKeyLockedInExclusiveMode, flagKeyLocked,
flagKeyLockedInShareMode, and note persistentFlags/initKeysAndMutations remain
as-is.

In `@txnkv/transaction/txn_test.go`:
- Around line 110-128: Update the typo in the test failure message: in
TestLockKeys change the require.FailNow call inside the requireNoRequest closure
(used by txn.store.client.onSend) to say "locking keys in optimistic mode do not
invoke SendRequest" (fix "optismistic" → "optimistic") so the error string is
spelled correctly when txn.lockKeys is expected not to call SendRequest; no
logic changes needed (references: TestLockKeys, requireNoRequest, txn.lockKeys,
newTestTxn, GetMemBuffer().GetFlags).
🧹 Nitpick comments (6)
tikv/gc.go (1)

290-301: Guard against empty SharedLockInfos to avoid dropping locks.

If GetSharedLockInfos() can be non-nil but empty, the wrapper lock will be skipped and no lock will be returned for that entry. Consider guarding with len(...) > 0 and falling back to the wrapper otherwise. Please confirm kvproto’s guarantee here.

♻️ Proposed defensive tweak
-		for _, lockInfo := range locksInfo {
-			if sharedLockInfos := lockInfo.GetSharedLockInfos(); sharedLockInfos != nil {
+		for _, lockInfo := range locksInfo {
+			if sharedLockInfos := lockInfo.GetSharedLockInfos(); len(sharedLockInfos) > 0 {
 				// expand shared lock into multiple locks, and drop the dummy wrapper lock.
 				for _, sharedLockInfo := range sharedLockInfos {
 					locks = append(locks, txnlock.NewLock(sharedLockInfo))
 				}
-				continue
-			}
-			locks = append(locks, txnlock.NewLock(lockInfo))
+			} else {
+				locks = append(locks, txnlock.NewLock(lockInfo))
+			}
 		}
txnkv/transaction/txn_test.go (1)

59-86: Consider: GetOracle() returns nil which could cause NPE if accessed.

The mockStore.GetOracle() returns nil. While this works for the current tests that don't require the oracle, it could cause unexpected panics if future tests or the code under test attempts to use it.

Consider returning a mock oracle
+type mockOracle struct{}
+
+func (o *mockOracle) GetTimestamp(ctx context.Context, opt *oracle.Option) (uint64, error) {
+	return 1, nil
+}
+
+// ... other required interface methods
+
 func (m *mockStore) GetOracle() oracle.Oracle {
-	return nil
+	return &mockOracle{}
 }
txnkv/transaction/txn.go (1)

660-660: Verify: TODO for pipelined DML shared lock handling.

This TODO indicates that pipelined DML does not prewrite shared locks even when flags.HasLockedInShareMode() is true. Ensure this is tracked and addressed if pipelined DML with shared locks becomes a requirement.

Do you want me to open a new issue to track this task?

integration_tests/shared_lock_test.go (3)

43-60: Consider documenting the rationale for the specific TTL/backoff values.

The setup modifies global state (ManagedLockTTL to 3s, CommitMaxBackoff to 1s). While this is necessary for testing, a brief comment explaining why these specific values were chosen would improve maintainability.

Add clarifying comments
 func (s *testSharedLockSuite) SetupSuite() {
+	// Set shorter TTL for faster test execution while still allowing lock heartbeat validation
 	atomic.StoreUint64(&transaction.ManagedLockTTL, 3000) // 3s
+	// Reduce backoff to speed up conflict resolution tests
 	atomic.StoreUint64(&transaction.CommitMaxBackoff, 1000)
 	s.Nil(failpoint.Enable("tikvclient/injectLiveness", `return("reachable")`))
 }

84-134: Consider argument order in s.Equal for clearer error messages.

The testify convention is s.Equal(expected, actual). Several assertions have the arguments reversed, which affects error message clarity when tests fail.

Proposed fixes for argument order
-		s.Equal(txn1.GetCommitter().GetPrimaryKey(), pk1)
+		s.Equal(pk1, txn1.GetCommitter().GetPrimaryKey())

Apply similar changes to lines 102, 112, etc.


113-133: Test relies on timing which may cause flakiness.

The test uses time.Sleep(500 * time.Millisecond) to wait for the lock to be blocked, and then verifies timing with afterRelease.After(beforeRelease). In high-load CI environments, this could potentially be flaky.

Consider using a synchronization mechanism to ensure txn3 has started waiting before checking the timing.

you06 added 4 commits January 20, 2026 19:47
Signed-off-by: you06 <you1474600@gmail.com>
Signed-off-by: you06 <you1474600@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the dco. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants