-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
ShutdownWrap vs handle.close #32486
Comments
Not an expert, but... isn't final and destroy fundamentally different? Final/shutdown is an ordered operation, that after all data currently queued has transmitted, will do an orderly shutdown of the socket indicating no more outbound data will be sent (but not preventing more data inbound). destroy just closes the underlying OS handle (an fd on unix). The timing of this wrt. any ongoing data being sent or received is indeterminate, and once the fd is closed it will (of course) cease to exist, so can't be used to send or recv any more data. What happens on destroy() to all the ongoing send/recv queues is AFAICT not well specified by the streams contracte, and not consistently implemented... thus the stream of issues you are finding related to it. streams are about ordered bi-directional (sometimes) data xfer, and destroy just chops through that. Given this, that one does an orderly async wrapped operation, and one probably goes much more directly towards uv_close() is what I'd expect, is that what you are seeing? |
Indeed.
Good. This was not clear to me. Though I'm still a little confused why "shutdown" only affects the outbound side, should I think of it as "shutdown/end outbound"?. Is it possible to shutdown inbound only?
Got it.
Makes sense. |
https://linux.die.net/man/2/shutdown ^-- can do either or both directions. close() is similar to doing both directions. "normal" (orderly) usage is read() until EOF on incoming, write until no more data to send, then shutdown(WR) on outgoing. When both EOF received, and shutdown(WR) have ocurred, then close(). Thats at the syscall layer, but all the stack layers above emulate that basic pattern (because that is ultimately what occurs). abnormal termination is just close(), at syscall layer. .destroy() (maybe... its not well defined) at the node stream layer. |
yes: .end() maps to shutdown(WR) |
Perfect. I think that answered my question. Thanks a lot. |
@sam-github @addaleax just one more follow up here, pseudo example function onReadableStreamEnd () {
this.end() // -> process.nextTick -> _final -> shutdown
this.destroy() // -> _destroy -> close
} i.e. it's probably fixed through #31806 but I'm just curious whether this could be a problem in earlier node versions? |
@ronag Yeah, I would say that’s a potential problem … ideally, the shutdown would complete first and call the |
Yes, the |
I think its a house of cards down there in C++ streams.... TLS is the worse I've seen, because its this complex protocol engine with a top (facing node js) and a bottom (facing another stream... likely a tcp socket, but could be any bi-directional stream), and when a packet comes IN the bottom, it can actually cause stuff to go back OUT even though there is nothing in or out from the js layer yet. And reading from the js layer can cause TLS to wake up and write things out the bottom... it really stresses the "independent bi-directional streams that xform data going in the same direction, but with weak interactions between the in and out directions" paradigm of sockets. It works, seemingly!, but its pretty fragile. |
Right. I’d be a big fan of re-writing the TLS implementation from scratch… 😄 |
Oh most definitely. It's been on my todo list for a while now, especially having done through the whole QUIC implementation. |
I tired to rework the "implicit handshake" to explicit, but never got it quite working, there was always some set of edge test cases that broke when another was fixed, and I ran out of time and energy. |
When not allowing half open, handle.close would be invoked before shutdown has been called and completed causing a potential data race. Fixes: nodejs#32486 (comment)
Is the I have some vague memory of this not being the case but wanted to check with someone more knowledgable in this area, |
@ronag |
When not allowing half open, handle.close would be invoked before shutdown has been called and completed causing a potential data race. Fixes: #32486 (comment) PR-URL: #32491 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
When not allowing half open, handle.close would be invoked before shutdown has been called and completed causing a potential data race. Fixes: #32486 (comment) PR-URL: #32491 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
When not allowing half open, handle.close would be invoked before shutdown has been called and completed causing a potential data race. Fixes: #32486 (comment) PR-URL: #32491 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
I'm trying to understand some of the net code and ran into
_final
and_destroy
._final
uses aShutdownWrap
while_destroy
does ahandle.close()
What is the difference?
The text was updated successfully, but these errors were encountered: