Skip to content

[improve][ml] Reduce read permit callback allocations - #286

Open
lhotari wants to merge 1 commit into
lh-perfopt-range-read-callback-basefrom
lh-perfopt-range-read-callback
Open

lhotari wants to merge 1 commit into
lh-perfopt-range-read-callback-basefrom
lh-perfopt-range-read-callback

Conversation

@lhotari

@lhotari lhotari commented Sep 19, 2026

Copy link
Copy Markdown
Owner

Motivation

Managed-ledger range reads currently allocate three coordination objects for every successful read batch: the read callback, an AtomicInteger that counts retained entries, and a capturing Runnable attached to every returned entry. These short-lived allocations add GC pressure on the persistent-topic read path.

Modifications

Make the private read callback also own the atomic remaining-entry field and implement Runnable. Every returned entry can then share that callback directly as its deallocation hook.

The callback uses a terminal counter state to make successful or failed completion idempotent. It clears the forwarded callback after delivery, including when that callback throws, so entries retained by a consumer do not retain the dispatcher callback and its object graph. Read permits continue to be released exactly once after the final entry is deallocated, or immediately for an empty or failed read.

Verifying this change

A focused JMH benchmark covering real entry copies, deallocation hooks, and inflight-read permit accounting measured 40 fewer allocated bytes per batch for batch sizes 1, 100, and 1,000. CPU confidence intervals overlap, so this change does not claim a CPU improvement.

An end-to-end saturation screen sent five million keyed messages through 500 producers to five Key_Shared subscriptions with ten consumers each. Every subscription received all five million messages with zero duplicates, ordering violations, or invalid messages. The candidate completed at 66,192 msg/s and the immediately following baseline at 56,517 msg/s; this workload has substantial run-to-run variation, so the comparison is used only to exclude a material regression.

Validation:

  • RangeEntryCacheImplTest
  • InflightReadsLimiterIntegrationTest
  • focused JMH benchmark with GC allocation profiling
  • ./gradlew quickCheck
  • ./gradlew spotlessCheck checkstyleMain checkstyleTest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant