-
Notifications
You must be signed in to change notification settings - Fork 456
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
Make page cache and read_blk async #5023
Conversation
1624 tests run: 1549 passed, 0 failed, 75 skipped (full report)The comment gets automatically updated with the latest test results
80b99f8 at 2023-08-29T08:54:06.506Z :recycle: |
983fe79
to
523a54e
Compare
7c106f7
to
8d3b0d3
Compare
f1062a2
to
fcbd58a
Compare
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 don't think we can do Handle::block_on in drop.
8d3b0d3
to
d63f31d
Compare
4cdb800
to
4620505
Compare
## Problem The `EphemeralFile::write_blob` function accesses the page cache internally. We want to require `async` for these accesses in #5023. ## Summary of changes This removes the implementaiton of the `BlobWriter` trait for `EphemeralFile` and turns the `write_blob` function into an inherent function. We can then make it async as well as the `push_bytes` function. We move the `SER_BUFFER` thread-local into the `InMemoryLayerInner` so that the same buffer can be accessed by different threads as the async is (potentially) moved between threads. Part of #4743, preparation for #5023.
4620505
to
09146c0
Compare
d63f31d
to
3719b16
Compare
823a414
to
fb37dfb
Compare
In #5023, we want to make the slot locks async. The `drop_buffers_for_immutable` is used by `EphemeralFile::drop` and locks the slot locks. Drop impls can't be async, so, we must find a workaround. Some background on drop_buffers_for_immutable: it's really just a nice courtesy to proactively give back the slots. After dropping the EphemeralFile, we're not going to use them in the future and so, `find_victim` will repurpose them eventually. The only part that is important is `remove_mapping`, because if we don't do that, we'll never get back to removing the materialized_page_map / immutable_page_map, thereby effectively leaking memory. So, how to work around the lack of async destructors: the simple way would be to push the work into a background queue. This has an obvious perf penalty. So, this PR takes another approach, based on the insight that the BlockLease/PageReadGuards handed out by EphemeralFile barely outlive the EphemeralFile. This PR changes the lifetime of the PageReadGuard returned by EphemeralFile to _ensure_ this in the type system. With that, we can switch to try_write(), and be quite certain that there are no outstanding PageReadGuards for the EphemeralFile that is being dropped. So, we know we're doing the slot clean-up work. Note: this PR does not debate whether the slot cleanup work is really necessary. In my opinion, we can just not do it and let the pages get find_victim'ed a little later than now. But, let's have that discussion another day.
fb37dfb
to
02381a2
Compare
02381a2
to
2f4cf35
Compare
In #5023, we want to make the slot locks async. The `drop_buffers_for_immutable` is used by `EphemeralFile::drop` and locks the slot locks. Drop impls can't be async, so, we must find a workaround. Some background on drop_buffers_for_immutable: it's really just a nice courtesy to proactively give back the slots. After dropping the EphemeralFile, we're not going to use them in the future and so, `find_victim` will repurpose them eventually. The only part that is important is `remove_mapping`, because if we don't do that, we'll never get back to removing the materialized_page_map / immutable_page_map, thereby effectively leaking memory. So, how to work around the lack of async destructors: the simple way would be to push the work into a background queue. This has an obvious perf penalty. So, this PR takes another approach, based on the insight that the BlockLease/PageReadGuards handed out by EphemeralFile barely outlive the EphemeralFile. This PR changes the lifetime of the PageReadGuard returned by EphemeralFile to _ensure_ this in the type system. With that, we can switch to try_write(), and be quite certain that there are no outstanding PageReadGuards for the EphemeralFile that is being dropped. So, we know we're doing the slot clean-up work. Note: this PR does not debate whether the slot cleanup work is really necessary. In my opinion, we can just not do it and let the pages get find_victim'ed a little later than now. But, let's have that discussion another day.
1f3d275
to
7e19960
Compare
Before this patch, when dropping an EphemeralFile, we'd scan the entire `slots` to proactively evict its pages (`drop_buffers_for_immutable`). This was _necessary_ before #4994 because the page cache was a write-back cache: we'd be deleting the EphemeralFile from disk after, so, if we hadn't evicted its pages before that, write-back in `find_victim` wouldhave failed. But, since #4994, the page cache is a read-only cache, so, it's safe to keep read-only data cached. It's never going to get accessed again and eventually, `find_victim` will evict it. The only remaining advantage of `drop_buffers_for_immutable` over relying on `find_victim` is that `find_victim` has to do the clock page replacement iterations until the count reaches 0, whereas `drop_buffers_for_immutable` can kick the page out right away. However, weigh that against the cost of `drop_buffers_for_immutable`, which currently scans the entire `slots` array to find the EphemeralFile's pages. Alternatives have been proposed in #5122 and #5128, but, they come with their own overheads & trade-offs. Also, the real reason why we're looking into this piece of code is that we want to make the slots rwlock async in #5023. Since `drop_buffers_for_immutable` is called from drop, and there is no async drop, it would be nice to not have to deal with this. So, let's just stop doing `drop_buffers_for_immutable` and observe the performance impact in benchmarks.
2f4cf35
to
213e62d
Compare
The returned PageReadGuard is not Send so we change the locks used for the SlotInner's in the page cache to the ones from tokio. Also, make read_blk async.
213e62d
to
0cfc9ed
Compare
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 makes sense as our next step in async-izing things.
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.
Pushed some fixups as arpad is OOO.
## Problem `block_in_place` is a quite expensive operation, and if it is used, we should explicitly have to opt into it by allowing the `clippy::disallowed_methods` lint. For more, see #5023 (comment). Similar arguments exist for `Handle::block_on`, but we don't do this yet as there is still usages. ## Summary of changes Adds a clippy.toml file, configuring the [`disallowed_methods` lint](https://rust-lang.github.io/rust-clippy/master/#/disallowed_method).
Problem
read_blk
does I/O and thus we would like to make it async. We can't make the function async as long as thePageReadGuard
returned byread_blk
isn'tSend
. The page cache is called byread_blk
, and thus it can't be async withoutread_blk
being async. Thus, we have a circular dependency.Summary of changes
Due to the circular dependency, we convert both the page cache and
read_blk
to async at the same time:We make the page cache use
tokio::sync
synchronization primitives as those areSend
. This makes all the places that acquire a lock require async though, which we then also do. This includes also asyncification of theread_blk
function.Builds upon #4994, #5015, #5056, and #5129.
Part of #4743.