-
Notifications
You must be signed in to change notification settings - Fork 25k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle response correctly when request already cancelled #110249
Handle response correctly when request already cancelled #110249
Conversation
Pinging @elastic/es-distributed (Team:Distributed) |
if (localRefs.tryIncRef() == false) { | ||
assert localRefs.hasReferences() == false : "tryIncRef failed but RefCounted not completed"; | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like it could hide the test being broken (i.e. if we always cancel before the call to processResponse
it'll happily pass without testing anything).
Another approach would be to put a synchronization point after the call to sendResponse, which we wait on before cancelling the request. That way we could be sure we'd begun sending the response before the cancellation? but perhaps handling cancellation prior to the response being sent is part of the test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we could just call tryIncRef
, and if it fails to increment the counter, it should also not decrement it later (by virtue of channel.sendResponse
not sending the chunked response)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the current change is fine. We also do something similar at prepareRequest
a few lines above.
Line 637 in ef52f8c
if (localRefs != null && localRefs.tryIncRef()) { |
perhaps handling cancellation prior to the response being sent is part of the test?
I think so. The random sleep in the test method is intended to have cancellation happen in different places, including in prepareRequest
where no response is ever generated.
it should also not decrement it later (by virtue of channel.sendResponse not sending the chunked response)?
I think this might not be the case. It seems that response is released if channel.sendResponse
fails to send.
elasticsearch/server/src/main/java/org/elasticsearch/http/DefaultRestChannel.java
Lines 191 to 192 in ef52f8c
if (success == false) { | |
Releasables.close(toClose); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
With the changes in elastic#109519 we now do one more async step while serving the response, so we need to acquire another ref to track the new step. Relates elastic#109866 Relates elastic#110118 Relates elastic#110175 Relates elastic#110249
Related to #109866
Since #110118 the test fails under the same circumstances, but in a different way.
Now, when
processResponse
executes after the cancellation has completed (localRefs.hasReferences() == false
) - but before the channel is closed (RestActionListener.ensureOpen()
passes), the call tomustIncRef()
fails because the reference counts have already reached zero. This change usestryIncRef()
instead, double-checking on a failure thathasReferences() == false
(although I'm not sure whether that bit is necessary)