[ISSUE #10936] Avoid temporary buffers during batch message encoding - #10938
[ISSUE #10936] Avoid temporary buffers during batch message encoding#10938ai-yang wants to merge 2 commits into
Conversation
…oding Signed-off-by: Rui <1685901819@qq.com>
Signed-off-by: Rui <1685901819@qq.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #10938 +/- ##
=============================================
- Coverage 48.62% 48.49% -0.13%
+ Complexity 13692 13652 -40
=============================================
Files 1381 1381
Lines 101464 101472 +8
Branches 13187 13187
=============================================
- Hits 49337 49210 -127
- Misses 46142 46250 +108
- Partials 5985 6012 +27 ☔ 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.
Summary
Eliminates intermediate byte[] allocations in MessageDecoder.encodeMessages by computing the aggregate size first, then writing all messages directly into a single ByteBuffer. The public API and wire format are unchanged. JMH benchmarks show 12–34% throughput gain and 33–45% allocation reduction.
Findings
- [Info]
common/src/main/java/org/apache/rocketmq/common/message/MessageDecoder.java:738–762— The two-pass approach (size computation + direct write) is clean. One minor note:propertiesLengthis computed in bothencodedMessageSizeand the internalencodeMessagehelper. Consider caching it in thepropertiesBytes[]array alongside bodies to avoid the redundant cast, though the overhead is negligible. - [Info]
common/src/main/java/org/apache/rocketmq/common/message/MessageDecoder.java:738— The first pass callsmessage.getBody()and caches the reference. If a caller mutates the body array between the two passes, the size computed in pass 1 could mismatch the data written in pass 2. This is the same implicit assumption the old code made, so it's not a regression — just worth noting for future maintainers.
Verdict
Solid optimization with good test coverage (golden vector + equivalence test). The refactored internal helpers (encodedMessageSize, internal encodeMessage) are well-factored and the public API remains untouched.
Automated review by github-manager-bot
Which Issue(s) This PR Fixes
Brief Description
MessageDecoder.encodeMessagescurrently encodes every message into its own completebyte[], retains those arrays, then allocates a final result and copies every message again.This change removes those temporary full-message buffers:
ByteBufferis allocated;The public API and encoded wire format are unchanged.
How Did You Test This Change?
Correctness
The new tests compare
encodeMessages(messages)with the concatenation ofencodeMessage(message)for every input and verify an independent fixed wire vector. The completecommonmodule suite passes:Command:
mvn -o \ -Dspotbugs-plugin.version=4.2.2 -Dspotbugs.skip=true \ -Dcheckstyle.skip=true -Drat.skip=true \ -pl common testRelevant downstream tests also pass:
JMH benchmark
JMH 1.36 configuration:
-Xms512m -Xmx512mheap;The benchmark's
baseline()method reconstructs the previous aggregation algorithm in the same binary (per-message full encodings followed by a final copy), so the table labels it as a reconstructed baseline.Values are means plus or minus JMH's 99.9% confidence-interval half-width. The baseline and optimized throughput confidence intervals do not overlap in any scenario.
The 100 x 1 KiB case was repeated on OpenJDK 8u492:
Its throughput confidence intervals are also disjoint.
I also benchmarked the actual production method from separate baseline and optimized checkouts in A-B-A order for 100 x 1 KiB:
This is +30.24%/+33.91% throughput versus the two baseline runs and -45.28% allocation. The confidence intervals are disjoint.
Benchmark source, methodology, checksums, and all raw per-fork/per-iteration JSON results: https://gist.github.com/ai-yang/c3e3f65351054263dec6f7b8d67ad3cd
git diff --checkalso passes.