Skip to content

pd-ctl: add GC state inspection commands - #11054

Open
wfxr wants to merge 18 commits into
tikv:masterfrom
wfxr:wfxr/gc-state-cmd
Open

pd-ctl: add GC state inspection commands#11054
wfxr wants to merge 18 commits into
tikv:masterfrom
wfxr:wfxr/gc-state-cmd

Conversation

@wfxr

@wfxr wfxr commented Jul 28, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

PD exposes per-keyspace and cluster-wide GC state through RPCs, but operators
cannot inspect that state through pd-ctl. This makes it difficult to identify
whether GC advancement is blocked by a keyspace-local barrier or a
cluster-wide global barrier.

Issue Number: close #11013, ref #8978

What is changed and how does it work?

Add read-only pd-ctl gc-state keyspace, gc-state global, and
gc-state all commands.

Expose the server-provided keyspace-level GC mode through the public GC client
model so the command can distinguish independent keyspace GC from unified GC.

Return deterministic JSON containing effective transaction and GC safe points,
local GC barriers, and cluster-wide global GC barriers. Keep local barriers in
per-keyspace results and report global barriers only in the global view or once
at the top level of the combined view.

Document the troubleshooting workflow and cover the command with unit,
Classic/NextGen integration, help-contract, and TiDB-X playground tests.

Check List

Tests

  • Unit test
    • GC client protobuf conversion and public-model behavior
    • GC-state ID parsing, JSON projection, sorting, TTL conversion, command
      lifecycle, error handling, and help contracts
  • Integration test
    • Classic and NextGen PD clusters with keyspace-local and global GC barriers
    • Root pd-ctl command execution and legacy command regression coverage
  • Manual test
    • Built and inspected gc-state, keyspace, global, and all help output
    • Verified all three commands against a TiDB-X playground
    • Injected keyspace-local and global barriers through the public GC client
      and verified their placement and values in all three JSON views
    • Ran make static, make pd-ctl, and NEXT_GEN=1 make pd-server pd-ctl

Release note

Add `pd-ctl gc-state` commands for inspecting per-keyspace GC safe points, local GC barriers, and cluster-wide global GC barriers.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Added pd-ctl gc-state with keyspace, global, and all views.
    • GC state now includes keyspace-level GC classification (IsKeyspaceLevelGC).
    • Added --include-expired to control visibility of zero-TTL (expired) GC barriers in JSON output.
  • Documentation
    • Expanded GC state troubleshooting guidance, including deterministic JSON examples and TTL semantics.
  • Bug Fixes
    • Improved cluster ID test isolation via cleanup after execution.
  • Tests
    • Added unit and integration coverage to preserve keyspace-level GC fields and validate expired-barrier behavior/TTL.

@ti-chi-bot

ti-chi-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ti-chi-bot ti-chi-bot Bot added release-note Denotes a PR that will be considered when it comes time to generate release notes. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. do-not-merge/needs-triage-completed dco-signoff: yes Indicates the PR's author has signed the dco. labels Jul 28, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 28, 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 rleungx 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 28, 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 Plus

Run ID: d40a5e46-11cd-402a-950c-09e89119fbb3

📥 Commits

Reviewing files that changed from the base of the PR and between dd7b932 and b134800.

📒 Files selected for processing (4)
  • tools/pd-ctl/README.md
  • tools/pd-ctl/pdctl/command/gc_state_command.go
  • tools/pd-ctl/pdctl/command/gc_state_command_test.go
  • tools/pd-ctl/tests/safepoint/gc_state_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • tools/pd-ctl/README.md

📝 Walkthrough

Walkthrough

Adds keyspace-level GC metadata propagation and introduces the read-only pd-ctl gc-state command with keyspace, global, and all views, deterministic JSON output, optional expired-barrier inclusion, documentation, unit tests, and integration coverage.

Changes

GC state inspection

Layer / File(s) Summary
GC scope metadata
client/clients/gc/client.go, client/gc_client.go, client/gc_client_test.go, tests/integrations/client/client_test.go, pkg/storage/endpoint/cluster_id_test.go
GC state conversion preserves whether a state is keyspace-level GC, with focused unit, integration, and cleanup coverage.
GC state command and barrier filtering
tools/pd-ctl/pdctl/command/gc_state_command.go, tools/pd-ctl/pdctl/ctl.go
Adds PD-backed keyspace, global, and all views, deterministic barrier JSON, TTL conversion, and --include-expired filtering.
Command validation and integration coverage
tools/pd-ctl/pdctl/command/gc_state_command_test.go, tools/pd-ctl/tests/safepoint/gc_state_test.go, tools/pd-ctl/README.md
Covers command routing, output contracts, validation, errors, expired barriers, TTL semantics, documentation, and test-cluster behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant GCStateCommand
  participant PDGCStateReader
  participant PD
  Operator->>GCStateCommand: invoke keyspace, global, or all with include-expired option
  GCStateCommand->>PDGCStateReader: request GC state
  PDGCStateReader->>PD: call GC state RPC
  PD-->>PDGCStateReader: return states and barriers
  PDGCStateReader-->>GCStateCommand: return state data
  GCStateCommand-->>Operator: write filtered sorted JSON
Loading

Possibly related PRs

  • tikv/pd#10669: Refactors the same GC state structure and barrier-exclusion paths.
  • tikv/pd#11024: Modifies protobuf conversion logic in the same pbToGCState code path.

Suggested labels: lgtm, approved

