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]