mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-06 07:26:43 -04:00
paths: fsync after writing to a file (#4892)
As reported in #4886, `metadata.toml` can get get lost if the server crashes at an unfortunate point in time. To mitigate that, make `path_type::write` replace the file atomically, and issue `fsync` on the file and enclosing directory. # Expected complexity level and risk 1
This commit is contained in:
@@ -12,6 +12,7 @@ chrono = { workspace = true, features = ["now"] }
|
||||
fs2.workspace = true
|
||||
itoa.workspace = true
|
||||
serde.workspace = true
|
||||
tempfile.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
@@ -21,8 +22,5 @@ junction.workspace = true
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
xdg.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -162,6 +162,8 @@ mod utils;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use serde as __serde;
|
||||
#[doc(hidden)]
|
||||
pub use tempfile as __tempfile;
|
||||
|
||||
/// Implemented for path types. Use `from_path_unchecked()` to construct a strongly-typed
|
||||
/// path directly from a `PathBuf`.
|
||||
|
||||
@@ -104,8 +104,25 @@ macro_rules! path_type {
|
||||
}
|
||||
|
||||
pub fn write(&self, contents: impl AsRef<[u8]>) -> std::io::Result<()> {
|
||||
self.create_parent()?;
|
||||
std::fs::write(self, contents)
|
||||
use std::io::Write as _;
|
||||
|
||||
let path = &self.0;
|
||||
let parent = path.parent().ok_or_else(||
|
||||
std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidInput,
|
||||
format!("cannot replace {} without enclosing directory", path.display()))
|
||||
)?;
|
||||
std::fs::create_dir_all(&parent)?;
|
||||
|
||||
let mut tmp = $crate::__tempfile::NamedTempFile::new_in(parent)?;
|
||||
tmp.write_all(contents.as_ref())?;
|
||||
tmp.as_file().sync_all()?;
|
||||
tmp.persist(&path)?;
|
||||
// On Windows, syncing the directory is not necessary and doesn't even work.
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
std::fs::File::open(parent)?.sync_all()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Opens a file at this path with the given options, ensuring its parent directory exists.
|
||||
|
||||
Reference in New Issue
Block a user