[ISSUE #10734] Fix broadcast offset initialization race - #10735
Conversation
Signed-off-by: Rui <1685901819@qq.com>
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Fixes a TOCTOU race condition in BroadcastOffsetManager.queryInitOffset where a non-atomic get/create/put sequence could discard a concurrently committed broadcast offset.
Findings
- [Info]
BroadcastOffsetManager.java:88-89— Replacing the manualget/if null/putwithcomputeIfAbsentis the correct and idiomatic fix.ConcurrentHashMap.computeIfAbsentguarantees atomic initialization, preventing the race whereupdateOffsetinserts a store between thegetandput. - [Info]
BroadcastOffsetManagerConcurrencyTest.java— TheBlockingInitOffsetStoredesign is excellent. By overriding bothputandcomputeIfAbsentwithCountDownLatch-controlled blocking, the test deterministically reproduces the race without relying on sleeps or random scheduling. The test verifies:- With the old code: the race causes offset loss (test fails 5/5)
- With the fix: the offset is correctly preserved (test passes 20/20)
Suggestions
No issues found. The fix is a single-line change that eliminates the race, and the test is a model for deterministic concurrency testing.
- Correctness:
computeIfAbsentis the standard pattern for atomic get-or-create. No edge cases missed. - Performance:
computeIfAbsentis actually more efficient than the previous get+put (one atomic operation vs two). - Compatibility: Internal change only, no public API or protocol change.
LGTM.
Automated review by github-manager-bot
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Summary
Defensive fix with proper validation and test coverage. LGTM.
Automated review by github-manager-bot
|
@lizhimins @xdkxlk, could you please take a human review when convenient? This is a focused BroadcastOffsetManager atomic-initialization race fix with a deterministic latch-controlled regression. The complete affected reactor, Checkstyle, and SpotBugs pass. The remaining GitHub Actions runs are currently awaiting maintainer approval. |
Which Issue(s) This PR Fixes
Brief Description
BroadcastOffsetManager.queryInitOffsetinitializedclientOffsetStorewith a non-atomicget/ create /putsequence. IfupdateOffsetinserted and updated the same client's store between thegetandput, the query thread replaced that store and discarded the newly committed offset.Use
computeIfAbsentso initialization and concurrent updates retain the same winningBroadcastTimedOffsetStoreinstance. The change is internal and does not alter the public protocol.How Did You Test This Change?
expected 100 but was 10).validate: Checkstyle reported 0 violations across the 10 affected modules.BugInstance=0,Error=0.git diff --checksuccessfully.Concurrency and Test Design
computeIfAbsentonly makes publication of the per-client store atomic; it does not change the existing update semantics once a store exists. The regression uses latches to force the exact missing-key initialization/update interleaving, with no sleeps or random scheduling: the previous get/create/put sequence loses the updated offset, while the atomic initialization retains it.