diff options
author | Alex <alex@adnab.me> | 2023-01-04 14:43:45 +0000 |
---|---|---|
committer | Alex <alex@adnab.me> | 2023-01-04 14:43:45 +0000 |
commit | 02e8eb167efa1f08d69fe7f8e6192cde726c45aa (patch) | |
tree | 0365526335f6597e672984ec67ed1390480238f5 /src/block/manager.rs | |
parent | 329c0e64f9044511f1a0d46b1b3ed99bdd890630 (diff) | |
parent | 936b6cb563b9dc8bb5c879f8bd6b89574f016f03 (diff) | |
download | garage-02e8eb167efa1f08d69fe7f8e6192cde726c45aa.tar.gz garage-02e8eb167efa1f08d69fe7f8e6192cde726c45aa.zip |
Merge pull request 'PutObject: better cleanup when request is interrupted in the middle' (#462) from interrupted-cleanup into main
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/462
Diffstat (limited to 'src/block/manager.rs')
-rw-r--r-- | src/block/manager.rs | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/src/block/manager.rs b/src/block/manager.rs index 19841d64..1655be06 100644 --- a/src/block/manager.rs +++ b/src/block/manager.rs @@ -6,6 +6,7 @@ use std::time::Duration; use arc_swap::ArcSwapOption; use async_trait::async_trait; use bytes::Bytes; +use rand::prelude::*; use serde::{Deserialize, Serialize}; use futures::Stream; @@ -676,14 +677,21 @@ impl BlockManagerLocked { } }; - let mut path2 = path.clone(); - path2.set_extension("tmp"); - let mut f = fs::File::create(&path2).await?; + let mut path_tmp = path.clone(); + let tmp_extension = format!("tmp{}", hex::encode(thread_rng().gen::<[u8; 4]>())); + path_tmp.set_extension(tmp_extension); + + let mut delete_on_drop = DeleteOnDrop(Some(path_tmp.clone())); + + let mut f = fs::File::create(&path_tmp).await?; f.write_all(data).await?; f.sync_all().await?; drop(f); - fs::rename(path2, path).await?; + fs::rename(path_tmp, path).await?; + + delete_on_drop.cancel(); + if let Some(to_delete) = to_delete { fs::remove_file(to_delete).await?; } @@ -749,3 +757,23 @@ async fn read_stream_to_end(mut stream: ByteStream) -> Result<Bytes, Error> { .concat() .into()) } + +struct DeleteOnDrop(Option<PathBuf>); + +impl DeleteOnDrop { + fn cancel(&mut self) { + drop(self.0.take()); + } +} + +impl Drop for DeleteOnDrop { + fn drop(&mut self) { + if let Some(path) = self.0.take() { + tokio::spawn(async move { + if let Err(e) = fs::remove_file(&path).await { + debug!("DeleteOnDrop failed for {}: {}", path.display(), e); + } + }); + } + } +} |