Skip to content

schedule/labeler: index keyspace rules incrementally#11031

Open
rleungx wants to merge 5 commits into
tikv:masterfrom
rleungx:fix-region-label-index
Open

schedule/labeler: index keyspace rules incrementally#11031
rleungx wants to merge 5 commits into
tikv:masterfrom
rleungx:fix-region-label-index

Conversation

@rleungx

@rleungx rleungx commented Jul 20, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: Close #11030

Adding or deleting one canonical keyspace region-label rule rebuilt and sorted
the complete generic range index under the labeler lock. The cost and transient
memory therefore grew with every existing keyspace and was repeated by the
Scheduling Service watcher.

This is the upstream counterpart of tidbcloud/pd-cse#560.

What is changed and how does it work?

  • Recognize only the exact RawKV/Txn keyspace-rule shape generated by
    pkg/keyspace; all other rules retain the generic range-list behavior.
  • Store canonical rules in sparse fixed-size slots with presence bitsets and
    derive their split boundaries on demand.
  • Update one canonical rule in bounded time without traversing or sorting all
    rules, including Plan and watcher paths.
  • Merge canonical and generic split points during lookup while preserving
    RawKV-disabled, RawKV-enabled, generic-rule, and priority semantics.
  • Keep lookups allocation-free and avoid duplicate generic range-list searches.
  • Add edge-case, collision-atomicity, and cross-boundary tests plus 100k/1M
    startup, lock-held update, and lookup benchmarks.
schedule/labeler: index keyspace rules incrementally

Check List

Tests

  • Unit test
  • Integration test
  • Manual scale benchmark

Self-checks:

  • make gotest GOTEST_ARGS='./pkg/schedule/labeler ./pkg/schedule/rangelist ./pkg/mcs/scheduling/server/rule -count=1'
  • go test -race on the changed labeler/rangelist tests
  • make static, followed by final targeted golangci-lint
  • 100k/1M benchmarks: startup 144 ms / 1.70 s, peak RSS 89 MB / 668 MB;
    lock-held update 156 ns / 163 ns and lookup 100 ns / 104 ns, all with 0 B
    and 0 allocations per operation

Code changes

  • No configuration, HTTP API, or persistent-data format changes.

Side effects

  • Adds a specialized in-memory index for deterministic keyspace rules; generic
    user rules continue to use the existing range list.

Related changes

  • Companion fix: tidbcloud/pd-cse#560

Release note

Improve region-label scalability for large keyspace counts by indexing deterministic keyspace rules incrementally.

Summary by CodeRabbit

  • New Features

    • Added deterministic keyspace-based region labeling with consistent results for both raw and transactional modes.
    • Enhanced split-key discovery by merging keyspace and generic range outputs and resolving boundaries strictly within open intervals.
  • Bug Fixes

    • Keyspace rule updates/deletions now update only the relevant deterministic label slots, preventing unintended label/range-list side effects.
    • Improved correctness when combining generic rules with keyspace boundaries, including edge-range handling.
  • Performance

    • Introduced incremental, sparse indexing for generic and keyspace rules to reduce rebuild overhead.
  • Tests

    • Added comprehensive unit tests and benchmarks covering indexing, boundary behavior, legacy compatibility, incremental updates, and sparse reuse.

Signed-off-by: Ryan Leung <rleungx@gmail.com>
@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. dco-signoff: yes Indicates the PR's author has signed the dco. do-not-merge/needs-triage-completed labels Jul 20, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 20, 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 andremouche 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

@ti-chi-bot ti-chi-bot Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jul 20, 2026
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: cf0c7e58-ac87-4b6a-9550-5e2208763ab6

📥 Commits

Reviewing files that changed from the base of the PR and between 120ccd8 and a50a693.

📒 Files selected for processing (3)
  • pkg/schedule/labeler/keyspace_index.go
  • pkg/schedule/labeler/keyspace_index_test.go
  • pkg/schedule/labeler/labeler.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/schedule/labeler/keyspace_index_test.go
  • pkg/schedule/labeler/keyspace_index.go
  • pkg/schedule/labeler/labeler.go

📝 Walkthrough

Walkthrough

RegionLabeler now separates generic and canonical keyspace rules, maintains a sparse deterministic keyspace index, combines both sources during label lookup, and merges their split keys. Tests and benchmarks cover boundaries, updates, compatibility, and performance.

Changes

Keyspace rule indexing

Layer / File(s) Summary
Canonical keyspace index
pkg/schedule/labeler/keyspace_index.go
Adds canonical raw/txn rule validation, sparse storage, deterministic boundaries, coverage queries, and split-key merging.
RegionLabeler index maintenance
pkg/schedule/labeler/labeler.go, pkg/schedule/labeler/plan.go
Separates rule indexes, adds lazy range-list rebuilding, and centralizes mutation handling.
Combined range and keyspace lookup
pkg/schedule/rangelist/range_list.go, pkg/schedule/rangelist/range_list_test.go, pkg/schedule/labeler/labeler.go
Adds range-based data lookup and combines generic and canonical rules for labels and split keys.
Index and update validation
pkg/schedule/labeler/keyspace_index_test.go
Tests indexing, boundaries, sparse storage, compatibility, incremental updates, removals, and benchmarks.

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

Sequence Diagram(s)

sequenceDiagram
  participant RegionLabeler
  participant rangeList
  participant keyspaceRuleIndex
  participant RegionLabel
  RegionLabeler->>rangeList: query generic range data
  RegionLabeler->>keyspaceRuleIndex: query canonical rule and split boundaries
  rangeList-->>RegionLabeler: return generic rules
  keyspaceRuleIndex-->>RegionLabeler: return keyspace rule
  RegionLabeler->>RegionLabel: resolve highest-index labels
