about summary refs log tree commit diff
path: root/kittybox-rs/src/database/file
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2023-07-16 01:35:24 +0300
committerVika <vika@fireburn.ru>2023-07-17 01:53:42 +0300
commit2b59a731eb5099fda4a31922e7b9c44fd9f9ab9d (patch)
tree319bfb399323dda8d3eebc6a5ea9637c0cf240bf /kittybox-rs/src/database/file
parentb63d1204be8b9e264a645352c594e136f248ea3d (diff)
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/src/database/file')
-rw-r--r--kittybox-rs/src/database/file/mod.rs30
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(())
     }
 }