Skip to content

gc etcd key use meta service group#10949

Open
ystaticy wants to merge 4 commits into
tikv:masterfrom
ystaticy:txnsafepoint_etcd
Open

gc etcd key use meta service group#10949
ystaticy wants to merge 4 commits into
tikv:masterfrom
ystaticy:txnsafepoint_etcd

Conversation

@ystaticy

@ystaticy ystaticy commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: Close #xxx

What is changed and how does it work?

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No code

Code changes

Side effects

  • Possible performance regression
  • Increased code complexity
  • Breaking backward compatibility

Related changes

Release note

None.

Summary by CodeRabbit

  • New Features

    • Added support for routing GC transaction safe points through meta service groups and using group-specific endpoints for assigned keyspaces.
    • Exposed configurable GC state provider construction with optional meta-service-group storage.
    • Updated server startup/shutdown to initialize and close the routing storage provider.
  • Bug Fixes

    • Refined GC barrier/blocker behavior for routed mode, skipping the special worker safe-point blocker when appropriate.
    • Applied downgrade-compatible writeback only for non-routed safe points.
  • Tests

    • Added tests validating txn safe points persist and load correctly across local and routed meta service group endpoints.

Signed-off-by: ystaticy <y_static_y@sina.com>
@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-linked-issue dco-signoff: yes Indicates the PR's author has signed the dco. release-note-none Denotes a PR that doesn't merit a release note. labels Jun 29, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

