Skip to content

resource_control: add paging bytes pre-charge in RU calculation#10548

Open
JmPotato wants to merge 2 commits intotikv:masterfrom
JmPotato:demo/ru-paging-size
Open

resource_control: add paging bytes pre-charge in RU calculation#10548
JmPotato wants to merge 2 commits intotikv:masterfrom
JmPotato:demo/ru-paging-size

Conversation

@JmPotato
Copy link
Copy Markdown
Member

@JmPotato JmPotato commented Apr 2, 2026

What problem does this PR solve?

Issue Number: ref pingcap/kvproto#1448

Implement byte-budget RU pre-charge and settlement in the resource controller's KV calculator to support RC paging.

What is changed and how does it work?

Add a two-phase RU charging model for RC paging based on PagingSizeBytes:

Phase 1 (BeforeKVRequest - Pre-charge):

  • For read requests with pagingSizeBytes > 0, pre-charge estimated read RU: RRU += ReadBytesCost × pagingSizeBytes
  • This distributes throttling pressure to Phase 1 instead of concentrating it at Phase 2

Phase 2 (AfterKVRequest - Settlement):

  • Subtract the pre-charged bytes RU: RRU -= ReadBytesCost × pagingSizeBytes
  • Net total = baseCost + actualReadCost + cpuCost (no double-counting)

Changes:

  • RequestInfo interface: add PagingSizeBytes() uint64 method
  • KVCalculator.BeforeKVRequest: pre-charge byte-budget RRU when paging is enabled
  • KVCalculator.AfterKVRequest: subtract pre-charged amount during settlement
  • Unit test covering pre-charge, settlement, total RU verification, and backward compatibility
resource_control: add paging bytes pre-charge in RU calculation

Implement two-phase RU charging for RC paging to mitigate token cliff
effects in concurrent worker scenarios.

Check List

Tests

  • Unit test

Code changes

Side effects

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

Related changes

Release note

None.

Summary by CodeRabbit

  • Tests

    • Added unit test validating Request Rate Unit accounting accuracy in pagination scenarios.
  • Refactor

    • Improved RRU pre-charging mechanism to properly account for per-page byte budgets, preventing double-counting and ensuring precise cost calculation.

JmPotato added 2 commits April 2, 2026 10:18
Add PagingSizeBytes() to RequestInfo interface. When a read request
carries a byte budget (from RC paging), BeforeKVRequest pre-charges
the estimated read RU in Phase 1, and AfterKVRequest subtracts it
in Phase 2 to maintain correct total cost.

This makes concurrent workers throttle at Phase 1 instead of all
hitting Phase 2 simultaneously.

Signed-off-by: JmPotato <github@ipotato.me>
Test that BeforeKVRequest pre-charges pagingSizeBytes * ReadBytesCost,
AfterKVRequest subtracts it, and the net total equals baseCost + actualCost.

Signed-off-by: JmPotato <github@ipotato.me>
@ti-chi-bot ti-chi-bot bot added do-not-merge/needs-linked-issue release-note-none Denotes a PR that doesn't merit a release note. do-not-merge/needs-triage-completed dco-signoff: yes Indicates the PR's author has signed the dco. 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 hundundm 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
Copy Markdown

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

This pull request implements a paging size bytes pre-charge mechanism for KV RRU (Resource Request Unit) accounting. The RequestInfo interface gains a PagingSizeBytes() method, the KVCalculator pre-charges estimated bytes cost during phase 1 and deducts it during phase 2 to prevent double-counting, and supporting test infrastructure is added.

Changes

Cohort / File(s) Summary
Core Logic
client/resource_group/controller/model.go
Added PagingSizeBytes() uint64 method to RequestInfo interface. Updated KVCalculator.BeforeKVRequest to pre-charge ReadBytesCost * PagingSizeBytes for read requests, and AfterKVRequest to subtract the same amount from RRU consumption to prevent double-counting.
Test Infrastructure & Tests
client/resource_group/controller/testutil.go, client/resource_group/controller/group_controller_test.go
Extended TestRequestInfo with pagingSizeBytes field and corresponding accessor method. Added comprehensive unit test TestPagingSizeBytesPreCharge validating pre-charge behavior across phases, including cases with and without paging size bytes set.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

