diff options
author | Vika <vika@fireburn.ru> | 2023-07-16 01:35:24 +0300 |
---|---|---|
committer | Vika <vika@fireburn.ru> | 2023-07-17 01:53:42 +0300 |
commit | 2b59a731eb5099fda4a31922e7b9c44fd9f9ab9d (patch) | |
tree | 319bfb399323dda8d3eebc6a5ea9637c0cf240bf /kittybox-rs | |
parent | b63d1204be8b9e264a645352c594e136f248ea3d (diff) | |
download | kittybox-2b59a731eb5099fda4a31922e7b9c44fd9f9ab9d.tar.zst |
FileStorage: properly fsync() files and directories
Total crash-safety. Yank the power cord all you want, your data is going to be safe and sound. (Unless your drive controller lies to you about flushing its caches)
Diffstat (limited to 'kittybox-rs')
-rw-r--r-- | kittybox-rs/src/database/file/mod.rs | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/kittybox-rs/src/database/file/mod.rs b/kittybox-rs/src/database/file/mod.rs index 842a834..8514717 100644 --- a/kittybox-rs/src/database/file/mod.rs +++ b/kittybox-rs/src/database/file/mod.rs @@ -316,8 +316,8 @@ impl Storage for FileStorage { .parent() .expect("Parent for this directory should always exist") .to_owned(); - if !parent.is_dir() { - tokio::fs::create_dir_all(parent).await?; + if !(spawn_blocking(move || parent.is_dir()).await.unwrap()) { + tokio::fs::create_dir_all(path.parent().unwrap()).await?; } let mut file = tokio::fs::OpenOptions::new() @@ -328,8 +328,10 @@ impl Storage for FileStorage { file.write_all(post.to_string().as_bytes()).await?; file.flush().await?; + file.sync_all().await?; drop(file); tokio::fs::rename(&tempfile, &path).await?; + tokio::fs::File::open(path.parent().unwrap()).await?.sync_all().await?; if let Some(urls) = post["properties"]["url"].as_array() { for url in urls.iter().map(|i| i.as_str().unwrap()) { @@ -369,10 +371,13 @@ impl Storage for FileStorage { { tracing::debug!("Adding to channel list..."); // Add the h-feed to the channel list - let mut path = relative_path::RelativePathBuf::new(); - path.push(user); - path.push("channels"); - let path = path.to_path(&self.root_dir); + let path = { + let mut path = relative_path::RelativePathBuf::new(); + path.push(user); + path.push("channels"); + + path.to_path(&self.root_dir) + }; tracing::debug!("Channels file path: {}", path.display()); let tempfilename = path.with_extension("tmp"); let channel_name = post["properties"]["name"][0] @@ -426,8 +431,10 @@ impl Storage for FileStorage { .write_all(serde_json::to_string(&channels)?.as_bytes()) .await?; tempfile.flush().await?; + tempfile.sync_all().await?; drop(tempfile); - tokio::fs::rename(tempfilename, path).await?; + tokio::fs::rename(tempfilename, &path).await?; + tokio::fs::File::open(path.parent().unwrap()).await?.sync_all().await?; } Ok(()) } @@ -454,8 +461,10 @@ impl Storage for FileStorage { temp.write_all(new_json.to_string().as_bytes()).await?; temp.flush().await?; + temp.sync_all().await?; drop(temp); - tokio::fs::rename(tempfilename, path).await?; + tokio::fs::rename(tempfilename, &path).await?; + tokio::fs::File::open(path.parent().unwrap()).await?.sync_all().await?; (json, new_json) }; @@ -667,8 +676,11 @@ impl Storage for FileStorage { tempfile .write_all(serde_json::to_string(&settings)?.as_bytes()) .await?; + tempfile.flush().await?; + tempfile.sync_all().await?; drop(tempfile); - tokio::fs::rename(temppath, path).await?; + tokio::fs::rename(temppath, &path).await?; + tokio::fs::File::open(path.parent().unwrap()).await?.sync_all().await?; Ok(()) } } |