use std::io::{BufWriter, Write};
use std::path::Path;
use crate::error::{Error, Result};
pub(crate) fn open_wal_writer(wal_path: &Path, context: &str) -> Result<BufWriter<std::fs::File>> {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(wal_path)
.map_err(|e| Error::Index(format!("{context} open: {e}")))?;
Ok(BufWriter::new(file))
}
pub(crate) fn wal_write(
w: &mut BufWriter<std::fs::File>,
bytes: &[u8],
context: &str,
) -> Result<()> {
w.write_all(bytes)
.map_err(|e| Error::Index(format!("{context} write: {e}")))
}
pub(crate) fn flush_wal(w: &mut BufWriter<std::fs::File>, context: &str) -> Result<()> {
w.flush()
.map_err(|e| Error::Index(format!("{context} flush: {e}")))?;
w.get_ref()
.sync_all()
.map_err(|e| Error::Index(format!("{context} fsync: {e}")))
}
pub(crate) fn wal_truncate(wal_path: &Path, context: &str) -> Result<()> {
if !wal_path.exists() {
return Ok(());
}
let file = std::fs::OpenOptions::new()
.write(true)
.open(wal_path)
.map_err(|e| Error::Index(format!("{context} truncate open: {e}")))?;
file.set_len(0)
.map_err(|e| Error::Index(format!("{context} truncate: {e}")))
}
pub(crate) fn read_entry_header(data: &[u8], pos: usize, context: &str) -> Option<(usize, usize)> {
if pos + 4 > data.len() {
tracing::warn!("{context} truncated at offset {pos}: not enough bytes for length prefix");
return None;
}
let bytes: [u8; 4] = data[pos..pos + 4].try_into().ok()?;
let body_len = u32::from_le_bytes(bytes) as usize;
Some((pos + 4, body_len))
}