use std::path::PathBuf;
use crate::error::{StorageError, io_err};
use super::barrier::Barrier;
use super::ledger::JsonlLedger;
impl JsonlLedger {
pub(crate) fn write_wave(
&mut self,
writes: &[(PathBuf, Vec<u8>)],
created: Vec<PathBuf>,
) -> Result<(), StorageError> {
let written = self.land(writes, &created);
if written.is_err() {
self.pending_unwind = Some(created);
if let Err(unwind) = self.finish_unwind() {
eprintln!("the ledger tail is restored before the next wave instead: {unwind}");
}
}
written
}
pub(crate) fn finish_unwind(&mut self) -> Result<(), StorageError> {
let Some(created) = self.pending_unwind.take() else {
return Ok(());
};
match self.restore(&created) {
Ok(()) => {
self.barrier = Barrier::Whole;
Ok(())
}
Err(error) => {
self.pending_unwind = Some(created);
Err(error)
}
}
}
fn land(
&mut self,
writes: &[(PathBuf, Vec<u8>)],
created: &[PathBuf],
) -> Result<(), StorageError> {
for (path, bytes) in writes {
self.vfs
.append(path, bytes)
.map_err(io_err("append event line", path))?;
}
for (path, _) in writes {
self.vfs
.sync_data(path)
.map_err(io_err("sync segment", path))?;
}
if !created.is_empty() {
self.vfs
.sync_dir(&self.dir)
.map_err(io_err("sync ledger dir", &self.dir))?;
}
Ok(())
}
fn restore(&mut self, created: &[PathBuf]) -> Result<(), StorageError> {
for path in created {
if self.vfs.exists(path) {
self.vfs
.remove_file(path)
.map_err(io_err("remove a segment the failed wave created", path))?;
}
}
if !created.contains(&self.seg_path) {
self.vfs
.truncate(&self.seg_path, self.seg_len)
.map_err(io_err(
"truncate a segment back before the failed wave",
&self.seg_path,
))?;
}
Ok(())
}
}
#[cfg(test)]
#[path = "unwind/tests.rs"]
mod tests;