size/M, type/development

Suggested reviewers

  • disksing
  • nolouch
  • rleungx

Poem

🐰 A charge hopped through in two swift phases,
Pre-paid bytes prevent accounting traces,
Phase one advances, phase two retreats,
No double-counting, the ledger's complete! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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
Title check ✅ Passed The title clearly and specifically describes the main change: adding paging bytes pre-charge functionality to the RU calculation in resource control.
Description check ✅ Passed The description includes all required template sections with substantive content: problem statement with issue reference, detailed explanation of changes with technical implementation details, appropriate checklist selections, and release note.

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

@ti-chi-bot ti-chi-bot bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Apr 2, 2026
@ti-chi-bot
Copy link
Copy Markdown
Contributor

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

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

🧹 Nitpick comments (1)
client/resource_group/controller/group_controller_test.go (1)

226-226: Use the defaultAvgBatchProportion constant instead of hardcoding 0.7.

The test is in the same package as config.go where this constant is defined, so it can be referenced directly. This keeps the test aligned with the actual default value and avoids duplication.

♻️ Suggested fix
-	baseCost := float64(cfg.ReadBaseCost) + float64(cfg.ReadPerBatchBaseCost)*0.7
+	baseCost := float64(cfg.ReadBaseCost) + float64(cfg.ReadPerBatchBaseCost)*defaultAvgBatchProportion
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/resource_group/controller/group_controller_test.go` at line 226,
Replace the hardcoded 0.7 used when computing baseCost with the package constant
defaultAvgBatchProportion so the test uses the canonical default; specifically,
update the expression computing baseCost (which uses cfg.ReadBaseCost and
cfg.ReadPerBatchBaseCost) to multiply cfg.ReadPerBatchBaseCost by
defaultAvgBatchProportion instead of 0.7.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@client/resource_group/controller/model.go`:
- Around line 55-57: The new PagingSizeBytes() uint64 method was added to the
RequestInfo interface which will break external implementations; update any
external/custom types that implement RequestInfo (and ensure TestRequestInfo
remains correct) to add a PagingSizeBytes() method returning the intended byte
budget (0 for no pre-charge) or provide a default adapter that satisfies
RequestInfo; locate implementations by searching for RequestInfo,
TestRequestInfo, and any concrete types used where RequestInfo is expected and
add the PagingSizeBytes method with the correct semantics before merging.

---

Nitpick comments:
In `@client/resource_group/controller/group_controller_test.go`:
- Line 226: Replace the hardcoded 0.7 used when computing baseCost with the
package constant defaultAvgBatchProportion so the test uses the canonical
default; specifically, update the expression computing baseCost (which uses
cfg.ReadBaseCost and cfg.ReadPerBatchBaseCost) to multiply
cfg.ReadPerBatchBaseCost by defaultAvgBatchProportion instead of 0.7.
🪄 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: 2cdc3320-aa36-4f9e-b292-00f712694795

📥 Commits

Reviewing files that changed from the base of the PR and between ea48887 and b98ff48.

📒 Files selected for processing (3)
  • client/resource_group/controller/group_controller_test.go
  • client/resource_group/controller/model.go
  • client/resource_group/controller/testutil.go

Comment on lines +55 to +57
// PagingSizeBytes returns the byte budget per page for RC paging.
// 0 means no byte-based pre-charge estimation is applied.
PagingSizeBytes() uint64
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for types that might implement the RequestInfo interface
# by looking for methods like IsWrite() bool which is part of the interface

rg -n --type=go 'func \([^)]+\) IsWrite\(\) bool' -A1 -B2

Repository: tikv/pd

Length of output: 357


🏁 Script executed:

#!/bin/bash
# Find the RequestInfo interface definition
rg -n --type=go 'type RequestInfo interface' -A 20

Repository: tikv/pd

Length of output: 1733


