CAMEL-24266: Add volatile to Delayer.delayValue for JMM visibility - #25206
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
gnodet
left a comment
There was a problem hiding this comment.
Review: Looks good ✅
Correct and minimal fix — adding volatile to Delayer.delayValue closes the JMM visibility gap between routing threads (writing in calculateDelay()) and JMX threads (reading via ManagedDelayer.getDelay()). No issues found.
Details
delayValueis alongfield with cross-thread access: written on routing threads incalculateDelay()and read on JMX threads viagetDelayValue(). Withoutvolatile, 32-bit JVMs risk torn reads (JLS 17.7) and all JVMs risk stale reads.- No
AtomicLongneeded since there are no read-modify-write operations. - Performance cost is negligible — volatile loads compile to plain MOV on x86, and the store barrier in
calculateDelay()is on a code path that already blocks or schedules a delayed task. - Verified no other fields in
DelayerorDelayProcessorSupporthave the same cross-thread visibility concern:asyncDelayedandcallerRunsWhenRejectedare set during lifecycle initialization (with happens-before from CamelContext startup);delayedCountis alreadyAtomicInteger. - Clean follow-up to PR #24985 (CAMEL-24227 volatile sweep), which fixed the
delayExpression field but missed the reverse direction (delayValue, routing-to-JMX).
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 547 tested, 29 compile-only — current: 547 all testedMaveniverse Scalpel detected 576 affected modules (current approach: 547).
|
Claude Code on behalf of gnodet
Summary
Delayer.delayValueis a plainlongfield written by routing threads (incalculateDelay()) and read by JMX threads (viaManagedDelayer.getDelay()→getDelayValue()). This creates a JMM visibility gap:longare non-atomic (JLS 17.7), so JMX could observe a torn valueThis was flagged during review of PR #24985 (CAMEL-24227 volatile sweep), which fixed the forward direction (
delayExpression written by JMX, read by routing threads) but missed the reverse direction (delayValuewritten by routing threads, read by JMX).Fix
Add
volatileto thedelayValuefield. On x86 this compiles to the sameMOVinstruction as a plain load, so there is zero performance cost. NoAtomicLongis needed because there are no read-modify-write operations — it's pure store/load.Test plan
DelayerTest,DelayerAsyncDelayedTest,DelayerPerRouteTestpassManagedDelayerTest(JMX MBean that readsdelayValue) passescamel-core-processormodule compiles and formats cleanly🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com