Skip to content

client/resource_group: delay reporting write reservation#10986

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

client/resource_group: delay reporting write reservation#10986
YuhaoZhang00 wants to merge 3 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

Failed write requests can leave two related accounting artifacts behind:

  • If a periodic consumption report is sent after the client records the write reservation but before the failed response pays it back, PD can over-count WRU. The local payback can make the client-side delta negative, but actual consumption reports only send positive monotonic deltas, so the earlier reservation is not corrected on the PD side.
  • The response-side failed-write payback delta is also ignored by the local limiter path, so the local token balance can remain over-debited by that payback amount.

What is changed and how does it work?

This PR keeps using the full write reservation for token acquisition, but delays reporting the write reservation as actual consumption until the response confirms success. For failed writes, the response-side payback is removed from the reported actual consumption path so it does not become negative reported usage.

This PR also refunds the failed-write response-side payback delta to the local limiter. The limiter refund primitive is covered directly, and read requests skip the write-only helper path without allocating an empty consumption object.

client/resource_group: delay reporting write reservation

Report write reservations as actual consumption only after the write response succeeds. This prevents failed writes that cross a reporting boundary from leaving WRU over-counted in PD, while preserving request-time token reservation and refunding the response-side failed-write payback locally.

Check List

Tests

  • Unit test

Code changes

  • None

Side effects

  • None

Related changes

  • Need to cherry-pick to the release branch

Release note

Fix an issue that failed write requests could be over-counted in resource group WRU usage or leave the response-side write payback unapplied locally when they crossed a reporting boundary.

Summary by CodeRabbit

  • New Features

    • Improved request accounting for write operations so reported consumption better reflects reservations and refunds.
    • Added token refund support in limiter behavior, including handling for failed writes.
  • Bug Fixes

    • Fixed failed write requests so reserved tokens are returned correctly.
    • Prevented refunded write usage from being counted as negative reported consumption.
  • Tests

    • Added coverage for failed write reporting, token refunds, and non-write request handling.

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3a3a9bed-a093-40db-85fe-64f99e7cdba7

📥 Commits

Reviewing files that changed from the base of the PR and between 93e0042 and fda5879.

📒 Files selected for processing (2)
  • client/resource_group/controller/group_controller.go
  • client/resource_group/controller/group_controller_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • client/resource_group/controller/group_controller_test.go
  • client/resource_group/controller/group_controller.go

📝 Walkthrough

Walkthrough

This PR updates failed-write WRU accounting so controller reporting uses reported consumption views, and local limiter state can refund write reservations when a write response fails.

Changes

Failed write WRU accounting

Layer / File(s) Summary
Reported consumption helpers
client/resource_group/controller/model.go, client/resource_group/controller/model_test.go
Adds cloning and write-only reservation/refund helpers, plus reported request/response consumption views and a test that non-write requests skip them.
Limiter refund support
client/resource_group/controller/limiter.go, client/resource_group/controller/limiter_test.go
Adds Limiter.RefundTokens and tests its token, burst, and no-op behavior.
Controller reporting and refunds
client/resource_group/controller/group_controller.go, client/resource_group/controller/group_controller_test.go
Routes request/response accounting through reported consumption, refunds local write reservations on failed writes, and adds controller tests for the failed-write paths.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant groupCostController
  participant model as model.go helpers
  participant Limiter
  participant gc_mu as gc.mu.consumption

  Client->>groupCostController: onRequestWaitImpl
  groupCostController->>model: reportedRequestConsumption(tokenDelta, req)
  model-->>groupCostController: reportedDelta
  groupCostController->>gc_mu: record reportedDelta
  groupCostController->>Limiter: reserve write tokens

  Client->>groupCostController: onResponseImpl / onResponseWaitImpl
  groupCostController->>model: reportedResponseConsumption(tokenDelta, req, resp)
  model-->>groupCostController: reportedDelta
  groupCostController->>gc_mu: record reportedDelta
  alt write failed
    groupCostController->>Limiter: RefundTokens(now, refundAmount)
  else write succeeded
    groupCostController->>Limiter: remove or acquire tokens
  end
Loading

Suggested labels: type/development, lgtm

Suggested reviewers: JmPotato, rleungx, disksing

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main change: delaying write reservation reporting.
Description check ✅ Passed The description follows the template with issue number, change summary, tests, side effects, related changes, and release note.
Linked Issues check ✅ Passed The changes satisfy #10985 by delaying WRU reporting until success and refunding failed-write payback to the local limiter.
Out of Scope Changes check ✅ Passed The added controller, limiter, and test changes all support the write-reservation reporting fix and appear in scope.
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.

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. do-not-merge/needs-triage-completed 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/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.

client/resource_group: failed writes can over-count WRU

1 participant