wasmer_journal/concrete/
mem_file.rs

1use std::{
2    fs::File,
3    io::{Seek, Write},
4    path::Path,
5    sync::RwLock,
6};
7
8use lz4_flex::{block, decompress};
9
10use super::*;
11
12/// The memory file journal processes journal entries by writing any memory mutations
13/// directly to a file. Later this can be used as a mounting target for resuming
14/// a process without having to reload the journal from scratch.
15#[derive(Debug)]
16pub struct MemFileJournal {
17    file: RwLock<File>,
18}
19
20impl MemFileJournal {
21    pub fn new(path: &Path) -> anyhow::Result<Self> {
22        Ok(Self {
23            file: RwLock::new(
24                std::fs::OpenOptions::new()
25                    .create(true)
26                    .truncate(false)
27                    .write(true)
28                    .open(path)?,
29            ),
30        })
31    }
32}
33
34impl Drop for MemFileJournal {
35    fn drop(&mut self) {
36        let _ = self.flush();
37    }
38}
39
40impl Clone for MemFileJournal {
41    fn clone(&self) -> Self {
42        let file = self.file.read().unwrap();
43        Self {
44            file: RwLock::new(file.try_clone().unwrap()),
45        }
46    }
47}
48
49impl ReadableJournal for MemFileJournal {
50    fn read(&self) -> anyhow::Result<Option<LogReadResult<'_>>> {
51        Ok(None)
52    }
53
54    fn as_restarted(&self) -> anyhow::Result<Box<DynReadableJournal>> {
55        Ok(Box::new(self.clone()))
56    }
57}
58
59impl WritableJournal for MemFileJournal {
60    fn write<'a>(&'a self, entry: JournalEntry<'a>) -> anyhow::Result<LogWriteResult> {
61        let estimated_size = entry.estimate_size() as u64;
62        match entry {
63            JournalEntry::UpdateMemoryRegionV1 {
64                region,
65                compressed_data,
66            } => {
67                let (uncompressed_size, compressed_data) =
68                    block::uncompressed_size(&compressed_data)?;
69                let decompressed_data = decompress(compressed_data, uncompressed_size)?;
70
71                let mut file = self.file.write().unwrap();
72                file.seek(std::io::SeekFrom::Start(region.start))?;
73                file.write_all(&decompressed_data)?;
74            }
75            JournalEntry::ProcessExitV1 { .. } | JournalEntry::InitModuleV1 { .. } => {
76                let file = self.file.read().unwrap();
77                file.set_len(0)?;
78            }
79            _ => {}
80        }
81
82        Ok(LogWriteResult {
83            record_start: 0,
84            record_end: estimated_size,
85        })
86    }
87
88    fn flush(&self) -> anyhow::Result<()> {
89        let mut file = self.file.write().unwrap();
90        file.flush()?;
91        Ok(())
92    }
93}
94
95impl Journal for MemFileJournal {
96    fn split(self) -> (Box<DynWritableJournal>, Box<DynReadableJournal>) {
97        (Box::new(self.clone()), Box::new(self.clone()))
98    }
99}