use super::edit::{BootstrapEdit, VersionEdit, replay_edits};
use crate::fs::{Fs, FsOpenOptions, SyncMode};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
use crate::io::{Seek, SeekFrom};
use crate::path::Path;
#[cfg(feature = "std")]
use std::io::{Seek, SeekFrom};
pub fn append_edit(
fs: &dyn Fs,
path: &Path,
edit: &VersionEdit,
scratch: &mut Vec<u8>,
sync_mode: SyncMode,
) -> crate::Result<Option<u64>> {
edit.encode(scratch)?;
if scratch.len() > super::framing::MAX_FRAME_PAYLOAD as usize {
return Ok(None);
}
let mut file = fs
.open(
path,
&FsOpenOptions::new().write(true).create(true).append(true),
)
.map_err(crate::Error::from)?;
super::framing::write_frame(&mut file, scratch)?;
file.sync_all_with(sync_mode).map_err(crate::Error::from)?;
Ok(Some(
(super::framing::FRAME_HEADER_LEN + scratch.len()) as u64,
))
}
pub fn write_log(
fs: &dyn Fs,
path: &Path,
payload: &[u8],
sync_mode: SyncMode,
) -> crate::Result<u64> {
let mut file = fs
.open(
path,
&FsOpenOptions::new().write(true).create(true).truncate(true),
)
.map_err(crate::Error::from)?;
super::framing::write_frame_of_any_len(&mut file, payload)?;
file.sync_all_with(sync_mode).map_err(crate::Error::from)?;
Ok((super::framing::FRAME_HEADER_LEN + payload.len()) as u64)
}
pub fn replay_log(
fs: &dyn Fs,
path: &Path,
mode: crate::config::ManifestRecoveryMode,
bootstrap: Option<BootstrapEdit>,
) -> crate::Result<Vec<VersionEdit>> {
match fs.open(path, &FsOpenOptions::new().read(true)) {
Ok(mut file) => replay_edits(&mut file, mode, bootstrap),
Err(e) if e.kind() == crate::io::ErrorKind::NotFound => {
if bootstrap.is_some() {
return Err(crate::Error::TornManifestEditLog {
kind: "bootstrap-edit",
});
}
Ok(Vec::new())
}
Err(e) => Err(crate::Error::from(e)),
}
}
pub fn log_size(fs: &dyn Fs, path: &Path) -> crate::Result<u64> {
match fs.open(path, &FsOpenOptions::new().read(true)) {
Ok(mut file) => file.seek(SeekFrom::End(0)).map_err(crate::Error::from),
Err(e) if e.kind() == crate::io::ErrorKind::NotFound => Ok(0),
Err(e) => Err(crate::Error::from(e)),
}
}
#[cfg(test)]
#[expect(clippy::expect_used, clippy::indexing_slicing, reason = "test code")]
mod tests;