Skip to content

FlowControlHandler: respect auto-read when toggled while dequeueing#16949

Merged
normanmaurer merged 3 commits into
netty:4.2from
schiemon:fix/flowcontrolhandler-autoread-16945
Jun 24, 2026
Merged

FlowControlHandler: respect auto-read when toggled while dequeueing#16949
normanmaurer merged 3 commits into
netty:4.2from
schiemon:fix/flowcontrolhandler-autoread-16945

Conversation

@schiemon

@schiemon schiemon commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Motivation

FlowControlHandler does not respect changes to the channel's auto-read setting while flushing the queue. As such, a downstream handler that disables auto-read from within channelRead() cannot stop FlowControlHandler from flushing the rest of the queue.

Modification

  • Merge dequeueOne() and dequeueAll() into a single dequeue() loop that re-checks config.isAutoRead() and unsatisfiedReads before every message.
  • Add tests for auto-read toggled on and off from channelRead and re-entrant reads satisfied from the queue, plus previously missing coverage for handler removal, channelInactive release, and releaseMessages = false.

Result

A downstream handler that disables auto-read from channelRead() now stops delivery of the rest of the queue.

Fixes #16945

@schiemon schiemon force-pushed the fix/flowcontrolhandler-autoread-16945 branch 2 times, most recently from 5a521c8 to 4ceff75 Compare June 13, 2026 16:33
@schiemon

schiemon commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

Need to have another look at this tomorrow before undrafting

@normanmaurer

Copy link
Copy Markdown
Member

@schiemon just ping us when it's ready.

@schiemon schiemon force-pushed the fix/flowcontrolhandler-autoread-16945 branch 2 times, most recently from 8eda866 to 4a2aead Compare June 15, 2026 09:55
@schiemon schiemon marked this pull request as ready for review June 15, 2026 12:08
@schiemon

Copy link
Copy Markdown
Contributor Author

@chrisvest @normanmaurer ready for review 👍

