Skip to content

client/resource_group: settle write consumption at response time - #10986

Open
YuhaoZhang00 wants to merge 5 commits into
tikv:masterfrom
YuhaoZhang00:fix/failed-write-consumption-report
Open

client/resource_group: settle write consumption at response time#10986
YuhaoZhang00 wants to merge 5 commits into
tikv:masterfrom
YuhaoZhang00:fix/failed-write-consumption-report

Conversation

@YuhaoZhang00

@YuhaoZhang00 YuhaoZhang00 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: Close #10985

OnRequestWait must reserve the full write cost before sending a KV RPC so the local limiter can enforce admission control. The same reservation was also entering cumulative reported consumption immediately, which coupled token reservation with settled consumption. Successful write WRU could be reported before the response, and any existing failed-write payback that crossed a periodic reporting boundary could not correct the already reported positive delta because consumption reporting is monotonic.

What is changed and how does it work?

This PR keeps request-time write token reservation unchanged but removes the write reservation from request-side reported consumption. The response-side reporting helper restores the reservation unconditionally, so the reservation and the existing response delta settle together in one reporting interval. Successful writes report their full reservation at response settlement; when the controller receives a failed response, its existing payback is combined with the reservation before reporting instead of depending on a later negative correction.

The reporting split no longer depends on ResponseInfo.Succeed() to decide whether to restore the reservation. Determining success in client-go and handling requests with no response are explicitly outside this PR scope. Because the same settled-consumption counter also feeds the controller average RU observation and reporting threshold, write consumption becomes visible to those paths at response settlement as well; request-time admission remains protected by the unchanged local limiter reservation.

client/resource_group: settle write consumption at response time

Keep request-time token reservation for write admission control, but move reported write consumption to response settlement so the reservation and response delta are accounted in the same reporting interval.

Check List

Tests

  • Unit test

Code changes

  • None

Side effects

  • Successful write WRU is reported at response settlement instead of request time.
  • Request-time local limiter reservation is unchanged.
  • client-go success detection and no-response behavior are unchanged.

Related changes

  • Need to cherry-pick to the release branch

Release note

Report resource group write consumption at response settlement while preserving request-time token reservation.

Summary by CodeRabbit

  • Bug Fixes
    • Corrected write resource consumption reporting so reserved write units/bytes are recorded when a response is received, not at reservation time.
    • Prevented write usage from showing up in interim request reports until success.
    • Improved accuracy of consumption reporting for unsuccessful responses while preserving existing request details.
  • Tests
    • Added unit coverage to verify write consumption settlement timing and correct handling across success and failure scenarios.
  • Performance
    • Reduced allocations during reporting by reusing caller-provided buffers (validated via allocation-focused tests/benchmarks).

Signed-off-by: Yuhao Zhang <yhzhang00@outlook.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 8, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 8, 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 contribution This PR is from a community contributor. needs-ok-to-test Indicates a PR created by contributors and need ORG member send '/ok-to-test' to start testing. labels Jul 8, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Hi @YuhaoZhang00. Thanks for your PR.

I'm waiting for a tikv member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

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 the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jul 8, 2026
@coderabbitai

coderabbitai Bot commented Jul 8, 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
📝 Walkthrough

Walkthrough

Write WRU and WriteBytes reporting now excludes reservations during the request phase and adds them during response processing. Unit and controller tests verify successful settlement, failed-response deltas, and delayed periodic reporting.

Changes

Write consumption accounting

Layer / File(s) Summary
Reported consumption accounting
client/resource_group/controller/model.go, client/resource_group/controller/model_test.go
Adds write reservation consumption calculation, subtracts reservations from request reports, adds them to response reports, uses caller-provided buffers, and tests settlement and allocation behavior.
Controller response settlement
client/resource_group/controller/group_controller.go, client/resource_group/controller/group_controller_test.go
Passes reported consumption buffers through request and response paths and verifies that reserved WRU and WriteBytes appear in periodic reporting after a successful response.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • tikv/pd#10611: Updates the same request/response consumption accounting pipeline for related resource-group metering behavior.

Suggested labels: type/development

