RUST-793 Reduce size of returned futures #417
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
RUST-793
This PR boxes the futures returned from
execute_operation
in order to reduce the size of the futures eventually returned to users.In Rust, futures are "zero cost" in the sense that they have no hidden heap allocations (i.e. everything is on the stack), and they're implemented as giant enum-like state machines (with the code between each
.await
point as the states) that store all the stack data for each state. Like regular Rust enums, the size of this state machine is equivalent to the size of the largest variant, so the size of our futures are equivalent to the stack space required for the await point that uses the most stack space. Additionally, due to some missing optimizations in the compiler (rust-lang/rust#62958), the size can exponentially grow with the number of nested.await
points.This explanation is over-simplified / could be inaccurate, so I highly recommend checking out this video for a better overview of futures in Rust and the problem we're dealing with.
This is a known problem with Rust async, and the general advice is to just
Box::pin
the branches that might use a lot of space. I spent a lot of time digging into this for the driver, and I couldn't really pinpoint any rouge branches other than the entirety ofexecute_operation
, so I just decided to box it entirely, as most of our futures will reach it at some point. Fortunately, this did not seem to have a noticeable impact on performance. The concerning thing is that something likefind_one
(which calls through tofind
) is still pretty massive even after this boxing (~3 KiB), but I think that's just par for the course in async Rust. For most systems this won't be a problem as the stack is pretty huge.Size of futures before boxing:
Sizes after: