[ISSUE #10980] Encode and decode POP checkpoint and ack messages without the intermediate JSON string - #10981
[ISSUE #10980] Encode and decode POP checkpoint and ack messages without the intermediate JSON string#10981wang-jiahua wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Optimizes POP revive-topic checkpoint/ack serialization and parsing by eliminating intermediate String creation, reducing per-record allocations while preserving the stored UTF-8 JSON bytes.
Changes:
- Switch POP CK/ACK/BATCH_ACK encoding from
toJSONString(...).getBytes(UTF_8)toJSON.toJSONBytes(...). - Parse revive-topic records directly from
messageExt.getBody()instead ofnew String(body)+ parse. - Add unit tests to validate byte equivalence and byte[] round-trip decoding (including non-ASCII content).
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| store/src/test/java/org/apache/rocketmq/store/pop/PopCheckPointTest.java | Adds byte-equivalence + byte[] round-trip test for PopCheckPoint. |
| store/src/test/java/org/apache/rocketmq/store/pop/BatchAckMsgTest.java | Adds byte-equivalence + byte[] round-trip test for BatchAckMsg. |
| store/src/test/java/org/apache/rocketmq/store/pop/AckMsgTest.java | Adds byte-equivalence + byte[] round-trip test for AckMsg. |
| broker/src/main/java/org/apache/rocketmq/broker/processor/PopReviveService.java | Parses CK/ACK/BATCH_ACK directly from message body bytes; only builds raw string when logging is enabled. |
| broker/src/main/java/org/apache/rocketmq/broker/processor/PopMessageProcessor.java | Encodes CK messages via JSON.toJSONBytes. |
| broker/src/main/java/org/apache/rocketmq/broker/processor/PopBufferMergeService.java | Encodes ACK/BATCH_ACK via JSON.toJSONBytes. |
| broker/src/main/java/org/apache/rocketmq/broker/processor/ChangeInvisibleTimeProcessor.java | Encodes ACK and (re-)put CK via JSON.toJSONBytes. |
| broker/src/main/java/org/apache/rocketmq/broker/processor/AckMessageProcessor.java | Encodes ACK/BATCH_ACK via JSON.toJSONBytes. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
RockteMQ-AI
left a comment
There was a problem hiding this comment.
LGTM — clean, focused performance optimization that eliminates unnecessary intermediate String allocations on the POP checkpoint/ack encode and decode paths.
Summary
Replaces JSON.toJSONString(x).getBytes(UTF_8) with JSON.toJSONBytes(x) at all 6 encode sites, and new String(body) + JSON.parseObject(raw, ...) with direct JSON.parseObject(body, ...) at all 3 decode sites in PopReviveService. Since fastjson2 uses UTF-8 internally for both toJSONBytes and parseObject(byte[]), the serialized form is byte-identical to the previous path — no behavioral change.
The roundtrip equivalence tests (JsonBytesRoundtripTest) covering all 6 message types (including Chinese characters and $ in keys) provide good confidence that the optimization is safe.
Unused StandardCharsets imports are properly cleaned up.
Automated review by github-manager-bot
…s without the intermediate JSON string
19c3f16 to
f2696b9
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #10981 +/- ##
=============================================
- Coverage 48.58% 48.52% -0.06%
+ Complexity 13676 13674 -2
=============================================
Files 1381 1381
Lines 101475 101472 -3
Branches 13190 13190
=============================================
- Hits 49299 49237 -62
- Misses 46174 46214 +40
- Partials 6002 6021 +19 ☔ 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
This PR optimizes POP checkpoint and ack message encoding/decoding by eliminating intermediate String allocations. The changes switch from JSON.toJSONString(x).getBytes(UTF_8) to JSON.toJSONBytes(x) at encode sites, and parse directly from byte arrays at decode sites in PopReviveService. The stored bytes remain unchanged (fastjson2 produces identical UTF-8 output), ensuring backward compatibility.
Verdict: LGTM — Clean optimization with good test coverage.
Review Notes
- Correctness: The byte-equivalence is correctly verified in tests, including non-ASCII character handling. The decode path changes are safe since
JSON.parseObject(byte[], Class)is equivalent to the previousnew String(body)+parseObject(String, Class)pattern. - Performance: Eliminates one intermediate String and one byte[] copy per CK/ack record. While the per-record saving is small, it aligns with the existing
PopConsumerRecordpattern and reduces GC pressure on the hot POP consume path. - Logging improvement: The additional
POP_LOGGER.isInfoEnabled()guard prevents unnecessary String construction when logging is enabled but info level is not — nice defensive optimization. - Tests: Good coverage with byte-equivalence tests (
testToJsonBytesMatchesJsonStringBytes) and round-trip tests. The newPopCheckPointTestclass fills a gap in test coverage.
Automated review by github-manager-bot
Which Issue(s) This PR Fixes
Fixes #10980
Brief Description
Every POP checkpoint/ack written to the revive topic was serialized as
JSON.toJSONString(x).getBytes(UTF_8)— a full intermediateStringplus a secondbyte[]copy per record — andPopReviveService#scanReviveQueuematerializednew String(body)before parsing each CK/ack/batch-ack record. This PR switches the six encode sites (PopMessageProcessor#buildCkMsg,PopBufferMergeService#putAckToStore/putBatchAckToStore,AckMessageProcessor,ChangeInvisibleTimeProcessorack + re-put CK) toJSON.toJSONBytes(x)and parses revive records straight frommessageExt.getBody(); the raw string is now built only inside theenablePopLogbranch that logs it.The stored bytes are unchanged — fastjson2's
toJSONBytesproduces the same UTF-8 bytes astoJSONString().getBytes(UTF_8)— and the newer popkv implementation (PopConsumerRecord) already uses exactly this pattern.How Did You Test This Change?
PopCheckPointTest(new), plus new cases inAckMsgTest/BatchAckMsgTest— 5/5 pass.AckMessageProcessorTest8/8,ChangeInvisibleTimeProcessorTest9/9,PopMessageProcessorTest8/8,PopBufferMergeServiceTest4/4.PopReviveServiceTestmatches the develop baseline exactly (one pre-existing failure — a V1/V2 retry-topic naming assertion — identical with and without this change).mqadmin setConsumeMode -m POP, producer 64 threads + consumer 20 threads, consume TPS steady at ~150k, pop path confirmed active via pop.log, per arm clean store + broker restart + page cache drop, 3 interleaved trials, broker jar swapped per arm): broker young GC per million consumed messages 2.67/2.68/2.66 (base) vs 2.66/2.63/2.79 (patch) — parity, zero failures, no regression. The saving itself (one string + one array copy per CK/ack) is below GC-count resolution at this load, so this is a cleanup-level optimization aligned with the popkv precedent.