Suggested reviewers: jmpotato

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: moving write consumption settlement to response time.
Description check ✅ Passed The description matches the template with issue number, change summary, checklist items, and release note.
Linked Issues check ✅ Passed The code changes match #10985 by keeping request-time reservation while settling write consumption in response reporting.
Out of Scope Changes check ✅ Passed The changes appear focused on controller-side reporting and related tests/benchmarks, with no clear unrelated scope creep.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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.

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.18%. Comparing base (aa5a988) to head (ebe73aa).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #10986      +/-   ##
==========================================
- Coverage   79.21%   79.18%   -0.04%     
==========================================
  Files         541      541              
  Lines       75677    75726      +49     
==========================================
+ Hits        59949    59960      +11     
- Misses      11491    11524      +33     
- Partials     4237     4242       +5     
Flag Coverage Δ
unittests 79.18% <90.90%> (-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.

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

196-224: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated calculator-loop between reservation and refund helpers.

writeReservationConsumption and writeRefundConsumption are structurally identical except for the KVCalculator method invoked. Consider extracting the common loop/type-assertion into a small helper parameterized by the calculator method to reduce duplication.

♻️ Example refactor
+func applyWriteAdjustment(calculators []ResourceCalculator, req RequestInfo, fn func(*KVCalculator, *rmpb.Consumption, RequestInfo)) *rmpb.Consumption {
+	adjustment := &rmpb.Consumption{}
+	if !req.IsWrite() {
+		return adjustment
+	}
+	for _, calc := range calculators {
+		if kvCalc, ok := calc.(*KVCalculator); ok {
+			fn(kvCalc, adjustment, req)
+		}
+	}
+	return adjustment
+}
+
-func writeReservationConsumption(calculators []ResourceCalculator, req RequestInfo) *rmpb.Consumption {
-	reservation := &rmpb.Consumption{}
-	if !req.IsWrite() {
-		return reservation
-	}
-	for _, calc := range calculators {
-		kvCalc, ok := calc.(*KVCalculator)
-		if !ok {
-			continue
-		}
-		kvCalc.calculateWriteCost(reservation, req)
-	}
-	return reservation
-}
-
-func writeRefundConsumption(calculators []ResourceCalculator, req RequestInfo) *rmpb.Consumption {
-	refund := &rmpb.Consumption{}
-	if !req.IsWrite() {
-		return refund
-	}
-	for _, calc := range calculators {
-		kvCalc, ok := calc.(*KVCalculator)
-		if !ok {
-			continue
-		}
-		kvCalc.payBackWriteCost(refund, req)
-	}
-	return refund
-}
+func writeReservationConsumption(calculators []ResourceCalculator, req RequestInfo) *rmpb.Consumption {
+	return applyWriteAdjustment(calculators, req, (*KVCalculator).calculateWriteCost)
+}
+
+func writeRefundConsumption(calculators []ResourceCalculator, req RequestInfo) *rmpb.Consumption {
+	return applyWriteAdjustment(calculators, req, (*KVCalculator).payBackWriteCost)
+}
🤖 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/resource_group/controller/model.go` around lines 196 - 224, Both
writeReservationConsumption and writeRefundConsumption duplicate the same
ResourceCalculator loop and KVCalculator type assertion, differing only in the
method invoked. Extract the shared iteration and type-checking logic in model.go
into a small helper around KVCalculator, then have writeReservationConsumption
call the helper with calculateWriteCost and writeRefundConsumption call it with
payBackWriteCost to remove duplication while preserving 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.

Nitpick comments:
In `@client/resource_group/controller/model.go`:
- Around line 196-224: Both writeReservationConsumption and
writeRefundConsumption duplicate the same ResourceCalculator loop and
KVCalculator type assertion, differing only in the method invoked. Extract the
shared iteration and type-checking logic in model.go into a small helper around
KVCalculator, then have writeReservationConsumption call the helper with
calculateWriteCost and writeRefundConsumption call it with payBackWriteCost to
remove duplication while preserving behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a7b296f1-4dfd-49df-8bd0-9233fbce3586

📥 Commits

Reviewing files that changed from the base of the PR and between b9b3eed and ebe73aa.

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

Signed-off-by: Yuhao Zhang <yhzhang00@outlook.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/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jul 8, 2026
Signed-off-by: Yuhao Zhang <yhzhang00@outlook.com>
@YuhaoZhang00

YuhaoZhang00 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Conflict-resolution note:

Expected conflicts after rebasing this PR on top of #10611:

  • client/resource_group/controller/model.go
  • client/resource_group/controller/group_controller.go
  • client/resource_group/controller/group_controller_test.go
  • client/resource_group/controller/limiter.go

Resolve them by keeping both semantics:

  • model.go: keep both paging pre-charge reporting helpers and write reservation/refund reporting helpers. Request-side reporting should exclude both synthetic paging pre-charge and write reservation. Response-side reporting should restore actual paging read usage, report write reservation only on successful writes, and exclude failed-write payback/refund from actual consumption.
  • group_controller.go: keep paging metrics/counting from client/resource_group: add RC paging pre-charge with PredictedReadBytes hint #10611 and failed-write limiter refund from this PR. A negative response-side delta should refund the local limiter for both paging over-estimates and failed-write payback.
  • group_controller_test.go: keep both paging tests and failed-write tests. Update/remove client/resource_group: add RC paging pre-charge with PredictedReadBytes hint #10611 split-boundary assertions that expected failed writes not to refund; after this PR, failed writes should refund through the bugfix path.
  • limiter.go: comment-only conflict around RefundTokens; keep the fuller comment explaining why maybeNotify is not called.

After resolving, rerun the targeted client/resource_group/controller tests for paging pre-charge/refund and failed-write reservation/refund.

Merge the current upstream master and keep request-time write admission reservation separate from reported consumption. Restore the reservation in the response-side settlement delta without branching on response success.

Signed-off-by: Yuhao Zhang <yhzhang00@outlook.com>
@ti-chi-bot ti-chi-bot Bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed do-not-merge/needs-triage-completed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jul 22, 2026
@YuhaoZhang00 YuhaoZhang00 changed the title client/resource_group: delay reporting write reservation client/resource_group: settle write consumption at response time Jul 22, 2026
Signed-off-by: Yuhao Zhang <yhzhang00@outlook.com>

@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

🤖 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/resource_group/controller/group_controller.go`:
- Around line 689-690: The response settlement logic around reportedDelta in
both client/resource_group/controller/group_controller.go lines 689-690 and
727-728 must refund every negative delta, including failed-write paybacks,
rather than restricting RefundTokens to paging reads. Update both response paths
consistently while preserving the existing paging overestimate refund 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 Plus

Run ID: 27e0b2ac-4fd1-45db-a1c9-30ccc275e089

📥 Commits

Reviewing files that changed from the base of the PR and between 81d054a and 8d75e68.

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

Comment on lines +689 to +690
var reported rmpb.Consumption
reportedDelta := reportedResponseConsumption(gc.calculators, req, delta, &reported)

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

Refund every negative settlement delta, not only paging deltas. Failed writes reserve tokens in onRequestWaitImpl, then AfterKVRequest applies negative write payback. Both response paths currently skip RefundTokens unless the request is a paging read.

  • client/resource_group/controller/group_controller.go#L689-L690: refund negative failed-write deltas in addition to paging overestimates.
  • client/resource_group/controller/group_controller.go#L727-L728: apply the same refund behavior in the response-wait path.
Proposed fix
- } else if v < 0 && isPagingRead && bytesForEst > 0 {
+ } else if v < 0 {
    counter.limiter.RefundTokens(time.Now(), -v)
  }
📝 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
var reported rmpb.Consumption
reportedDelta := reportedResponseConsumption(gc.calculators, req, delta, &reported)
} else if v < 0 {
counter.limiter.RefundTokens(time.Now(), -v)
}
📍 Affects 1 file
  • client/resource_group/controller/group_controller.go#L689-L690 (this comment)
  • client/resource_group/controller/group_controller.go#L727-L728
🤖 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/resource_group/controller/group_controller.go` around lines 689 - 690,
The response settlement logic around reportedDelta in both
client/resource_group/controller/group_controller.go lines 689-690 and 727-728
must refund every negative delta, including failed-write paybacks, rather than
restricting RefundTokens to paging reads. Update both response paths
consistently while preserving the existing paging overestimate refund behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution This PR is from a community contributor. dco-signoff: yes Indicates the PR's author has signed the dco. needs-ok-to-test Indicates a PR created by contributors and need ORG member send '/ok-to-test' to start testing. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

client/resource_group: settle reported write consumption at response time

1 participant