maintainer: replay deferred WAITING barrier statuses after dispatcher enters replicating#4808
maintainer: replay deferred WAITING barrier statuses after dispatcher enters replicating#4808zier-one wants to merge 1 commit intopingcap:masterfrom
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
📝 WalkthroughWalkthroughThis PR introduces a deferred status mechanism for dispatchers not yet replicating. Block status reports arriving while a dispatcher is in non-replicating state with WAITING stage status are buffered and replayed once replication begins, improving consistency in barrier event handling. Changes
Sequence DiagramsequenceDiagram
participant Disp as Dispatcher<br/>(Not Replicating)
participant Barrier as Barrier
participant PendingMap as Pending Status<br/>Map
participant Handler as Status Handler
Disp->>Barrier: TableSpanBlockStatus<br/>(WAITING stage)
Barrier->>Barrier: Check: dispatcher<br/>not replicating?
alt Dispatcher Not Replicating
Barrier->>PendingMap: upsert(status)
PendingMap-->>Barrier: stored
Barrier->>Barrier: Skip normal<br/>handling
else Dispatcher Replicating
Barrier->>Handler: handleOneStatus()
Handler-->>Barrier: ACK + WRITE actions
end
Disp->>Barrier: Replication starts
Barrier->>Barrier: Resend()
Barrier->>PendingMap: snapshot()
PendingMap-->>Barrier: deferred statuses
loop For each deferred status
Barrier->>Barrier: dispatcherAlreadyPassedPendingState?
alt Not passed
Barrier->>Handler: handleOneStatus()
Handler-->>Barrier: ACK + WRITE actions
Barrier->>PendingMap: delete(status)
else Already passed
Barrier->>PendingMap: delete(status)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
Hi @zier-one. Thanks for your PR. I'm waiting for a pingcap member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions 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. |
|
Welcome @zier-one! |
There was a problem hiding this comment.
Code Review
This pull request introduces a mechanism to defer block statuses from dispatchers that are not yet in the replicating state. It adds a pendingUnreplicatingStatusMap to the Barrier struct to track these statuses and replays them during the Resend cycle once the dispatcher enters the replicating state. The changes also include refactoring handleOneStatus to use common types and extracting barrier check logic into a reusable replicationPassedBarrier function. Feedback was provided regarding a potential misleading warning log that may trigger when statuses are deferred instead of processed immediately.
| if b.tryDeferUnreplicatingWaitingStatus(from, cfID, dispatcherID, status) { | ||
| continue | ||
| } |
There was a problem hiding this comment.
The deferral logic introduced here will cause the warning no dispatcher status to send (located around line 129 in the full file) to trigger even when statuses are correctly deferred. This could lead to misleading logs and noise in production. Consider tracking the number of deferred statuses in this loop and suppressing that warning if any statuses were deferred.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
maintainer/barrier_helper.go (1)
157-172: Consider pre-allocating slice capacity insnapshot().The slice is created with zero capacity, but the total count is known after iterating. This is a minor optimization opportunity.
♻️ Optional: Pre-allocate with estimated capacity
func (m *pendingUnreplicatingStatusMap) snapshot() []pendingUnreplicatingStatusEntry { m.mutex.Lock() defer m.mutex.Unlock() - entries := make([]pendingUnreplicatingStatusEntry, 0) + // Estimate total entries for pre-allocation + total := 0 + for _, statuses := range m.byDispatcher { + total += len(statuses) + } + entries := make([]pendingUnreplicatingStatusEntry, 0, total) for dispatcherID, statuses := range m.byDispatcher { for key, value := range statuses {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@maintainer/barrier_helper.go` around lines 157 - 172, In pendingUnreplicatingStatusMap.snapshot(), avoid starting entries with zero capacity; first compute total := sum of len(statuses) for each statuses in m.byDispatcher, then allocate entries := make([]pendingUnreplicatingStatusEntry, 0, total) before the nested loops; keep the rest of the loop appending to entries and return entries—this preserves behavior but reduces reallocations when building the slice.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@maintainer/barrier_helper.go`:
- Around line 157-172: In pendingUnreplicatingStatusMap.snapshot(), avoid
starting entries with zero capacity; first compute total := sum of len(statuses)
for each statuses in m.byDispatcher, then allocate entries :=
make([]pendingUnreplicatingStatusEntry, 0, total) before the nested loops; keep
the rest of the loop appending to entries and return entries—this preserves
behavior but reduces reallocations when building the slice.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b30f1629-d57b-4da7-bd1d-169dc2193eea
📒 Files selected for processing (4)
maintainer/barrier.gomaintainer/barrier_event.gomaintainer/barrier_helper.gomaintainer/barrier_test.go
|
/ok-to-test |
|
If there are lots of barrier events, does this change cause OOM? |
What problem does this PR solve?
Issue Number: close #4810
This PR fixes a timing window in the maintainer barrier flow. Before this change, when a non-DDL dispatcher reported a
WAITINGblock status before the maintainer had moved it fromschedulingtoreplicating, the status was ignored immediately. As a result, the barrier could not advance on the first report and had to wait for the dispatcher's local fixed5sresend task.This change stores such deferred
WAITINGstatuses inside the maintainer and replays them through the existing barrier state machine after the dispatcher actually becomesreplicating, so barrier progress no longer depends on the dispatcher's local5sresend as the primary recovery path.What is changed and how it works?
This PR applies to barrier scenarios where a non-DDL dispatcher can observe a barrier before it is officially moved into the
replicatingset, especially:CREATE TABLE ... LIKE ...that bring referenced-table dispatchers into the same barrier;WAITINGreport can land in thescheduling -> replicatingtransition window.Before:
WAITINGreport could be ignored if it arrived during the non-replicating window;5sresend task;After:
WAITINGstatuses instead of dropping them;replicating, the maintainer actively replays the cached status in periodicBarrier.Resend();5sresend as the primary compensation path.Check List
Tests
[x] Unit test
Added coverage for:
TestDeferUnreplicatingWaitingStatusTestResendReplaysDeferredWaitingStatusAfterDispatcherReplicatingTestResendDropsDeferredWaitingStatusWhenDispatcherMissingTestResendDropsDeferredWaitingStatusWhenDispatcherAlreadyPassedTestResendDropsDeferredWaitingStatusWhenDispatcherMovedAlso re-ran the nearby barrier scheduling regression:
TestDeferAllDBBlockEventFromDDLDispatcherWhilePendingScheduleSummary by CodeRabbit
Bug Fixes
Tests
Release note