[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 siddontang 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 Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4dfec81e-db52-4182-8f79-410ff1cbc61c

📥 Commits

Reviewing files that changed from the base of the PR and between 2516143 and e932de8.

📒 Files selected for processing (2)
  • pkg/storage/endpoint/gc_states_test.go
  • pkg/storage/endpoint/meta_service_group_gc_storage.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/storage/endpoint/gc_states_test.go

📝 Walkthrough

Walkthrough

Adds meta-service-group-aware txn safe point routing to the GC subsystem. A new MetaServiceGroupGCStorageProvider routes txn safe point reads and writes to per-group etcd storage endpoints. GCStateProvider gains options, routed load/transaction helpers, and gc_state_manager and the server are updated to use them.

Changes

Meta-service group GC txn safe point routing

Layer / File(s) Summary
MetaServiceGroupGCStorageProvider interfaces and implementation
pkg/storage/endpoint/meta_service_group_gc_storage.go
Defines MetaServiceGroupIDProvider and MetaServiceGroupResolver; implements MetaServiceGroupGCStorageProvider with cached per-group etcd clients, endpoint normalization, GetStorage, and Close.
Keyspace manager resolver methods
pkg/keyspace/keyspace.go, pkg/keyspace/meta_service_group.go
Adds GetMetaServiceGroupIDByKeyspaceID to keyspace.Manager and GetGroupEndpoints to MetaServiceGroupManager.
GCStateProvider routing options and transactions
pkg/storage/endpoint/gc_states.go
Adds GCStateProviderOption/WithMetaServiceGroupStorageProvider, GetGCStateProviderWithOptions, routed LoadTxnSafePoint, IsTxnSafePointRouted, and RunInTxnSafePointTransaction.
gc_state_manager routed advancement
pkg/gc/gc_state_manager.go
advanceTxnSafePointImpl checks IsTxnSafePointRouted, switches to RunInTxnSafePointTransaction, skips the gc_worker barrier when routed, and narrows downgrade-compatible write-back.
Server wiring and lifecycle
server/server.go
Server gains metaServiceGroupGCStorageProvider; startServer constructs and injects it; Close shuts it down.
Tests
pkg/storage/endpoint/gc_states_test.go
Updates provider construction and adds coverage for routed txn safe points across local and remote storage endpoints.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • tikv/pd#10677: Both PRs modify GCStateManager.advanceTxnSafePointImpl with overlapping txn safe point advancement logic.

Suggested labels

lgtm, approved

Suggested reviewers

  • rleungx
  • lhy1024
  • AmoebaProtozoa

Poem

🐇 I hop by group and endpoint bright,
Safe points now travel left and right.
GC watches every trail,
Routed paths won’t lose the mail.
A happy nibble, neat and true —
The rabbit grins at work anew.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is mostly the untouched template, with only placeholder content and no real problem, implementation, or testing details. Replace the template text with a real summary, add a valid Issue Number, explain the change and tests, and fill out the checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 56.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is clearly related to the main change: routing GC etcd key handling through meta service groups.
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 the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jun 29, 2026
Signed-off-by: ystaticy <y_static_y@sina.com>
@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 Jun 29, 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.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/gc/gc_state_manager.go (1)

469-484: 🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

Preserve the local GC-state revision guard when txn safe points are routed.

The routed transaction now commits against the meta-service-group storage revision, but the blockers are still read from local GC state (LoadGCSafePoint, LoadAllGCBarriers, CompatibleLoadTiDBMinStartTS, LoadAllGlobalGCBarriers). A concurrent local barrier write won’t conflict with the remote transaction, so the txn safe point can advance past a newly added blocker; expired global-barrier deletes are also enqueued against the remote storage.

Please keep blocker reads/writes under a local GC-state revision check, or move the relevant blocker state into the same routed storage before advancing the routed txn safe point.

Also applies to: 535-544, 557-563

🤖 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 `@pkg/gc/gc_state_manager.go` around lines 469 - 484, The routed txn safe point
update in the GC state flow is bypassing the local GC-state revision guard, so
blocker reads and related writes can race with concurrent local GC state
changes. In the GCStateManager path around the txn safe point transaction, keep
the blocker checks and updates (LoadGCSafePoint, LoadAllGCBarriers,
CompatibleLoadTiDBMinStartTS, LoadAllGlobalGCBarriers) protected by the local
revision validation, or move that blocker state into the same routed storage
used by the transaction before advancing the safe point. Make the same
adjustment in the other affected GC-state methods so routed writes cannot skip
newly added blockers.
🧹 Nitpick comments (1)
pkg/storage/endpoint/gc_states_test.go (1)

713-780: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add coverage for routed advancement with concurrent/local blockers.

The test verifies read/write placement, but not the GC manager path where txn safe points are routed while GC barriers remain local. Please add a case that exercises AdvanceTxnSafePoint with local barriers/global barriers to catch revision-guard regressions.

🤖 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 `@pkg/storage/endpoint/gc_states_test.go` around lines 713 - 780, The current
test only verifies where txn safe points are stored, but it does not cover
routed advancement through the GC manager when local and global GC barriers are
present. Extend TestTxnSafePointWithMetaServiceGroups to exercise
AdvanceTxnSafePoint on the GC state provider and include a case with local
barriers/global barriers so revision-guard behavior is validated. Use the
existing localStorage, group1Storage, group2Storage, and provider setup to
assert the advancement path and resulting safe point values.
🤖 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.

Inline comments:
In `@client/client.go`:
- Around line 569-606: Use a classic counted retry loop in the GetTSAsync retry
path so the final retry count is preserved for the post-loop check; the current
`for retryCount = range maxRetries` form leaves `retryCount` at `maxRetries-1`
after exhaustion, which prevents `checkRetry` from firing as intended. Update
the loop in the `GetTSAsync` retry logic so `retryCount` reaches `maxRetries`
when all attempts are used, while keeping the existing retryable error handling,
logging, and failpoint behavior unchanged.

In `@client/clients/tso/client.go`:
- Around line 1041-1043: The failpoint block in the health check path mutates
resp.Status before confirming resp is non-nil, which can panic when the health
check already failed. Update the logic around the failpoint in the health-check
handler to guard resp before setting its Status, using the existing health-check
response handling in the same function so the mutation only happens when a
response object is available.

In `@pkg/storage/endpoint/gc_states.go`:
- Around line 499-508: `RunInTxnSafePointTransaction` is still handing callers a
full `GCStateWriteBatch`, which lets routed txn-safe-point code write
non-txn-safe-point GC state on the meta-service-group storage. Update
`GCStateProvider.RunInTxnSafePointTransaction` and the related
`runInGCStateTransactionOnStorage`/`advanceTxnSafePointImpl` call path so this
API only permits txn-safe-point writes, either by narrowing the batch surface or
validating/rejecting barrier and global-barrier operations before execution.

In `@pkg/storage/endpoint/meta_service_group_gc_storage.go`:
- Around line 134-136: The stale etcd client cleanup in the group endpoint swap
logic is ignoring Close() failures, which violates the errcheck guideline and
can hide resource issues. Update the old.client.Close() call in the meta service
group GC storage path to handle and surface the error instead of discarding it,
using the existing group/client cleanup flow around old.client and the endpoint
update logic so failures are logged or propagated appropriately.

---

Outside diff comments:
In `@pkg/gc/gc_state_manager.go`:
- Around line 469-484: The routed txn safe point update in the GC state flow is
bypassing the local GC-state revision guard, so blocker reads and related writes
can race with concurrent local GC state changes. In the GCStateManager path
around the txn safe point transaction, keep the blocker checks and updates
(LoadGCSafePoint, LoadAllGCBarriers, CompatibleLoadTiDBMinStartTS,
LoadAllGlobalGCBarriers) protected by the local revision validation, or move
that blocker state into the same routed storage used by the transaction before
advancing the safe point. Make the same adjustment in the other affected
GC-state methods so routed writes cannot skip newly added blockers.

---

Nitpick comments:
In `@pkg/storage/endpoint/gc_states_test.go`:
- Around line 713-780: The current test only verifies where txn safe points are
stored, but it does not cover routed advancement through the GC manager when
local and global GC barriers are present. Extend
TestTxnSafePointWithMetaServiceGroups to exercise AdvanceTxnSafePoint on the GC
state provider and include a case with local barriers/global barriers so
revision-guard behavior is validated. Use the existing localStorage,
group1Storage, group2Storage, and provider setup to assert the advancement path
and resulting safe point values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec022aff-c37c-43ed-93d0-df1322ada79a

📥 Commits

Reviewing files that changed from the base of the PR and between 6f795b1 and 7cebc5c.

📒 Files selected for processing (9)
  • client/client.go
  • client/clients/tso/client.go
  • pkg/gc/gc_state_manager.go
  • pkg/keyspace/keyspace.go
  • pkg/keyspace/meta_service_group.go
  • pkg/storage/endpoint/gc_states.go
  • pkg/storage/endpoint/gc_states_test.go
  • pkg/storage/endpoint/meta_service_group_gc_storage.go
  • server/server.go

Comment thread client/client.go Outdated
Comment thread client/clients/tso/client.go Outdated
Comment on lines +1041 to +1043
if _, _err_ := failpoint.Eval(_curpkg_("unreachableNetwork")); _err_ == nil {
resp.Status = healthpb.HealthCheckResponse_UNKNOWN
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard resp before mutating failpoint state.

This failpoint runs before err is checked, so an errored health check with a nil response will panic on resp.Status.

Proposed fix
 			resp, err := healthCli.Check(healthCtx, &healthpb.HealthCheckRequest{Service: ""})
 			if _, _err_ := failpoint.Eval(_curpkg_("unreachableNetwork")); _err_ == nil {
+				if resp == nil {
+					resp = &healthpb.HealthCheckResponse{}
+				}
 				resp.Status = healthpb.HealthCheckResponse_UNKNOWN
 			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if _, _err_ := failpoint.Eval(_curpkg_("unreachableNetwork")); _err_ == nil {
resp.Status = healthpb.HealthCheckResponse_UNKNOWN
})
}
resp, err := healthCli.Check(healthCtx, &healthpb.HealthCheckRequest{Service: ""})
if _, _err_ := failpoint.Eval(_curpkg_("unreachableNetwork")); _err_ == nil {
if resp == nil {
resp = &healthpb.HealthCheckResponse{}
}
resp.Status = healthpb.HealthCheckResponse_UNKNOWN
}
🤖 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 `@client/clients/tso/client.go` around lines 1041 - 1043, The failpoint block
in the health check path mutates resp.Status before confirming resp is non-nil,
which can panic when the health check already failed. Update the logic around
the failpoint in the health-check handler to guard resp before setting its
Status, using the existing health-check response handling in the same function
so the mutation only happens when a response object is available.

Comment on lines +499 to +508
func (p GCStateProvider) RunInTxnSafePointTransaction(keyspaceID uint32, f func(GCStateProvider, *GCStateWriteBatch) error) error {
storage, err := p.getTxnSafePointStorage(keyspaceID)
if err != nil {
return err
}
txnSafePointProvider := NewGCStateProvider(storage)
return runInGCStateTransactionOnStorage(storage, func(wb *GCStateWriteBatch) error {
return f(txnSafePointProvider, wb)
})
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep routed txn-safe-point transactions scoped to txn-safe-point data.

RunInTxnSafePointTransaction still exposes a full GCStateWriteBatch, so callers can enqueue GC barrier/global barrier writes that will execute on the routed meta-service-group storage instead of the local GC-state storage. This is already easy to hit from advanceTxnSafePointImpl; consider narrowing this API or validating allowed ops.

🤖 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 `@pkg/storage/endpoint/gc_states.go` around lines 499 - 508,
`RunInTxnSafePointTransaction` is still handing callers a full
`GCStateWriteBatch`, which lets routed txn-safe-point code write
non-txn-safe-point GC state on the meta-service-group storage. Update
`GCStateProvider.RunInTxnSafePointTransaction` and the related
`runInGCStateTransactionOnStorage`/`advanceTxnSafePointImpl` call path so this
API only permits txn-safe-point writes, either by narrowing the batch surface or
validating/rejecting barrier and global-barrier operations before execution.

Comment on lines +134 to +136
if old != nil && old.client != nil {
_ = old.client.Close()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Handle the stale etcd client close error.

Line 135 ignores Close() failures, which can hide cleanup/resource issues when group endpoints change.

Proposed fix
 	if old != nil && old.client != nil {
-		_ = old.client.Close()
+		if err := old.client.Close(); err != nil {
+			return nil, errors.Wrapf(err, "close stale meta-service group %s etcd client", groupID)
+		}
 	}

As per coding guidelines, “No ignored errors unless allowed in .golangci.yml errcheck exclusions.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if old != nil && old.client != nil {
_ = old.client.Close()
}
if old != nil && old.client != nil {
if err := old.client.Close(); err != nil {
return nil, errors.Wrapf(err, "close stale meta-service group %s etcd client", groupID)
}
}
🤖 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 `@pkg/storage/endpoint/meta_service_group_gc_storage.go` around lines 134 -
136, The stale etcd client cleanup in the group endpoint swap logic is ignoring
Close() failures, which violates the errcheck guideline and can hide resource
issues. Update the old.client.Close() call in the meta service group GC storage
path to handle and surface the error instead of discarding it, using the
existing group/client cleanup flow around old.client and the endpoint update
logic so failures are logged or propagated appropriately.

Source: Coding guidelines

Signed-off-by: ystaticy <y_static_y@sina.com>
if err != nil {
return AdvanceTxnSafePointResult{}, err
}
err = m.gcMetaStorage.RunInTxnSafePointTransaction(keyspaceID, func(txnSafePointProvider endpoint.GCStateProvider, wb *endpoint.GCStateWriteBatch) error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This transaction writes the routed txn safe point in remote etcd, but still reads local GC barriers, global barriers, and min-start-ts. Local blocker changes will not conflict with the remote revision, so the txn safe point can advance past a new blocker.

newTxnSafePoint = max(oldTxnSafePoint, minBlocker)

if downgradeCompatibleMode {
if downgradeCompatibleMode && !isTxnSafePointRouted {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This routed guard is also needed for the expired global barrier cleanup above. Otherwise the routed batch deletes from remote storage while the global barriers were read from local storage.

Signed-off-by: ystaticy <y_static_y@sina.com>
@ti-chi-bot

ti-chi-bot Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

[FORMAT CHECKER NOTIFICATION]

Notice: To remove the do-not-merge/needs-linked-issue label, please provide the linked issue number on one line in the PR body, for example: Issue Number: close #123 or Issue Number: ref #456, multiple issues should use full syntax for each issue and be separated by a comma, like: Issue Number: close #123, ref #456.

📖 For more info, you can check the "Linking issues" section in the CONTRIBUTING.md.

@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 69.93464% with 46 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.11%. Comparing base (4335bc3) to head (e932de8).
⚠️ Report is 8 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10949      +/-   ##
==========================================
- Coverage   79.26%   79.11%   -0.15%     
==========================================
  Files         540      542       +2     
  Lines       74954    75457     +503     
==========================================
+ Hits        59412    59700     +288     
- Misses      11371    11501     +130     
- Partials     4171     4256      +85     
Flag Coverage Δ
unittests 79.11% <69.93%> (-0.15%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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. do-not-merge/needs-linked-issue release-note-none Denotes a PR that doesn't merit a release note. 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