[ISSUE #10464] Avoid unnecessary allocation in Message.getProperty and NFE in getPriority#10468
[ISSUE #10464] Avoid unnecessary allocation in Message.getProperty and NFE in getPriority#10468wang-jiahua wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Reduces side effects when reading message properties and makes priority parsing more explicit when the stored value is missing/empty.
Changes:
- Stop initializing
propertieson read ingetProperty(...)(returnnullwhenpropertiesis absent). - Add explicit null/empty handling when parsing priority in
getPriority().
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
oss-sentinel-ai
left a comment
There was a problem hiding this comment.
Review: Approved ✅
PR: #10468 — Avoid unnecessary allocation in Message.getProperty and NFE in getPriority
Type: Performance (1 file, +6/-3)
Assessment
Fixes two per-message allocation issues:
- getProperty() returns null immediately when properties is null (no HashMap creation)
- getPriority() adds null/empty fast-path (eliminates ~16,000 NFE/min)
Verdict
✅ Clean performance fix based on JFR profiling. Fixes #10464.
🤖 Automated review by oss-sentinel-ai
64ab982 to
35ebfd6
Compare
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Performance optimization in Message.java: eliminates unnecessary HashMap allocation in getProperty() and avoids NumberFormatException throw+catch in getPriority() when priority is unset.
Findings
- [Info]
getProperty()— Removing the side-effect (creatingHashMapon read) is correct. A getter should not mutate state. The Javadoc addition clearly documents the new contract. - [Info]
getPriority()— The null/empty fast-path beforeNumberUtils.toInt()is a clean fix. Under high throughput this avoids significant NFE overhead (~16k/min as noted). - [Info] Compatibility — The author verified no callers depend on the
HashMapcreation side-effect. This is safe.
Suggestions
- Consider adding a unit test for
getProperty()whenproperties == nullto prevent regression of the side-effect behavior. - Consider a microbenchmark (JMH) for
getPriority()to quantify the NFE avoidance improvement.
Overall: Clean, well-documented performance fix. LGTM.
Automated review by github-manager-bot
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot ✅ Approved
PR #10468: [ISSUE #10464] Avoid unnecessary allocation in Message.getProperty and NFE in getPriority
Summary
Two per-message allocation/CPU fixes in Message.java:
getProperty()no longer creates anew HashMap<>()as a side-effect whenproperties == null— a read-only method should not mutate state.getPriority()adds a null/empty fast-path beforeNumberUtils.toInt(), avoiding aNumberFormatExceptionthrow+catch cycle (~16K NFE/min under benchmark load).
Analysis
| Dimension | Assessment |
|---|---|
| Correctness | ✅ Both changes preserve existing behavior for all valid inputs. The getProperty() side-effect removal is safe — no callers rely on it (verified by author). |
| Performance | ✅ Eliminates unnecessary HashMap allocation on null-properties reads and avoids exception throw/catch overhead on every getPriority() call when priority is unset (majority of messages). |
| Tests | ✅ Existing unit tests pass. |
| Compatibility | ✅ No public API changes. The getProperty() behavior change (no side-effect) is safe — hasProperty() already handles null, and all write paths go through putProperty(). |
The Javadoc addition clearly documents the read-only contract. Well-written PR description with thorough compatibility analysis.
Verdict: Clean, safe optimization. Approved.
35ebfd6 to
fbca25a
Compare
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Two per-message allocation/CPU fixes in Message.java: (1) getProperty no longer lazily initializes the properties map on a read-only call, and (2) getPriority adds a null/empty fast-path to avoid NumberFormatException from NumberUtils.toInt(null).
Findings
- [Critical → Fixed] The original
getPropertysilently mutated state on a read — this was a genuine bug that could cause unexpectedHashMapallocations and side-effects in concurrent scenarios. The fix (returnnullwhenproperties == null) is correct. - [Warning] The behavioral change in
getPropertyis subtle: callers that previously relied on the lazy-init side-effect (callinggetPropertythenputPropertyexpecting the map to exist) would now need to callputPropertyfirst. However,putPropertyalready handles null → new HashMap internally, so this should be safe. - [Info] The
getPriorityfast-path avoids theInteger.parseInt(null)→ catch → default fallback, which is both faster and cleaner. - [Info] Excellent Javadoc on
getPropertyclarifying the read-only contract.
Suggestions
- Consider adding a regression test: call
getProperty("any")on aMessagewith null properties, verify it returns null andpropertiesfield remains null.
No blocking issues. Well-scoped fix with clear correctness improvement.
Automated review by github-manager-bot
…rty and NFE in getPriority - getProperty(): return null when properties map is uninitialized instead of creating an empty HashMap as a side-effect of a read-only call. - getPriority(): add null/empty fast-path before NumberUtils.toInt() to skip the NFE throw+catch when PRIORITY is unset (the common case). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fbca25a to
c92830e
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #10468 +/- ##
=============================================
- Coverage 48.19% 48.10% -0.09%
+ Complexity 13394 13371 -23
=============================================
Files 1377 1377
Lines 100730 100737 +7
Branches 13012 13015 +3
=============================================
- Hits 48542 48461 -81
- Misses 46254 46324 +70
- Partials 5934 5952 +18 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot (re-review)
Summary
Re-review after new commit c92830e: Avoid unnecessary allocation in Message.getProperty and add null-safe putAll in reviveRetry.
Changes Since Last Review
The new commit adds defensive null-checks before putAll() on messageExt.getProperties() in two locations:
PopConsumerService.reviveRetry()(line ~707)PopReviveService.reviveRetry()(line ~130)
Both now extract sourceProperties into a local variable and guard with if (sourceProperties != null) before calling putAll().
Findings
- [Positive] The null-checks are a good defensive fix. If
getProperties()ever returnsnull(e.g., during deserialization edge cases), the old code would throwNullPointerException. This is especially relevant in the revive/retry path where message state may be inconsistent. - [Positive] The
Message.getProperty()lazy-init behavior from the original PR remains clean — the Javadoc clearly documents the read-only, no-init semantics. - [Info] The null-check pattern is applied in both
PopConsumerServiceandPopReviveServiceconsistently. Consider adding a unit test for thesourceProperties == nullpath to prevent regression.
Verdict
The new commit strengthens the robustness of the revive/retry path. No remaining concerns.
Automated re-review by github-manager-bot
Which Issue(s) This PR Fixes
Fixes #10464
Brief Description
Two per-message allocation/CPU fixes in
Message.java:getProperty(String): whenproperties == null, returnsnullimmediately instead of creating anew HashMap<>()as a side-effect of a read-only call.getPriority(): adds a null/empty fast-path before delegating toNumberUtils.toInt(). Previously,NumberUtils.toInt(null, -1)internally calledInteger.parseInt(null)which throws and catches aNumberFormatExceptionon every invocation (~16,000 NFE/min under benchmark load). The fast-path skips this throw+catch whenPRIORITYis unset (the vast majority of messages).Compatibility
getProperty()no longer creates an empty HashMap as a side-effect. Callers that relied on this side-effect to laterputdirectly intoproperties(without going throughputProperty()) would break — but no such callers exist in the codebase (verified by grep).getPriority()return values are unchanged for all inputs.How Did You Test This Change
mvn -pl common -Dcheckstyle.skip=false -Dspotbugs.skip=true validate # 0 Checkstyle violationsExisting unit tests pass. The behavioral change in
getProperty()is safe becausehasProperty()already handlesproperties == nullby returningfalse, and all write paths go throughputProperty()which creates the HashMap on demand.