use std::fs;
use std::io::Write;
use std::path::Path;
use std::sync::atomic::{AtomicU64, Ordering};
use super::{RdbFileError, RdbFileResult};
pub(super) fn write_physical_metadata_bytes_atomically(
path: &Path,
bytes: &[u8],
) -> RdbFileResult<()> {
static NEXT_TEMP_SEQUENCE: AtomicU64 = AtomicU64::new(0);
let mut name = path
.file_name()
.ok_or_else(|| {
RdbFileError::InvalidOperation(format!(
"metadata path has no file name: {}",
path.display()
))
})?
.to_os_string();
name.push(format!(
".{}.{}.tmp",
std::process::id(),
NEXT_TEMP_SEQUENCE.fetch_add(1, Ordering::Relaxed)
));
let temp_path = path.with_file_name(name);
let mut file = fs::OpenOptions::new()
.create_new(true)
.write(true)
.open(&temp_path)?;
let result = (|| -> std::io::Result<()> {
file.write_all(bytes)?;
file.sync_all()?;
drop(file);
fs::rename(&temp_path, path)?;
#[cfg(unix)]
{
let parent = path
.parent()
.filter(|parent| !parent.as_os_str().is_empty())
.unwrap_or(Path::new("."));
fs::File::open(parent)?.sync_all()?;
}
Ok(())
})();
if result.is_err() {
let _ = fs::remove_file(&temp_path);
}
result.map_err(Into::into)
}