-
Notifications
You must be signed in to change notification settings - Fork 488
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
First part of VirtualFile async conversions #5180
Conversation
No tests were run or test report is not availableThe comment gets automatically updated with the latest test results
d2314af at 2023-09-01T12:36:25.604Z :recycle: |
let do_persist = |target_config_path: PathBuf| -> _ { | ||
async move { | ||
let target_config_parent = target_config_path.parent().with_context(|| { |
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.
Can probably save ourselves one level of indent here?
let do_persist = |target_config_path: PathBuf| -> _ { | |
async move { | |
let target_config_parent = target_config_path.parent().with_context(|| { | |
let do_persist = |target_config_path: PathBuf| async move { | |
let target_config_parent = target_config_path.parent().with_context(|| { |
F: FileExt, | ||
{ | ||
pub fn new(file: F) -> Self { | ||
impl FileBlockReader<VirtualFile> { |
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.
Extracted this stuff into #5181
/// Write the given buffer (which has to be below the kernel's internal page size) and fsync | ||
/// | ||
/// This ensures some level of atomicity (not a good one, but it's the best we have). | ||
pub fn write_and_fsync(&mut self, buf: &[u8]) -> Result<(), Error> { | ||
if self.write(buf)? != buf.len() { | ||
return Err(Error::new( | ||
std::io::ErrorKind::Other, | ||
"Could not write all the bytes in a single call", | ||
)); | ||
} | ||
self.sync_all()?; | ||
Ok(()) | ||
} |
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.
Would prefer to back out the addition of this function. It's not what I had in mind with
special-purpose api for write-once files, to be used in save_metadata and persist_tenant_conf
Will push a commit that removes this API, then create a PR that adds the API I had in mind.
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.
See my inline comments
(part of #4743) (preliminary to #5180) This PR adds a special-purpose API to `VirtualFile` for write-once files. It adopts it for `save_metadata` and `persist_tenant_conf`. This is helpful for the asyncification efforts (#4743) and specifically asyncification of `VirtualFile` because above two functions were the only ones that needed the VirtualFile to be an `std::io::Write`. (There was also `manifest.rs` that needed the `std::io::Write`, but, it isn't used right now, and likely won't be used because we're taking a different route for crash consistency, see #5172. So, let's remove it. It'll be in Git history if we need to re-introduce it when picking up the compaction work again; that's why it was introduced in the first place). We can't remove the `impl std::io::Write for VirtualFile` just yet because of the `BufWriter` in ```rust struct DeltaLayerWriterInner { ... blob_writer: WriteBlobWriter<BufWriter<VirtualFile>>, } ``` But, @arpad-m and I have a plan to get rid of that by extracting the append-only-ness-on-top-of-VirtualFile that #4994 added to `EphemeralFile` into an abstraction that can be re-used in the `DeltaLayerWriterInner` and `ImageLayerWriterInner`. That'll be another PR. ### Performance Impact This PR adds more fsyncs compared to before because we fsync the parent directory every time. 1. For `save_metadata`, the additional fsyncs are unnecessary because we know that `metadata` fits into a kernel page, and hence the write won't be torn on the way into the kernel. However, the `metadata` file in general is going to lose signficance very soon (=> see #5172), and the NVMes in prod can definitely handle the additional fsync. So, let's not worry about it. 2. For `persist_tenant_conf`, which we don't check to fit into a single kernel page, this PR makes it actually crash-consistent. Before, we could crash while writing out the tenant conf, leaving a prefix of the tenant conf on disk.
## Problem `VirtualFile` does both reading and writing, and it would be nice if both could be converted to async, so that it doesn't have to support an async read path and a blocking write path (especially for the locks this is annoying as none of the lock implementations in std, tokio or parking_lot have support for both async and blocking access). ## Summary of changes This PR is some initial work on making the `VirtualFile` APIs async. It can be reviewed commit-by-commit. * Introduce the `MaybeVirtualFile` enum to be generic in a test that compares real files with virtual files. * Make various APIs of `VirtualFile` async, including `write_all_at`, `read_at`, `read_exact_at`. Part of #4743 , successor of #5180. Co-authored-by: Christian Schwarz <me@cschwarz.com>
Problem
VirtualFile
does both reading and writing, and it would be nice if both could be converted to async, so that it doesn't have to support an async read path and a blocking write path (especially for the locks this is annoying as none of the lock implementations in std, tokio or parking_lot have support for both async and blocking access).Summary of changes
This PR is some initial work on making the
VirtualFile
APIs async. It can be reviewed commit-by-commit.MaybeVirtualFile
enum to be generic in a test that compares real files with virtual files.VirtualFile
async, includingwrite_all_at
,read_at
,read_exact_at
Send
.Part of #4743
Checklist before requesting a review
Checklist before merging