Comment on lines +169 to +170
if (!dequeue(ctx) || config.isAutoRead()) {
assert unsatisfiedReads > 0 || config.isAutoRead();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to store autoRead in a variable as otherwise it might be modified by another thread in between the if and the assert.

Suggested change
if (!dequeue(ctx) || config.isAutoRead()) {
assert unsatisfiedReads > 0 || config.isAutoRead();
boolean autoRead = config.isAutoRead();
if (!dequeue(ctx) || autoRead {
assert unsatisfiedReads > 0 || autoRead;

@schiemon schiemon Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point but we need to be careful here and capture the auto-read setting after dequeueing as it can change in downstream channelRead handlers that are invoked by dequeue

@schiemon schiemon force-pushed the fix/flowcontrolhandler-autoread-16945 branch 3 times, most recently from 3024057 to 32eb674 Compare June 16, 2026 09:49
Motivation:

- FlowControlHandler does not respect changes to the channel's auto-read
  setting while flushing the queue. As such, a downstream handler that
  disables auto-read from within channelRead() cannot stop
  FlowControlHandler from flushing the rest of the queue.

Modification:

- Merge dequeueOne() and dequeueAll() into a single dequeue() loop that
  re-checks config.isAutoRead() and unsatisfiedReads before every message.
- Add tests for auto-read toggled on and off from channelRead and re-entrant
  reads satisfied from the queue, plus previously missing coverage for
  handler removal, channelInactive release, and releaseMessages = false.

Result:

- A downstream handler that disables auto-read from channelRead() now stops
  delivery of the rest of the queue.

Fixes netty#16945
@schiemon schiemon force-pushed the fix/flowcontrolhandler-autoread-16945 branch from 32eb674 to a3e104b Compare June 16, 2026 09:51
@schiemon schiemon requested a review from normanmaurer June 16, 2026 10:16
@normanmaurer

Copy link
Copy Markdown
Member

@lhotari can you check ?

@lhotari

lhotari commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

@lhotari can you check ?

@normanmaurer LGTM. This suites Apache Pulsar use cases. Thanks for fixing, @schiemon.

@normanmaurer normanmaurer added this to the 4.2.16.Final milestone Jun 22, 2026
@normanmaurer normanmaurer added needs-cherry-pick-4.1 This PR should be cherry-picked to 4.1 once merged. needs-cherry-pick-5.0 This PR should be cherry-picked to 5.0 once merged. labels Jun 22, 2026
@normanmaurer normanmaurer requested review from chrisvest and yawkat June 22, 2026 14:48
@normanmaurer

Copy link
Copy Markdown
Member

@chrisvest @yawkat PTAL

@chrisvest chrisvest left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was speculating if there was a reentrancy bug, and it took me a day to chase down and verify that no there isn't.

Looks good.

@normanmaurer normanmaurer merged commit 8081e23 into netty:4.2 Jun 24, 2026
38 of 39 checks passed
@netty-project-bot

Copy link
Copy Markdown
Contributor

Could not create auto-port PR.
Got conflicts when cherry-picking onto 5.0.

@netty-project-bot

Copy link
Copy Markdown
Contributor

Auto-port PR for 4.1: #16983

@github-actions github-actions Bot removed the needs-cherry-pick-4.1 This PR should be cherry-picked to 4.1 once merged. label Jun 24, 2026
@normanmaurer

Copy link
Copy Markdown
Member

PR for 5.0 #16984

@normanmaurer normanmaurer removed the needs-cherry-pick-5.0 This PR should be cherry-picked to 5.0 once merged. label Jun 24, 2026
normanmaurer added a commit that referenced this pull request Jun 24, 2026
…le dequeueing (#16983)

Auto-port of #16949 to 4.1
Cherry-picked commit: 8081e23

---
## Motivation

`FlowControlHandler` does not respect changes to the channel's auto-read
setting while flushing the queue. As such, a downstream handler that
disables auto-read from within `channelRead()` cannot stop
`FlowControlHandler` from flushing the rest of the queue.

## Modification

- Merge `dequeueOne()` and `dequeueAll()` into a single `dequeue()` loop
that re-checks `config.isAutoRead()` and `unsatisfiedReads` before every
message.
- Add tests for auto-read toggled on and off from `channelRead` and
re-entrant reads satisfied from the queue, plus previously missing
coverage for handler removal, `channelInactive` release, and
`releaseMessages = false`.

## Result

A downstream handler that disables auto-read from `channelRead()` now
stops delivery of the rest of the queue.

Fixes #16945

Co-authored-by: Szymon Habrainski <56340221+schiemon@users.noreply.github.com>
Co-authored-by: Norman Maurer <norman_maurer@apple.com>
normanmaurer added a commit that referenced this pull request Jun 24, 2026
…16949) (#16984)

`FlowControlHandler` does not respect changes to the channel's auto-read
setting while flushing the queue. As such, a downstream handler that
disables auto-read from within `channelRead()` cannot stop
`FlowControlHandler` from flushing the rest of the queue.

- Merge `dequeueOne()` and `dequeueAll()` into a single `dequeue()` loop
that re-checks `config.isAutoRead()` and `unsatisfiedReads` before every
message.
- Add tests for auto-read toggled on and off from `channelRead` and
re-entrant reads satisfied from the queue, plus previously missing
coverage for handler removal, `channelInactive` release, and
`releaseMessages = false`.

A downstream handler that disables auto-read from `channelRead()` now
stops delivery of the rest of the queue.

Fixes #16945

Co-authored-by: Norman Maurer <norman_maurer@apple.com>

Co-authored-by: Szymon Habrainski <56340221+schiemon@users.noreply.github.com>
// Upstream closed the read cycle. Collapse every outstanding read() into a single downstream
// channelReadComplete; spurious upstream completions with no pending read are dropped.
if (config.isAutoRead() || unsatisfiedReads > 0) {
unsatisfiedReads = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why reset? wouldn't this force downstream(s) to manage unsatisfied reads manually?

if (config.isAutoRead()) {
    ctx.fireChannelReadComplete();
} else if (unsatisfiedReads > 0) {
    ctx.read();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tested our systems with and without this patch against the latest origin/4.2 state:

  • without patch (unsatisfiedReads = 0 + readComplete event) – ~7k tests failures
  • with patch (if (unsatisfiedReads > 0) ctx.read();) – all green

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.

FlowControlHandler no longer honors setAutoRead(false) made by a downstream handler while dequeuing (regression in 4.2.15)

6 participants