rich7420 opened a new pull request, #11112: URL: https://github.com/apache/ozone/pull/11112
## What changes were proposed in this pull request? `StringCodecBase` (the base of `StringCodec` and `FixedLengthStringCodec`) allocates a fresh `CharsetEncoder` on every encode and a fresh `CharsetDecoder` on every decode: - `encode(...)` -> `newEncoder().encode(...)` - `decodeNoFallback(...)` / `decodeWithFallback(...)` -> `newDecoder().decode(...)` These codecs are singletons on a hot path: every `String` RocksDB key/value (OM/SCM tables, iterators, compaction) is serialized/deserialized through them, so a short-lived coder is created on each call. `CharsetEncoder`/`CharsetDecoder` are stateful and not thread-safe, so this caches one per thread (`ThreadLocal`) and reuses it: - the encoder is `reset()` before each use, because the 3-arg `encode(in, out, endOfInput)` does not reset on its own; - the decoder uses the single-arg `CharsetDecoder.decode(ByteBuffer)`, which resets internally (per its javadoc), so no explicit reset is added there. The cache is per codec instance rather than `static`, because subclasses use different charsets. `reset()` only clears coding state and keeps `onMalformedInput`/`onUnmappableCharacter(REPORT)`, so behavior is unchanged. ## What is the link to the Apache JIRA https://issues.apache.org/jira/browse/HDDS-16277 ## How was this patch tested? The change is behavior-preserving, so the existing codec tests are the regression gate. They exercise repeated encode/decode over the singleton codecs (which now go through the reused coder), malformed-input reporting, and multi-byte rejection: ``` mvn -pl hadoop-hdds/framework test -Dtest=TestCodec,TestFixedLengthStringCodec Tests run: 8, Failures: 0, Errors: 0, Skipped: 0 -- in org.apache.hadoop.hdds.utils.db.TestCodec Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 -- in org.apache.hadoop.hdds.utils.db.TestFixedLengthStringCodec ``` checkstyle, pmd and findbugs are green on the fork CI run. ### Microbenchmark JMH (out of tree), JDK 21, single thread, `fork=2`. Both variants run the identical encode/decode and differ only in coder acquisition (fresh vs. reused per thread), so the delta is attributable to this change. `gc.alloc.rate.norm` error is +/- 0.001 B/op, i.e. the per-call allocation is exact. Encode: | input | ns/op (old -> new) | B/op (old -> new) | | --- | --- | --- | | `/vol1/bucket1/dir1/dir2/object-file-000000123.dat` | 81.7 -> 66.3 (-19%) | 208 -> 112 (-96 B, -46%) | | `8f14e45f-ceea-467a-9d1b-2f3c4d5e6f70` | 58.7 -> 53.6 (-9%) | 208 -> 112 (-96 B, -46%) | Decode: | input | ns/op (old -> new) | B/op (old -> new) | | --- | --- | --- | | `/vol1/bucket1/dir1/dir2/object-file-000000123.dat` | 29.5 -> 25.5 (-14%) | 368 -> 328 (-40 B, -11%) | | `8f14e45f-ceea-467a-9d1b-2f3c4d5e6f70` | 28.7 -> 26.5 (-8%) | 320 -> 280 (-40 B, -13%) | Each encode drops one `CharsetEncoder` (96 B/op) and each decode one `CharsetDecoder` (40 B/op); encode allocation rate falls ~34-41%. The benchmark isolates the coder acquisition, so the absolute per-call savings carry over to the full `toPersistedFormat`/`fromPersistedFormat` path, while the percentage there is diluted by the surrounding buffer work. -- 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] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
