Skip to content

[#1][TSO/Keyspace Group] Remove archive/tombstone keyspace from group (407ad06f)#10556

Open
bufferflies wants to merge 3 commits intotikv:masterfrom
bufferflies:pr-merge/407ad06f-remove-archive-tombstone
Open

[#1][TSO/Keyspace Group] Remove archive/tombstone keyspace from group (407ad06f)#10556
bufferflies wants to merge 3 commits intotikv:masterfrom
bufferflies:pr-merge/407ad06f-remove-archive-tombstone

Conversation

@bufferflies
Copy link
Copy Markdown
Contributor

@bufferflies bufferflies commented Apr 2, 2026

Summary

  • add a keyspace-group API to remove archived or tombstoned keyspaces from a group
  • filter request keyspaces by current keyspace state before mutating group membership
  • add API tests covering skipped, missing, and archived/tombstone removal cases

Issue Number

ref #10516, close #10555

author: @ystaticy

cp 407ad06f

Checklist

  • cherry-picked from upstream commit
  • conflict resolved against current master
  • make check

Summary by CodeRabbit

  • New Features

    • Added DELETE API to remove keyspaces from a keyspace group. Validates keyspace states (only ARCHIVED/TOMBSTONE), skips non-existent or already-absent entries, prevents removal of the default keyspace, rejects empty requests, returns current group when nothing is removed, and applies removals atomically with in-memory refresh.
  • Tests

    • Added end-to-end tests covering removal semantics, state validation, mixed/invalid inputs, and error scenarios.

…ikv#420)

* support remove archive & tombstone  keyspace from keyspace group

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

* support keyspace list

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

* no keyspace to remove ,return succ

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

* remove debug log

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

---------

Signed-off-by: ystaticy <y_static_y@sina.com>
(cherry picked from commit 407ad06)
@ti-chi-bot
Copy link
Copy Markdown
Contributor

ti-chi-bot bot commented Apr 2, 2026

Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@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. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels Apr 2, 2026
@ti-chi-bot
Copy link
Copy Markdown
Contributor

ti-chi-bot bot commented Apr 2, 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 overvenus 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

@bufferflies
Copy link
Copy Markdown
Contributor Author

/ping @bufferflies

@ti-chi-bot ti-chi-bot bot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Apr 2, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ab1f9bc5-8de1-4ddd-8b59-e956695430e4

📥 Commits

Reviewing files that changed from the base of the PR and between 53bf48c and 14d91a3.

📒 Files selected for processing (1)
  • tests/server/apiv2/handlers/tso_keyspace_group_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/server/apiv2/handlers/tso_keyspace_group_test.go

📝 Walkthrough

Walkthrough

Adds a service method and HTTP DELETE endpoint to remove archived or tombstone keyspaces from a keyspace group; performs validation, filters non-removable IDs, persists changes via an etcd transaction only when needed, and updates the in-memory groups cache.

Changes

Cohort / File(s) Summary
Service layer
pkg/keyspace/tso_keyspace_group.go
Added RemoveKeyspacesFromGroup(groupID uint32, keyspaceIDs []uint32) which acquires the manager write lock, loads the group via etcd txn, skips constant.DefaultKeyspaceID, ignores non-members, persists removals only when there are changes, and updates in-memory cache.
HTTP handler & routing
server/apiv2/handlers/tso_keyspace_group.go
Added DELETE /tso/keyspace-groups/:id/keyspaces handler RemoveKeyspacesFromGroup and RemoveKeyspacesFromGroupParams; validates path/body, loads keyspace metadata to filter to ARCHIVED/TOMBSTONE, skips missing keyspaces, and delegates to service or returns current group when nothing to remove.
Test utilities
tests/server/apiv2/handlers/testutil.go
Added MustRemoveKeyspacesFromGroup and FailRemoveKeyspacesFromGroupWithCode test helpers to call the new DELETE endpoint and assert/parse responses.
Tests
tests/server/apiv2/handlers/tso_keyspace_group_test.go
Added TestRemoveKeyspacesFromGroup with failpoint setup; creates keyspaces, exercises removal semantics across states (ENABLED/ARCHIVED/TOMBSTONE), mixed/missing IDs, non-existent group and empty-list validation; adjusted imports/constants for keyspace packages.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler as HTTP Handler
    participant KeyspaceMgr as KeyspaceManager
    participant GroupMgr as GroupManager
    participant Etcd as etcd/Storage
    participant Cache as In-Memory Cache

    Client->>Handler: DELETE /tso/keyspace-groups/:id/keyspaces\n{keyspaces: [...]}
    Handler->>Handler: Validate group ID and body
    Handler->>KeyspaceMgr: Load each keyspace metadata
    KeyspaceMgr-->>Handler: Metadata (state or not found)
    Handler->>Handler: Filter to ARCHIVED/TOMBSTONE (skip missing)
    alt No valid keyspaces
        Handler->>GroupMgr: GetKeyspaceGroupByID(groupID)
        GroupMgr-->>Handler: Current KeyspaceGroup
        Handler-->>Client: 200 OK {KeyspaceGroup}
    else Has valid keyspaces
        Handler->>GroupMgr: RemoveKeyspacesFromGroup(groupID, validIDs)
        GroupMgr->>GroupMgr: Acquire write lock
        GroupMgr->>Etcd: Load KeyspaceGroup (txn)
        Etcd-->>GroupMgr: KeyspaceGroup or not found
        GroupMgr->>GroupMgr: Build removal set (skip default/non-members)
        alt Removals needed
            GroupMgr->>Etcd: Save updated KeyspaceGroup (txn)
            Etcd-->>GroupMgr: Success
            GroupMgr->>Cache: groups[userKind].Put(kg)
        else No changes required
            GroupMgr-->>GroupMgr: Skip persistence
        end
        GroupMgr-->>Handler: Updated KeyspaceGroup
        Handler-->>Client: 200 OK {KeyspaceGroup}
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hoppity-hop, the list trims down,
Archived leaves drift off the ground.
Transactions hum, the cache says “done,”
Defaults stay safe beneath the sun.
🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change: adding an API to remove archive/tombstone keyspaces from a keyspace group.
Description check ✅ Passed The description provides a clear summary, references linked issues, and includes a completed checklist, though it lacks a 'What problem does this PR solve?' section.
Linked Issues check ✅ Passed The PR fully implements the objective from #10555: removing archived/tombstoned keyspaces from groups via a new API with proper filtering.
Out of Scope Changes check ✅ Passed All changes directly support the removal of archived/tombstone keyspaces: backend logic, HTTP endpoint, test utilities, and comprehensive tests. No out-of-scope modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

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

✨ 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 and usage tips.

Copy link
Copy Markdown

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/keyspace/tso_keyspace_group.go`:
- Around line 427-487: In RemoveKeyspacesFromGroup, before building toRemove add
the same split/merge guards used elsewhere: after loading kg validate
kg.IsSplitting() and kg.IsMerging() and return
errs.ErrKeyspaceGroupInSplit.FastGenByArgs(groupID) or
errs.ErrKeyspaceGroupInMerging.FastGenByArgs(groupID) respectively; ensure these
checks occur right after the kg nil check (using kg and groupID) so the function
aborts mutations during split/merge just like SetNodesForKeyspaceGroup,
UpdateKeyspaceForGroup, MoveKeyspacesToGroup, DeleteKeyspaceGroupByID, and
MergeKeyspaceGroups.

In `@server/apiv2/handlers/tso_keyspace_group.go`:
- Around line 581-584: The JSON bind error response uses
errs.ErrBindJSON.Wrap(err).GenWithStackByCause() (an error object) directly in
c.AbortWithStatusJSON after c.BindJSON(&params); update the call to pass a
string by invoking .Error() on the generated error (i.e., use
errs.ErrBindJSON.Wrap(err).GenWithStackByCause().Error()) so the payload
serializes consistently like other handlers; modify the code path that calls
c.AbortWithStatusJSON to send the .Error() string.
- Around line 625-633: When validKeyspaces is empty the handler calls
groupManager.GetKeyspaceGroupByID and returns kg without checking for nil;
update the handler to check if kg == nil after calling GetKeyspaceGroupByID and
return an error (e.g., c.AbortWithStatusJSON with ErrKeyspaceGroupNotExists or
appropriate HTTP 404/500) instead of returning HTTP 200 with null. Ensure you
reference the existing symbols: validKeyspaces,
groupManager.GetKeyspaceGroupByID, kg, and ErrKeyspaceGroupNotExists when
implementing the nil-check and error response.

In `@tests/server/apiv2/handlers/tso_keyspace_group_test.go`:
- Around line 276-277: The test enables two failpoints via
failpoint.Enable("github.com/tikv/pd/server/delayStartServerLoop",
`return(true)`) and
failpoint.Enable("github.com/tikv/pd/pkg/keyspace/skipSplitRegion",
"return(true)") but never disables them; add deferred cleanup immediately after
each successful enable: call defer
re.NoError(failpoint.Disable("github.com/tikv/pd/server/delayStartServerLoop"))
and defer
re.NoError(failpoint.Disable("github.com/tikv/pd/pkg/keyspace/skipSplitRegion"))
so both failpoints are disabled when the test exits.
🪄 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: dcb16c05-d4ad-4596-9132-2f4b74e702ec

📥 Commits

Reviewing files that changed from the base of the PR and between 319d880 and 911a71a.

📒 Files selected for processing (4)
  • pkg/keyspace/tso_keyspace_group.go
  • server/apiv2/handlers/tso_keyspace_group.go
  • tests/server/apiv2/handlers/testutil.go
  • tests/server/apiv2/handlers/tso_keyspace_group_test.go

@bufferflies
Copy link
Copy Markdown
Contributor Author

/ping @ystaticy

Signed-off-by: bufferflies <1045931706@qq.com>
@bufferflies
Copy link
Copy Markdown
Contributor Author

Re-reviewed the latest follow-up on head 53bf48c2997a0d1e9a3664a946947c87aef93d07.

This delta looks clean to me. The unresolved review items in the keyspace-group removal path and the related test cleanup are addressed, and I do not see a new behavior regression introduced by this follow-up.

I do not have a new finding on this delta.

Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/keyspace/tso_keyspace_group.go`:
- Around line 455-460: The loop that builds toRemove currently only skips
constant.DefaultKeyspaceID and can thus remove the bootstrap/system keyspace;
update the check in the keyspaceIDs iteration (where toRemove is populated) to
also skip the protected bootstrap keyspace by using the existing helpers: call
GetBootstrapKeyspaceID() or isProtectedKeyspaceID(ksID) and treat matches as
exempt from removal (i.e., continue the loop when ksID ==
constant.DefaultKeyspaceID || ksID == GetBootstrapKeyspaceID() ||
isProtectedKeyspaceID(ksID)) so the protected member of the default group is
never removed.

In `@tests/server/apiv2/handlers/tso_keyspace_group_test.go`:
- Around line 276-279: The defer calls currently call failpoint.Disable
immediately because re.NoError(...) is invoked at defer time; change the defer
usage to defer a closure that calls re.NoError(failpoint.Disable(...)) so the
Disable calls run at function exit. Locate the two places where
failpoint.Enable("github.com/tikv/pd/server/delayStartServerLoop", ...) and
failpoint.Enable("github.com/tikv/pd/pkg/keyspace/skipSplitRegion", ...) are
used and replace their corresponding defer re.NoError(failpoint.Disable(...))
with defer func() {
re.NoError(failpoint.Disable("github.com/tikv/pd/server/delayStartServerLoop"))
}() and defer func() {
re.NoError(failpoint.Disable("github.com/tikv/pd/pkg/keyspace/skipSplitRegion"))
}() respectively so the disables execute only when the test exits.
🪄 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: a5b58eb4-909d-4901-87ab-efa363515454

📥 Commits

Reviewing files that changed from the base of the PR and between 911a71a and 53bf48c.

📒 Files selected for processing (3)
  • pkg/keyspace/tso_keyspace_group.go
  • server/apiv2/handlers/tso_keyspace_group.go
  • tests/server/apiv2/handlers/tso_keyspace_group_test.go

Comment on lines +455 to +460
// Build a set of keyspaces to remove (excluding default keyspace)
toRemove := make(map[uint32]struct{})
for _, ksID := range keyspaceIDs {
// Skip default keyspace
if ksID == constant.DefaultKeyspaceID {
continue
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Protect the bootstrap/system keyspace here too.

This branch only skips constant.DefaultKeyspaceID, but the rest of this file treats the protected member of the default group as the bootstrap keyspace via GetBootstrapKeyspaceID() / isProtectedKeyspaceID(). In deployments where the bootstrap keyspace is the system keyspace, this path can remove it from the default group and break that invariant.

Suggested fix
-			if ksID == constant.DefaultKeyspaceID {
+			if isProtectedKeyspaceID(ksID) {
 				continue
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/keyspace/tso_keyspace_group.go` around lines 455 - 460, The loop that
builds toRemove currently only skips constant.DefaultKeyspaceID and can thus
remove the bootstrap/system keyspace; update the check in the keyspaceIDs
iteration (where toRemove is populated) to also skip the protected bootstrap
keyspace by using the existing helpers: call GetBootstrapKeyspaceID() or
isProtectedKeyspaceID(ksID) and treat matches as exempt from removal (i.e.,
continue the loop when ksID == constant.DefaultKeyspaceID || ksID ==
GetBootstrapKeyspaceID() || isProtectedKeyspaceID(ksID)) so the protected member
of the default group is never removed.

Signed-off-by: bufferflies <1045931706@qq.com>
@bufferflies
Copy link
Copy Markdown
Contributor Author

Re-reviewed the latest cleanup follow-up on head 14d91a39ab7241d0161f0a698062fe99f3acbe08.

This delta looks clean to me. The failpoint cleanup in TestRemoveKeyspacesFromGroup is now deferred via closures, so the disable calls execute at function exit instead of at defer-registration time.

I do not have a new finding on this delta.

@ti-chi-bot
Copy link
Copy Markdown
Contributor

ti-chi-bot bot commented Apr 7, 2026

@bufferflies: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-error-log-review 14d91a3 link true /test pull-error-log-review

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@ti-chi-bot
Copy link
Copy Markdown
Contributor

ti-chi-bot bot commented Apr 7, 2026

[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.

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 do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. 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.

407ad06f support removing archive and tombstone keyspaces from keyspace group

2 participants