use std::{
fs::File,
io::{Seek, Write},
path::Path,
sync::RwLock,
};
use lz4_flex::{block, decompress};
use super::*;
#[derive(Debug)]
pub struct MemFileJournal {
file: RwLock<File>,
}
impl MemFileJournal {
pub fn new(path: &Path) -> anyhow::Result<Self> {
Ok(Self {
file: RwLock::new(
std::fs::OpenOptions::new()
.create(true)
.write(true)
.open(path)?,
),
})
}
}
impl Drop for MemFileJournal {
fn drop(&mut self) {
let _ = self.flush();
}
}
impl Clone for MemFileJournal {
fn clone(&self) -> Self {
let file = self.file.read().unwrap();
Self {
file: RwLock::new(file.try_clone().unwrap()),
}
}
}
impl ReadableJournal for MemFileJournal {
fn read(&self) -> anyhow::Result<Option<LogReadResult<'_>>> {
Ok(None)
}
fn as_restarted(&self) -> anyhow::Result<Box<DynReadableJournal>> {
Ok(Box::new(self.clone()))
}
}
impl WritableJournal for MemFileJournal {
fn write<'a>(&'a self, entry: JournalEntry<'a>) -> anyhow::Result<LogWriteResult> {
let estimated_size = entry.estimate_size() as u64;
match entry {
JournalEntry::UpdateMemoryRegionV1 {
region,
compressed_data,
} => {
let (uncompressed_size, compressed_data) =
block::uncompressed_size(&compressed_data)?;
let decompressed_data = decompress(compressed_data, uncompressed_size)?;
let mut file = self.file.write().unwrap();
file.seek(std::io::SeekFrom::Start(region.start))?;
file.write_all(&decompressed_data)?;
}
JournalEntry::ProcessExitV1 { .. } | JournalEntry::InitModuleV1 { .. } => {
let file = self.file.read().unwrap();
file.set_len(0)?;
}
_ => {}
}
Ok(LogWriteResult {
record_start: 0,
record_end: estimated_size,
})
}
fn flush(&self) -> anyhow::Result<()> {
let mut file = self.file.write().unwrap();
file.flush()?;
Ok(())
}
}
impl Journal for MemFileJournal {
fn split(self) -> (Box<DynWritableJournal>, Box<DynReadableJournal>) {
(Box::new(self.clone()), Box::new(self.clone()))
}
}