Skip to content

Conversation

@rleungx
Copy link
Member

@rleungx rleungx commented Jan 15, 2026

DO NOT MERGE IT

This PR is used to test the AI's ability.

Summary by CodeRabbit

  • Refactor
    • Optimized internal batch entry handling by removing callback-based processing in favor of direct return values.
    • Improved priority queue implementation with streamlined method signatures for better performance and code maintainability.

✏️ Tip: You can customize this high-level summary in your review settings.

@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 15, 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 lcwangchao 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 dco-signoff: yes Indicates the PR's author has signed the dco. label Jan 15, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

The changes refactor the priority queue's Take method from a callback-based approach to a direct return-based approach, replacing Take(n, callback) with Take(n) []Item. The batch client is updated to use the new API with an explicit guard against empty results.

Changes

Cohort / File(s) Summary
Priority Queue Implementation
internal/client/priority_queue.go
Method signature changed from Take(n int, cb func([]Item)) (callback-based) to Take(n int) []Item (return-based). Returns nil for n <= 0, returns remaining items and resets queue for n >= Len(), returns slice of n items for n < Len(). Removed in-place memory cleanup in Pop.
Priority Queue Tests
internal/client/priority_queue_test.go
Tests refactored to use new return-based Take API. Removed callback collector pattern. Deleted TestPriorityQueueTakeAllLeavesReferencesInBackingArray test. Updated assertions to check returned slice directly.
Batch Processing
internal/client/client_batch.go
Updated to use new return-based Take API. Replaced callback pattern with explicit take-into-local-slice approach. Added guard condition to break loop when empty batch is taken (if len(reqs) == 0).

Sequence Diagram

sequenceDiagram
    participant CB as ClientBatch
    participant PQ as PriorityQueue
    participant Items as Items

    loop Batching Loop
        CB->>PQ: Take(n)
        PQ-->>CB: []Item (reqs)
        alt reqs is empty
            CB-->>CB: break
        else reqs has items
            CB->>Items: build(reqs)
            Items-->>CB: processed
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 The queue once danced with callbacks in hand,
Now returns flow free across the land!
No more callbacks calling—just items returned,
A cleaner path for batches that burned! ✨

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: reverting a previous commit that cleaned references in the priority queue, which aligns with the file modifications across all three changed files.

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

✨ Finishing touches
  • 📝 Generate docstrings

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 Jan 15, 2026
Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/client/priority_queue.go (1)

56-63: Memory leak: removed reference must be cleared.

The Pop method no longer clears the reference to the removed item in the backing array. When a slice is shrunk via old[0:n-1], the element at index n-1 remains in the backing array's capacity and prevents GC from collecting the referenced object.

This is the same issue explicitly documented in client_batch.go (lines 216-219) regarding memdb memory leaks in large transactions.

Proposed fix
 func (ps *prioritySlice) Pop() interface{} {
 	old := *ps
 	n := len(old)
 	item := old[n-1]
+	old[n-1] = nil // avoid memory leak
 	*ps = old[0 : n-1]
 	return item
 }
internal/client/client_batch.go (1)

214-229: Existing comment documents the memory leak being reintroduced.

The comment at lines 216-219 explicitly warns about the memory leak issue with backing array references:

"The data in the cap part of the slice would reference the prewrite keys whose underlying memory is borrowed from memdb. The reference cause GC can't release the memdb, leading to serious memory leak problems in the large transaction case."

This is the exact issue that the reverted PR #1835 was fixing in priority_queue.go. The Take() method now exhibits the same problematic pattern when n >= Len() by using pq.ps[:0] without clearing references.

🤖 Fix all issues with AI agents
In `@internal/client/priority_queue.go`:
- Around line 99-102: The branch that returns all items when n >= pq.Len()
returns pq.ps and then reslices pq.ps to pq.ps[:0] without niling elements,
leaking references; update the code in the block that handles this case (the
return-all branch using pq.ps and pq.Len()) to either copy the returned slice
into a new slice (so you can safely clear/nil the original backing array) or
explicitly nil out each element of pq.ps before reslicing (mirroring the
behavior in reset()), ensuring you clear references on pq.ps after obtaining ret
so GC can reclaim the items.
🧹 Nitpick comments (1)
internal/client/priority_queue_test.go (1)

