v0.9.0
Oxia Java Client 0.9.0 is a performance-focused release: the hot write and read paths shed allocations and lock contention, batch assembly moves from two dedicated threads per shard to a small shared pool, and the client now applies end-to-end backpressure by bounding the total size of pending operations.
Compatibility
- The client now caps the total size of accepted-but-incomplete operations at 256 MiB by default (#348). When the cap is reached, further operations block the calling thread until enough pending operations complete. Use
OxiaClientBuilder.maxPendingBytes(0)to restore the previous unbounded behavior. - Batches are now assembled by a shared
oxia-batcherthread pool (1 thread by default, configurable withOxiaClientBuilder.batchingThreads(int)) instead of two dedicated threads per shard (#349). Batching semantics — pipelined sends, per-shard ordering, flush-when-idle — are unchanged. OxiaClientBuilder.batchLinger(...)is deprecated for removal: batching has been adaptive for a while, so the setting has no effect (#346). Configuration files that contain abatchLingerentry keep loading. The perf tool's--batch-linger-msflag was removed.- There are no breaking API changes: code built against 0.8.0 keeps compiling and running.
Requirements
- Java 17 is required (unchanged).
- No data migration is required.
- No configuration change is required.
Public API Changes
- New
OxiaClientBuilder.maxPendingBytes(long): bounds the total size of pending operations; default 256 MiB,0disables the limit (#348). - New
OxiaClientBuilder.batchingThreads(int): number of shared batch-assembly threads; default 1 (#349). OxiaClientBuilder.batchLinger(Duration)is deprecated for removal (#346).
Performance Improvements
- Batch assembly runs on a small shared pool instead of two platform threads per shard, removing hundreds of idle threads and tens of MB of preallocated arrays at high shard counts (#349).
- Sync range scans use gRPC manual flow control: the transport thread no longer parks waiting for the application to consume each record, buffering stays bounded to one in-flight response per shard, and
close()cancels the underlying streams (#342). - Key-to-shard routing is an allocation-free xxh3 hash plus a binary search over the hash ranges, replacing a linear scan with per-call stream and boxing allocations (#343).
- The key comparator no longer allocates substrings per path segment: sorting 100k multi-segment keys drops from 187 ms / 1.21 GB allocated to 90 ms / 862 KB (#347).
- Write operations no longer materialize UTF-8 byte arrays just to measure key sizes (#344).
- Read batch requests are built in place instead of deep-copying a temporary request per get (#351).
- Session lookups on the ephemeral-put path take a lock-free fast path when the session already exists, instead of serializing all writers of a shard (#350).
- Each put schedules one timeout task instead of two (#341).
- Notifications are dispatched with a plain loop instead of a per-event
parallelStream(#345).
Metrics Changes
- None.
Operational Changes
- Dependency updates: log4j-core pinned to a fixed version across all build configurations, OpenTelemetry upgraded to 1.63.0 for CVE-2026-45292 (#352).
Changes Since v0.8.0
- feat: limit the total size of the pending operations (#348)
- perf: assemble batches on shared threads instead of one thread per shard (#349)
- perf: lock-free fast path for the session lookup (#350)
- perf: build read batch requests in place (#351)
- perf: rewrite CompareWithSlash without substring allocations, add JMH benchmarks module (#347)
- perf: dispatch notifications with a plain loop instead of parallelStream (#345)
- perf: compute UTF-8 key sizes without materializing the bytes (#344)
- perf: route keys to shards with a binary search over the hash ranges (#343)
- perf: switch sync range-scan iterator to gRPC manual flow control (#342)
- perf: schedule a single timeout task per put operation (#341)
- api: deprecate batchLinger, which has no effect (#346)
- build: fix Dependabot alerts for log4j-core and opentelemetry-api (#352)
- chore: release 0.9.0 (#353)
Full Changelog: v0.8.0...v0.9.0