Skip to content

Commit 203fc49

Browse files
committed
libsql: offline sync use atomic write for metadata
1 parent 1692e36 commit 203fc49

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

libsql/src/sync.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
use crate::{util::ConnectorService, Result};
2+
3+
use std::path::Path;
4+
25
use bytes::Bytes;
36
use hyper::Body;
7+
use tokio::io::AsyncWriteExt as _;
8+
use uuid::Uuid;
49

510
const METADATA_VERSION: u32 = 0;
611

@@ -123,7 +128,7 @@ impl SyncContext {
123128
})
124129
.unwrap();
125130

126-
tokio::fs::write(path, contents).await.unwrap();
131+
atomic_write(path, &contents[..]).await.unwrap();
127132

128133
Ok(())
129134
}
@@ -156,3 +161,27 @@ struct MetadataJson {
156161
version: u32,
157162
durable_frame_num: u32,
158163
}
164+
165+
async fn atomic_write<P: AsRef<Path>>(path: P, data: &[u8]) -> Result<()> {
166+
// Create a temporary file in the same directory as the target file
167+
let directory = path.as_ref().parent().unwrap();
168+
169+
let temp_name = format!(".tmp.{}", Uuid::new_v4());
170+
let temp_path = directory.join(temp_name);
171+
172+
// Write data to temporary file
173+
let mut temp_file = tokio::fs::File::create(&temp_path).await.unwrap();
174+
175+
temp_file.write_all(data).await.unwrap();
176+
177+
// Ensure all data is flushed to disk
178+
temp_file.sync_all().await.unwrap();
179+
180+
// Close the file explicitly
181+
drop(temp_file);
182+
183+
// Atomically rename temporary file to target file
184+
tokio::fs::rename(&temp_path, &path).await.unwrap();
185+
186+
Ok(())
187+
}

0 commit comments

Comments
 (0)