37-73: Missing test coverage for backing-array reference clearing.

According to the summary, TestPriorityQueueTakeAllLeavesReferencesInBackingArray was removed. This test was verifying that references are properly cleared in the backing array to prevent memory leaks. Without this test, future regressions in reference clearing behavior won't be caught.

Consider adding a test that verifies items can be garbage collected after being taken from the queue.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 847f93b and f0a7459.

📒 Files selected for processing (3)
  • internal/client/client_batch.go
  • internal/client/priority_queue.go
  • internal/client/priority_queue_test.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: race-test
  • GitHub Check: test
  • GitHub Check: integration-local
  • GitHub Check: integration-tikv
  • GitHub Check: integration-raw-tikv (v1ttl)
  • GitHub Check: integration-local-race
  • GitHub Check: integration-next-gen-tikv
  • GitHub Check: integration-raw-tikv (v2)
🔇 Additional comments (3)
internal/client/client_batch.go (1)

188-192: Correct adaptation to the new Take() API.

The two-step pattern (take then check) properly handles the case when the queue is empty or all items are canceled. The len(reqs) == 0 guard prevents calling build with an empty slice.

internal/client/priority_queue_test.go (1)

48-64: Test correctly updated to use the new return-based API.

The test logic remains sound, verifying:

  • Take(1) returns highest priority item
  • Take(2) returns next two in priority order
  • Take(5) when only 2 items remain returns those 2
  • Queue state (length, highest priority) is correctly updated
internal/client/priority_queue.go (1)

94-110: API change is correctly implemented across the codebase.

The signature change from callback-based to return-based is cleaner and correctly implemented. The single caller in internal/client/client_batch.go:188 has been properly updated to use the new return-based API (reqs := b.entries.Take(int(n))), and the subsequent code correctly handles the return value by checking len(reqs) == 0. The n <= 0 returning nil is a reasonable sentinel value, though this edge case is not explicitly tested in the test suite.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 99 to +102
if n >= pq.Len() {
ret := pq.ps
pq.ps = pq.ps[:0]
cb(ret)
for i := range ret {
ret[i] = nil
}
return
return ret
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Memory leak: references not cleared when taking all items.

When n >= pq.Len(), the code returns the slice and resets length to 0 via pq.ps[:0], but the backing array still holds references to all items. This prevents GC from collecting those items.

This is inconsistent with the reset() method (lines 140-145) which correctly nils out all elements before reslicing. The same pattern should be applied here.

Proposed fix
 	if n >= pq.Len() {
 		ret := pq.ps
+		for i := 0; i < len(pq.ps); i++ {
+			pq.ps[i] = nil
+		}
 		pq.ps = pq.ps[:0]
 		return ret
 	}

Note: This requires making a copy of ret before clearing, or clearing after returning a copy:

 	if n >= pq.Len() {
-		ret := pq.ps
-		pq.ps = pq.ps[:0]
-		return ret
+		ret := make([]Item, len(pq.ps))
+		copy(ret, pq.ps)
+		pq.reset()
+		return ret
 	}
📝 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
if n >= pq.Len() {
ret := pq.ps
pq.ps = pq.ps[:0]
cb(ret)
for i := range ret {
ret[i] = nil
}
return
return ret
if n >= pq.Len() {
ret := pq.ps
for i := 0; i < len(pq.ps); i++ {
pq.ps[i] = nil
}
pq.ps = pq.ps[:0]
return ret
}
🤖 Prompt for AI Agents
In `@internal/client/priority_queue.go` around lines 99 - 102, The branch that
returns all items when n >= pq.Len() returns pq.ps and then reslices pq.ps to
pq.ps[:0] without niling elements, leaking references; update the code in the
block that handles this case (the return-all branch using pq.ps and pq.Len()) to
either copy the returned slice into a new slice (so you can safely clear/nil the
original backing array) or explicitly nil out each element of pq.ps before
reslicing (mirroring the behavior in reset()), ensuring you clear references on
pq.ps after obtaining ret so GC can reclaim the items.

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