-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
core: Added changes to make ServerImpl.internalClose() thread-safe #11924
base: master
Are you sure you want to change the base?
core: Added changes to make ServerImpl.internalClose() thread-safe #11924
Conversation
Created this new PR with required changes along with Review points fixes as part of Existing PR #11864 which needs to close as duplicate once this PR merged. |
@@ -581,6 +586,7 @@ public void close(Status status, Metadata trailers) { | |||
// clientStreamListener.closed can trigger clientStream.cancel (see code in | |||
// ClientCalls.blockingUnaryCall), which may race with clientStream.serverClosed as both are | |||
// calling internalCancel(). | |||
closeCalled = true; |
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.
Eric had commented that the stream implementation should handle whether close had already been called but this PR is doing it in the InProcessTransport.
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.
Fixed and moved the changes to AbstractServerStream
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.
Needs work.
…ream implementation.
Fixed the Review comments and PR is Ready for your Re-review. |
@@ -120,6 +121,7 @@ public final void deliverFrame( | |||
|
|||
@Override | |||
public final void close(Status status, Metadata trailers) { | |||
Preconditions.checkState(!closeCalled, "call already closed"); | |||
Preconditions.checkNotNull(status, "status"); | |||
Preconditions.checkNotNull(trailers, "trailers"); | |||
if (!outboundClosed) { |
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.
If internalClose was called before, outboundClosed would have been set to true and any further calls to close() from anywhere else already skips over if outboundClosed is true. Your changes here don't seem to be achieving anything extra.
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.
We need to make the check apply for usages of stream in ServerCallImpl (application thread usages of the stream) if the stream had already been closed. Refer comment. Also we should not need to add another field to track the stream closed status since there is already an outboundClosed field and this should be able to be used for such checks.
@@ -120,6 +121,7 @@ public final void deliverFrame( | |||
|
|||
@Override | |||
public final void close(Status status, Metadata trailers) { | |||
Preconditions.checkState(!closeCalled, "call already closed"); |
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.
Is precondition the right thing to do or will logging an error message do? With an example callstack for close
close:123, AbstractServerStream (io.grpc.internal)
closeInternal:227, ServerCallImpl (io.grpc.internal)
close:213, ServerCallImpl (io.grpc.internal)
onCompleted:395, ServerCalls$ServerCallStreamObserverImpl (io.grpc.stub)
sayHello:104, HelloWorldServer$GreeterImpl (io.grpc.examples.helloworld)
invoke:285, GreeterGrpc$MethodHandlers (io.grpc.examples.helloworld)
onHalfClose:182, ServerCalls$UnaryServerCallHandler$UnaryServerCallListener (io.grpc.stub)
halfClosed:356, ServerCallImpl$ServerStreamListenerImpl (io.grpc.internal)
runInContext:861, ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed (io.grpc.internal)
run:37, ContextRunnable (io.grpc.internal)
run:133, SerializingExecutor (io.grpc.internal)
runWorker:1144, ThreadPoolExecutor (java.util.concurrent)
run:642, ThreadPoolExecutor$Worker (java.util.concurrent)
runWith:1596, Thread (java.lang)
run:1583, Thread (java.lang)
Failed precondition will cause the exception to be caught at runInContext:861, ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed
and again call internalClose
and rethrow the exception which then will be caught and logged in run:133, SerializingExecutor
.
If the application continues to attempt to write messages these steps will keep repeated for each attempt and the application is not going to come to know of it anyway. It may be better to just write an error log instead. @ejona86 to confirm.
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.
Review comments.
We discussed internally and concluded this issue is too complex to get it done by xWF. Please stop working on this issue. |
core: Added changes to make ServerImpl.internalClose thread-safe
Fixes: #3746