🏁 Script executed:

#!/bin/bash
# Search for all types that implement RequestInfo by looking for struct types with methods
# that match interface signatures (IsWrite, GetWrite, GetRead)
rg -n --type=go 'func \([^)]+\) (IsWrite|GetWrite|GetRead|PagingSizeBytes)\('

Repository: tikv/pd

Length of output: 246


🏁 Script executed:

#!/bin/bash
# Check if TestRequestInfo has PagingSizeBytes method
cat -n client/resource_group/controller/testutil.go | head -100

Repository: tikv/pd

Length of output: 3644


🏁 Script executed:

#!/bin/bash
# Search for all methods that are part of RequestInfo interface
# to identify all types implementing it
rg -n --type=go 'func \([^)]+\) (WriteBytes|ReplicaNumber|StoreID|RequestSize|AccessLocationType|PagingSizeBytes)\(\) ' | grep -v 'interface' | cut -d':' -f1 | sort -u

Repository: tikv/pd

Length of output: 95


🏁 Script executed:

#!/bin/bash
# Look for any new struct types defined that might implement RequestInfo
rg -n --type=go 'type \w+ struct' | head -30

Repository: tikv/pd

Length of output: 2146


🏁 Script executed:

#!/bin/bash
# Check if there are any comments or patterns suggesting external RequestInfo implementations
rg -n --type=go 'RequestInfo' -B2 -A2

Repository: tikv/pd

Length of output: 50363


🏁 Script executed:

#!/bin/bash
# Look more carefully for any type that could implement RequestInfo
# by searching for functions with exact matching signatures
rg -n --type=go 'func \([^)]+\) (IsWrite|WriteBytes|ReplicaNumber|StoreID|RequestSize|AccessLocationType|PagingSizeBytes)\(\)' --no-heading | cut -d':' -f1 | sort | uniq -c

Repository: tikv/pd

Length of output: 103


🏁 Script executed:

#!/bin/bash
# Check if there are any interfaces embedded or other implementations
rg -n --type=go 'RequestInfo' client/resource_group/controller/ | grep -v 'testutil\|model.go' | head -20

Repository: tikv/pd

Length of output: 2392


Interface change is intentionally breaking for external implementations only; internal codebase is properly updated.

Adding PagingSizeBytes() to the RequestInfo interface breaks external code implementing this interface, but the internal test implementation (TestRequestInfo) has already been updated with this method. This appears to be an intentional breaking change based on PR objectives mentioning backward compatibility impacts.

If external consumers (TiDB, TiKV client code) have custom RequestInfo implementations, ensure they are updated to include the PagingSizeBytes() method before merging.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/resource_group/controller/model.go` around lines 55 - 57, The new
PagingSizeBytes() uint64 method was added to the RequestInfo interface which
will break external implementations; update any external/custom types that
implement RequestInfo (and ensure TestRequestInfo remains correct) to add a
PagingSizeBytes() method returning the intended byte budget (0 for no
pre-charge) or provide a default adapter that satisfies RequestInfo; locate
implementations by searching for RequestInfo, TestRequestInfo, and any concrete
types used where RequestInfo is expected and add the PagingSizeBytes method with
the correct semantics before merging.

@ti-chi-bot
Copy link
Copy Markdown
Contributor

ti-chi-bot bot commented Apr 2, 2026

@JmPotato: 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-2 b98ff48 link true /test pull-unit-test-next-gen-2

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.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.96%. Comparing base (3eb99ae) to head (b98ff48).
⚠️ Report is 9 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10548      +/-   ##
==========================================
+ Coverage   78.88%   78.96%   +0.08%     
==========================================
  Files         530      532       +2     
  Lines       71548    71808     +260     
==========================================
+ Hits        56439    56705     +266     
+ Misses      11092    11074      -18     
- Partials     4017     4029      +12     
Flag Coverage Δ
unittests 78.96% <100.00%> (+0.08%) ⬆️

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 do-not-merge/needs-triage-completed release-note-none Denotes a PR that doesn't merit a release note. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant