FlowControlHandler: respect auto-read when toggled while dequeueing#16949
Conversation
5a521c8 to
4ceff75
Compare
|
Need to have another look at this tomorrow before undrafting |
|
@schiemon just ping us when it's ready. |
8eda866 to
4a2aead
Compare
|
@chrisvest @normanmaurer ready for review 👍 |
| if (!dequeue(ctx) || config.isAutoRead()) { | ||
| assert unsatisfiedReads > 0 || config.isAutoRead(); |
There was a problem hiding this comment.
You need to store autoRead in a variable as otherwise it might be modified by another thread in between the if and the assert.
| if (!dequeue(ctx) || config.isAutoRead()) { | |
| assert unsatisfiedReads > 0 || config.isAutoRead(); | |
| boolean autoRead = config.isAutoRead(); | |
| if (!dequeue(ctx) || autoRead { | |
| assert unsatisfiedReads > 0 || autoRead; |
There was a problem hiding this comment.
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
3024057 to
32eb674
Compare
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
32eb674 to
a3e104b
Compare
|
@lhotari can you check ? |
@normanmaurer LGTM. This suites Apache Pulsar use cases. Thanks for fixing, @schiemon. |
|
@chrisvest @yawkat PTAL |
chrisvest
left a comment
There was a problem hiding this comment.
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.
|
Could not create auto-port PR. |
|
Auto-port PR for 4.1: #16983 |
|
PR for 5.0 #16984 |
…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>
…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; |
There was a problem hiding this comment.
why reset? wouldn't this force downstream(s) to manage unsatisfied reads manually?
if (config.isAutoRead()) {
ctx.fireChannelReadComplete();
} else if (unsatisfiedReads > 0) {
ctx.read();
}There was a problem hiding this comment.
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
Motivation
FlowControlHandlerdoes not respect changes to the channel's auto-read setting while flushing the queue. As such, a downstream handler that disables auto-read from withinchannelRead()cannot stopFlowControlHandlerfrom flushing the rest of the queue.Modification
dequeueOne()anddequeueAll()into a singledequeue()loop that re-checksconfig.isAutoRead()andunsatisfiedReadsbefore every message.channelReadand re-entrant reads satisfied from the queue, plus previously missing coverage for handler removal,channelInactiverelease, andreleaseMessages = false.Result
A downstream handler that disables auto-read from
channelRead()now stops delivery of the rest of the queue.Fixes #16945