ai-yang opened a new issue, #10813:
URL: https://github.com/apache/rocketmq/issues/10813

   ### Before Creating the Enhancement Request
   
   - [x] I have confirmed that this should be classified as an enhancement 
rather than a bug/feature.
   
   ### Summary
   
   The LMQ append path currently creates avoidable temporary objects while 
preparing and committing multi-dispatch offsets. `LmqDispatch.wrapLmqDispatch` 
splits the queue-name property, allocates a `Long[]`, boxes every LMQ offset, 
and joins the array into a string. After the message is appended, 
`updateLmqOffsets` splits the same queue-name property again.
   
   I propose reusing the parsed queue names across the successful append path 
and building the offset property directly with `StringBuilder.append(long)`. 
This preserves the public API and the persisted message format while reducing 
allocation in a hot store path.
   
   ### Motivation
   
   LMQ messages execute this work for every append. A paired JMH benchmark on 
the current `develop` baseline (`2daf0e2ca91a1592d18235d43e5d709d1c35d15f`) 
shows that removing the intermediate array, boxing, and repeated split 
substantially reduces allocation:
   
   | LMQ queues | Baseline B/op | Optimized B/op | Saved B/op | Saved | Median 
paired throughput change |
   | ---: | ---: | ---: | ---: | ---: | ---: |
   | 1 | 1376.000 | 704.000 | 672.000 | 48.837% | +63.107% |
   | 4 | 3016.001 | 1536.000 | 1504.000 | 49.867% | +82.696% |
   
   Allocation decreased in all 5/5 independent pairs for both queue counts. The 
minimum reduction was 648 B/op. Throughput improved in every pair; the smallest 
paired gain was 46.723%.
   
   Environment: OpenJDK 8u492, JMH 1.36, Linux x86_64, Intel Xeon Gold 6133. 
Each of five alternating baseline-to-optimized pairs used one fork, both queue 
counts, five 1-second warmup iterations, ten 1-second measurement iterations, 
throughput mode, and `-prof gc`. The core invocation was:
   
   ```text
   org.openjdk.jmh.Main '.*LmqDispatchBenchmark.*' \
     -f 1 -wi 5 -i 10 -w 1s -r 1s -prof gc -rf json
   ```
   
   ### Describe the Solution You'd Like
   
   - Add an internal preparation method that parses queue names once and 
returns them for reuse after a successful append.
   - Build `PROPERTY_INNER_MULTI_QUEUE_OFFSET` directly with a `StringBuilder`, 
retaining empty fields for non-LMQ queue names.
   - Serialize the message property map once on the normal append path.
   - Increase LMQ offsets only after the physical append succeeds. An 
`END_OF_FILE` retry must not increment twice.
   - Keep the existing public methods, exception mapping, property ordering, 
and encoded message bytes compatible.
   
   The proposed regression coverage includes mixed LMQ/non-LMQ names, LMQ 
disabled, `WAIT_STORE_MSG_OK`, exact legacy property bytes, successful append, 
mapped-file rollover retry, RocksDB failure mapping, generic consume-queue 
failure mapping, and exactly-once offset increments.
   
   Correctness and quality gates already completed on JDK 8:
   
   - New regression class: 20 independent Maven/Surefire runs, 100/100 tests 
passed.
   - Affected reactor (`store -am`): 733 tests, 0 failures/errors, 4 existing 
skips.
   - Full root package coverage: all modules passed, with namesrv's 116 tests 
executed in an isolated network namespace because the host already occupied 
port 9876.
   - Checkstyle: 0 violations; SpotBugs: 0 bugs/errors in the affected reactor.
   - Apache RAT 0.12: all 19 reactor modules passed.
   - `git diff --check`: passed.
   
   ### Describe Alternatives You've Considered
   
   1. Keep `Long[]` and only replace `StringUtils.join`. This still retains the 
array and boxed `Long` objects.
   2. Reparse the dispatch property after append. This avoids carrying an 
internal reference but preserves the second split and its array allocation.
   3. Store parsed names in `PutMessageContext`. This enlarges a context used 
by non-LMQ messages and is unnecessary because the names are only needed within 
one append callback.
   
   ### Additional Context
   
   This enhancement does not change public APIs, configuration, protocol 
fields, or persistence format. The `END_OF_FILE` path intentionally falls back 
to parsing the already encoded message on retry so no additional per-message 
context field is required.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to