-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Stop retaining transport responses for test-only listener #125163
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
Stop retaining transport responses for test-only listener #125163
Conversation
We only retained the response to response to a test-only call back in this lambda. With this fixed, all that's seemingly left is removing the response reference from `OutboundMessage` and we should be (unless there's more specifc to the callsite issues upstream) able to GC these potentially huge instances a lot quicker under network pressure.
|
Pinging @elastic/es-distributed-coordination (Team:Distributed Coordination) |
…port-response-past-sending
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.
Makes sense to me. Could you open a PR with the more finished state too (with OutboundMessage gone) so we can see more clearly where this is heading? It might be that the next step is also not so large and we can do it in one.
| + "}{" | ||
| + isHandshake() | ||
| + "}{" | ||
| + message.getClass() |
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'd rather we kept some way to identify the response type, although I must say I never much liked sharing its class here. Could we plumb in the action from the TcpTransportChannel down to here first?
…port-response-past-sending
We only retained the response to response to a test-only call back in this lambda. With this fixed, all that's seemingly left is removing the response reference from `OutboundMessage` and we should be (unless there's more specifc to the callsite issues upstream) able to GC these potentially huge instances a lot quicker under network pressure.
|
@DaveCTurner thanks for taking a look. So roughly https://github.com/elastic/elasticsearch/compare/main...original-brownbear:drop-outbound-msg?expand=1 is where I'd take this. It's essentially just a bunch of test plumbing and maybe some other simplifications to serialization but nothing complicated either. Note that I made that version in a way that preserves the slowness warning serialization exactly as it is today ... not necessarily the approach I'd recommend long term but also not a big deal memory wise for now. |
Nobody uses this parameter (except some tests that simplify verify the otherwise-unused plumbing is connected). This commit removes it. Relates elastic#125163
Nobody uses this parameter (except some tests that simply verify the otherwise-unused plumbing is connected). This commit removes it. Relates elastic#125163
|
Ok yeah that looks nicer indeed, I think I'd rather do the whole thing in one step tbh rather than having this intermediate state. Or rather I'd like to do #125326 separately first because it's kinda unrelated to the rest of it, then just https://github.com/elastic/elasticsearch/compare/main...original-brownbear:drop-outbound-msg?expand=1 straight away. |
|
Sounds good, I'll wait for that PR to go on, then I'll update this one to cover all the changes when resolving the conflicts anyway :) |
|
👍 I think my only comment so far is I'd rather not use |
Nobody uses this parameter (except some tests that simply verify the otherwise-unused plumbing is connected). This commit removes it. Relates #125163
Nobody uses this parameter (except some tests that simply verify the otherwise-unused plumbing is connected). This commit removes it. Relates #125163
…port-response-past-sending
…port-response-past-sending
…e-past-sending' into stop-retaining-transport-response-past-sending
| channel, | ||
| message, | ||
| networkMessage, | ||
| requestAction == null |
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.
As I said above, not 100% sure about this one, but then again, either we want this information or not though and this still seems cheaper than redundantly building the string.
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.
Yep I think we want this info. Looks easy enough to plumb in the action on the response path too these days, but we can do that in a followup.
|
|
||
| // public for tests | ||
| public static BytesReference serialize( | ||
| @Nullable String requestAction, |
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 get your point @DaveCTurner, setting request or response based on a null is not great, but then again, this method already has an absurd number of parameters? :)
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.
Maybe it needs a parameters object? I think I'd call it... OutboundMessage 🤣
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'll follow up with something like this:
drops the isError boolean that only makes sense on responses, replacing it with a three-state enum, and makes the action available on all paths.
| final BytesReference totalBytes = message.serialize(body, os); | ||
| final BytesReference totalBytes; | ||
| if (isRequest) { | ||
| totalBytes = OutboundHandler.serialize( |
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 add some overloads to shorten this thing, but not sure it's worth it, it's not that many spots and it's test only code.
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.
Yeah no big deal IMO
|
Alright thanks @DaveCTurner I merge my other branch into this one. Fine by me adding another flag here to mark a request but other than that wdyt? :) Certainly could be done nicer here and there, but IMO it's an improvement over the status quo beyond the GC improvements because it also makes it a little easier to add additional zero-copy serialization paths I think. |
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 (few nits but nothing blocking)
|
|
||
| // public for tests | ||
| public static BytesReference serialize( | ||
| @Nullable String requestAction, |
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.
Maybe it needs a parameters object? I think I'd call it... OutboundMessage 🤣
| final BytesReference totalBytes = message.serialize(body, os); | ||
| final BytesReference totalBytes; | ||
| if (isRequest) { | ||
| totalBytes = OutboundHandler.serialize( |
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.
Yeah no big deal IMO
| channel, | ||
| message, | ||
| networkMessage, | ||
| requestAction == null |
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.
Yep I think we want this info. Looks easy enough to plumb in the action on the response path too these days, but we can do that in a followup.
| */ | ||
| void sendBytes(TcpChannel channel, BytesReference bytes, ActionListener<Void> listener) { | ||
| internalSend(channel, bytes, null, listener); | ||
| internalSend(channel, bytes, () -> "", listener); |
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.
| internalSend(channel, bytes, () -> "", listener); | |
| internalSend(channel, bytes, () -> "raw bytes", listener); |
| if (compressionScheme != null) { | ||
| status = TransportStatus.setCompress(status); | ||
| } | ||
| byteStreamOutput.seek(0); |
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 should at least assert that byteStreamOutput.position() == 0 at the top of the method (the existing code also makes this assumption)
|
|
||
| import java.io.IOException; | ||
|
|
||
| abstract class OutboundMessage extends NetworkMessage { |
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.
There's no usages of NetworkMessage left now either?
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.
Right deleted it :)
|
|
||
| final int variableHeaderLength = Math.toIntExact(byteStreamOutput.position() - TcpHeader.HEADER_SIZE); | ||
| BytesReference message = serializeMessageBody(writeable, compressionScheme, version, byteStreamOutput); | ||
| byte status = requestAction != null ? 0 : TransportStatus.setResponse((byte) 0); |
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.
nit: would prefer to start with 0 and use if (...) over ... ? ... : ... for harmony with the following lines
|
Thanks David! |
💔 Backport failed
You can use sqren/backport to manually backport by running |
…125326) Nobody uses this parameter (except some tests that simply verify the otherwise-unused plumbing is connected). This commit removes it. Relates elastic#125163
…125326) Nobody uses this parameter (except some tests that simply verify the otherwise-unused plumbing is connected). This commit removes it. Relates elastic#125163
Remove the `OutboundMessage` class that needlessly holds on to the the response instances after they are not needed any longer. Inlining the logic should save considerably heap under pressure and enabled further optimisations.
…125326) Nobody uses this parameter (except some tests that simply verify the otherwise-unused plumbing is connected). This commit removes it. Relates elastic#125163
Remove the `OutboundMessage` class that needlessly holds on to the the response instances after they are not needed any longer. Inlining the logic should save considerably heap under pressure and enabled further optimisations.
Remove the `OutboundMessage` class that needlessly holds on to the the response instances after they are not needed any longer. Inlining the logic should save considerably heap under pressure and enabled further optimisations.
Remove the `OutboundMessage` class that needlessly holds on to the the response instances after they are not needed any longer. Inlining the logic should save considerably heap under pressure and enabled further optimisations.
) Remove the `OutboundMessage` class that needlessly holds on to the the response instances after they are not needed any longer. Inlining the logic should save considerably heap under pressure and enabled further optimisations. backport of #125163
|
back ported in #126078 now, sorry for the delay @DaveCTurner ! |
|
Thanks Armin |
We only retained the response to response to a test-only call back in this lambda. Also in
OutboundMessagewe only retain the message for its class name until the very end on the off chance we need it to print a slowness warning. This should do away with all retention in the transport layer code, probably a lot of spots to fix for this upstream from there, but IMO it's a good start and saves heap for all the spots that don't need fixing right away.PS: I'm aware that the
OutBoundMessageis a weird class now, even weirder than before. My suggestion would be to go for this change as a "shortest possible fix" kinda thing and refactor awayOutBoundMessagein the next step (and quickly do so).