Suggested reviewers: rleungx, bufferflies, jmpotato

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding pd-ctl GC state inspection commands.
Description check ✅ Passed The description covers the problem, changes, tests, and release note, and includes the required issue number line.
Linked Issues check ✅ Passed The changes implement a read-only gc-state command for keyspace and all-keyspace GC troubleshooting with safe points and barriers.
Out of Scope Changes check ✅ Passed No clearly unrelated code changes stand out; the extra global/include-expired work remains aligned with GC-state inspection.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 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 Jul 28, 2026
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.65517% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.34%. Comparing base (070828c) to head (b134800).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #11054      +/-   ##
==========================================
+ Coverage   79.23%   79.34%   +0.11%     
==========================================
  Files         540      542       +2     
  Lines       76010    76639     +629     
==========================================
+ Hits        60226    60813     +587     
- Misses      11533    11555      +22     
- Partials     4251     4271      +20     
Flag Coverage Δ
unittests 79.34% <89.65%> (+0.11%) ⬆️

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.

wfxr added 13 commits July 28, 2026 14:26
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
@wfxr
wfxr force-pushed the wfxr/gc-state-cmd branch from dc851d9 to e2ce6ae Compare July 28, 2026 06:29
Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
@wfxr
wfxr marked this pull request as ready for review July 28, 2026 06:42
@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 28, 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: 2

🧹 Nitpick comments (1)
tools/pd-ctl/pdctl/command/gc_state_command.go (1)

344-352: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Pass the original error to status.Code.

status.FromError unwraps via errors.As, so status.Code(err) already covers fmt.Errorf("%w") chains; errors.Cause(err) only follows pingcap/errors causer chains and can miss gRPC status errors wrapped outside that chain. Apply this fix to the duplicate Unimplemented checks as well.

🤖 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 `@tools/pd-ctl/pdctl/command/gc_state_command.go` around lines 344 - 352,
Update the Unimplemented status check in the GC-state retrieval error path to
pass the original err directly to status.Code instead of errors.Cause(err),
preserving the existing annotation behavior. Apply the same change to every
duplicate Unimplemented check in this command.
🤖 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 `@tools/pd-ctl/pdctl/command/gc_state_command.go`:
- Around line 197-208: Update newLocalGCBarrierOutputs to skip nil barrier
entries before accessing BarrierID, BarrierTS, or TTL. Preserve the existing
output construction and sorting for non-nil entries so malformed protobuf
responses do not panic the CLI.

In `@tools/pd-ctl/tests/safepoint/gc_state_test.go`:
- Around line 83-88: Widen the lower TTL bound in the expires branch of the
safepoint test from 3595 seconds to a more tolerant value, while keeping the
3600-second upper bound and the non-expiring MaxInt64 assertion unchanged.

---

Nitpick comments:
In `@tools/pd-ctl/pdctl/command/gc_state_command.go`:
- Around line 344-352: Update the Unimplemented status check in the GC-state
retrieval error path to pass the original err directly to status.Code instead of
errors.Cause(err), preserving the existing annotation behavior. Apply the same
change to every duplicate Unimplemented check in this command.
🪄 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 Plus

Run ID: e91048ab-3bb5-41ce-83f7-160a2afa5049

📥 Commits

Reviewing files that changed from the base of the PR and between 276877c and e5ed1dd.

📒 Files selected for processing (10)
  • client/clients/gc/client.go
  • client/gc_client.go
  • client/gc_client_test.go
  • pkg/storage/endpoint/cluster_id_test.go
  • tests/integrations/client/client_test.go
  • tools/pd-ctl/README.md
  • tools/pd-ctl/pdctl/command/gc_state_command.go
  • tools/pd-ctl/pdctl/command/gc_state_command_test.go
  • tools/pd-ctl/pdctl/ctl.go
  • tools/pd-ctl/tests/safepoint/gc_state_test.go

Comment thread tools/pd-ctl/pdctl/command/gc_state_command.go Outdated
Comment thread tools/pd-ctl/tests/safepoint/gc_state_test.go Outdated
@wfxr

wfxr commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

/retest

wfxr added 2 commits July 28, 2026 15:45
Present only effective GC scopes in gc-state all and use the NullKeyspace scope for unified GC keyspaces.

Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
Skip nil local and global barrier entries before projecting JSON, and use gRPC status unwrapping directly for compatibility errors. Relax the finite TTL assertion to avoid slow-CI flakes.

Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
@wfxr

wfxr commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

/retest

Show correlated local and global barriers across the keyspace, global, and combined GC-state views. Clarify NullKeyspace placement, empty arrays, and finite versus non-expiring TTLs.

Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
@wfxr

wfxr commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

/retest

2 similar comments
@wfxr

wfxr commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

/retest

@wfxr

wfxr commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

/retest

if barrier == nil {
continue
}
result = append(result, gcBarrierOutput{

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.

When an expired barrier has not yet been lazily deleted by a later safe-point advancement, the read RPCs still return it with a zero TTL, and both projection helpers include it unconditionally. gc-state therefore mixes inactive local and global barriers with current blockers, so operators and scripts can attribute a stalled safe point to the wrong barrier.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Confirmed. I’ll omit zero-TTL barriers by default so gc-state shows effective blockers. However, expired barriers that are still awaiting lazy deletion are useful for diagnosing what previously blocked GC and whether a later safe-point advancement has performed cleanup. I’ll therefore add an --include-expired flag for keyspace, global, and all; when enabled, these barriers will remain in the existing arrays with ttl_seconds: 0.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done by b134800

Keep the effective GC state focused on active barriers while allowing operators to inspect zero-TTL entries with --include-expired.

Signed-off-by: Wenxuan Zhang <wenxuangm@gmail.com>
@wfxr

wfxr commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

/retest

@wfxr
wfxr requested a review from rleungx July 30, 2026 06:31
@wfxr

wfxr commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

/retest

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-triage-completed release-note Denotes a PR that will be considered when it comes time to generate release notes. 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.

pd-ctl: add a gc-state command for keyspace GC troubleshooting

2 participants