Loading

Possibly related issues

  • tikv/pd issue 11030: Covers the incremental keyspace-rule indexing and update behavior implemented in RegionLabeler.

Suggested reviewers: jmpotato

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% 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 clearly matches the main change: incremental keyspace rule indexing under schedule/labeler.
Description check ✅ Passed The PR description covers the problem, change behavior, tests, side effects, and release note, matching the template well.
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.

@rleungx

rleungx commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

/run-check-issue-triage-complete

@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.66879% with 45 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.27%. Comparing base (0b37df9) to head (6596587).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #11031      +/-   ##
==========================================
+ Coverage   79.23%   79.27%   +0.04%     
==========================================
  Files         541      542       +1     
  Lines       76035    76320     +285     
==========================================
+ Hits        60245    60503     +258     
- Misses      11545    11549       +4     
- Partials     4245     4268      +23     
Flag Coverage Δ
unittests 79.27% <85.66%> (+0.04%) ⬆️

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.

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

🧹 Nitpick comments (1)
pkg/schedule/labeler/keyspace_index_test.go (1)

58-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add unit test coverage for slot-collision rejection.

keyspaceRuleIndex.Add returns false when a different rule already occupies a slot (per its doc comment in keyspace_index.go), but no test exercises this path — only the "non-canonical shape" rejection is covered here. A small case (e.g., two distinct canonical rules both computed for the same numeric id) would lock in the two-phase atomicity guarantee.

🤖 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/schedule/labeler/keyspace_index_test.go` around lines 58 - 118, Extend
TestKeyspaceRuleIndex with two distinct canonical rules targeting the same
numeric keyspace ID, then assert the first Add succeeds, the second Add returns
false, and the original rule remains indexed. Verify the rejected Add does not
partially modify the index by checking Contains/GetRule and relevant split-key
behavior.
🤖 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 `@docs/keyspace-region-label-index.md`:
- Around line 33-38: Update the benchmark command sequence in the documentation
to run after make failpoint-enable and establish a cleanup trap that invokes
make failpoint-disable, ensuring cleanup occurs on exit. Keep both existing
benchmark commands unchanged and bracket the full sequence with the required
failpoint lifecycle.

---

Nitpick comments:
In `@pkg/schedule/labeler/keyspace_index_test.go`:
- Around line 58-118: Extend TestKeyspaceRuleIndex with two distinct canonical
rules targeting the same numeric keyspace ID, then assert the first Add
succeeds, the second Add returns false, and the original rule remains indexed.
Verify the rejected Add does not partially modify the index by checking
Contains/GetRule and relevant split-key behavior.
🪄 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: 1898be2b-f010-461a-ac8b-39b5832f688d

📥 Commits

Reviewing files that changed from the base of the PR and between 39b6220 and 08a407b.

📒 Files selected for processing (7)
  • docs/keyspace-region-label-index.md
  • pkg/schedule/labeler/keyspace_index.go
  • pkg/schedule/labeler/keyspace_index_test.go
  • pkg/schedule/labeler/labeler.go
  • pkg/schedule/labeler/plan.go
  • pkg/schedule/rangelist/range_list.go
  • pkg/schedule/rangelist/range_list_test.go

Comment thread docs/keyspace-region-label-index.md Outdated
rleungx added 2 commits July 21, 2026 10:44
Signed-off-by: Ryan Leung <rleungx@gmail.com>
Signed-off-by: Ryan Leung <rleungx@gmail.com>
@rleungx
rleungx requested review from JmPotato and lhy1024 July 22, 2026 04:25
Comment thread pkg/schedule/rangelist/range_list.go Outdated
@rleungx
rleungx requested a review from lhy1024 July 23, 2026 09:24
@rleungx

rleungx commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

/retest

if chunk.count == 0 {
s.chunks[chunkID] = nil
for len(s.chunks) > 0 && s.chunks[len(s.chunks)-1] == nil {
s.chunks = s.chunks[:len(s.chunks)-1]

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.

P2: canonical-rule replacement still regresses for single-slot and high-ID chunks.

When the current rule is the only entry in its chunk, clear drops the chunk and the following set allocates a new roughly 8 KiB keyspaceRuleChunk. For a high ID, this loop also trims every trailing nil directory entry, then set grows the directory again. This is reachable rather than theoretical: NextGen uses SystemKeyspaceID = MaxValidKeyspaceID - 1.

I verified this against the current PR head with a temporary targeted test and benchmark:

  • dense chunk: 99 ns/op, 0 B/op, 0 allocs/op
  • single low ID: 4552 ns/op, 9473 B/op, 1 alloc/op
  • single max ID: 14113 ns/op, 9472 B/op, 1 alloc/op

This contradicts the claimed allocation-free lock-held update path and leaves a sparse high-ID regression uncovered. Please avoid destroying/reallocating the sole chunk during replacement and avoid trimming then regrowing the high-ID directory; add a single-slot/high-ID benchmark or test.

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.

Fixed in a50a693. Canonical replacements now update owned slots in place, preserving the existing chunk and directory for both single-slot and max-ID rules. Added a zero-allocation reuse test for low and max IDs. Verification: full labeler/rangelist package tests passed; single-rule-update/100000 is 79.40 ns/op, 0 B/op, 0 allocs/op.

Signed-off-by: Ryan Leung <rleungx@gmail.com>
@ti-chi-bot

ti-chi-bot Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

@rleungx: 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-unit-test-next-gen-3 a50a693 link true /test pull-unit-test-next-gen-3

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.

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

[scalability] Index keyspace region-label rules incrementally

2 participants