Skip to content

4.x: Release replay buffers from cancelled consumers - #8317

Merged
akarnokd merged 1 commit into
ReactiveX:4.xfrom
tianrking:codex/replay-release-cancelled-consumers
Oct 5, 2026
Merged

akarnokd merged 1 commit into
ReactiveX:4.xfrom
tianrking:codex/replay-release-cancelled-consumers

Conversation

@tianrking

Copy link
Copy Markdown
Contributor

Holding a cancelled raw replay Disposable or Subscription kept the replay owner and its cached values reachable. Release that parent reference in ObservableReplay, FlowableReplay, ReplaySubject, and ReplayProcessor, and coordinate cursor cleanup with an active replay so cancellation cannot leave a stale linked node behind. Keep the request-management notification that may unblock other Flowable subscribers, and tolerate a concurrent request after the parent has been released.

The regression tests use public APIs, discard received values, and retain the original cancelled handle while checking the cached value through a weak reference. They cover unbounded, size-bounded, and time-and-size-bounded buffers for all four components, repeated cancellation, requests after cancellation, and request/cancel races.

Related #7912. This addresses cancellation retention; it does not resolve every remaining cache/replay GC item in that issue.

Validation on JDK 26 / Gradle 9.8:

  • The identical test blob produces 12 GC assertion failures against unchanged original production code; both request/cancel race controls pass.
  • The candidate passes 436 affected replay tests and 272 validators run locally.
  • The full hosted verification job passes 13,368 JUnit tests and 4,002 TestNG/TCK tests, plus the official build, Checkstyle, JaCoCo, and Javadoc tasks. Counts exclude existing skips. JaCoCo covers all 33 instrumented changed production lines.

The source SHA and raw file hashes are checked before and after execution. Only the four production classes and the regression test are in the PR; the external test-fork configuration and evidence workflow are outside its diff.

AI disclosure: I used Codex to investigate the retention path and develop the implementation and regression tests. The reasoning was that a custom consumer can legitimately retain its cancelled handle, but that handle no longer needs the independent replay owner or buffer. Review feedback will be followed up here.

@akarnokd akarnokd added this to the 4.0 milestone Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

🐷 TruffleHog + Entropy Beauty Scan

Average entropy of changed code: 4.331 bits/char
Verdict: ✅ Mid-4 beauty detected (thoughtful human code!)

Changed files entropy:

src/main/java/io/reactivex/rxjava4/internal/operators/flowable/FlowableReplay.java: 4.168
src/main/java/io/reactivex/rxjava4/internal/operators/observable/ObservableReplay.java: 4.222
src/main/java/io/reactivex/rxjava4/processors/ReplayProcessor.java: 4.300
src/main/java/io/reactivex/rxjava4/subjects/ReplaySubject.java: 4.367
src/test/java/io/reactivex/rxjava4/core/ReplayCancellationTest.java: 4.599

✅ No secrets or suspicious high-entropy strings found.

Mid-4 beauty heuristic in action — powered by our entropy chats! 😊

@akarnokd
akarnokd merged commit 452b30c into ReactiveX:4.x Oct 5, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants