landfill/storage/
appendonly.rs

1use std::io;
2
3use super::bytes::DiskBytes;
4use crate::{GuardedLandfill, Journal, Substructure};
5
6/// AppendOnly
7/// Since the collection can only grow, and written bytes never move in memory,
8/// it is possible to keep shared references into the stored bytes, while still
9/// concurrently appending new data.
10pub struct AppendOnly {
11    bytes: DiskBytes,
12    journal: Journal<u64>,
13}
14
15impl Substructure for AppendOnly {
16    fn init(lf: GuardedLandfill) -> io::Result<AppendOnly> {
17        let bytes = lf.substructure("bytes")?;
18        let journal = lf.substructure("journal")?;
19
20        Ok(AppendOnly { bytes, journal })
21    }
22
23    fn flush(&self) -> io::Result<()> {
24        self.bytes.flush()
25    }
26}
27
28impl AppendOnly {
29    /// Write a slice of bytes into the store returning their offset
30    pub fn write_aligned(
31        &self,
32        bytes: &[u8],
33        alignment: usize,
34    ) -> io::Result<u64> {
35        let len = bytes.len();
36
37        let write_offset = self.journal.update(|writehead| {
38            let res = DiskBytes::find_space_for(*writehead, len, alignment);
39            *writehead = res + len as u64;
40            res
41        });
42
43        let slice = unsafe { self.bytes.request_write(write_offset, len)? };
44
45        slice.copy_from_slice(bytes);
46
47        Ok(write_offset)
48    }
49
50    /// Write a slice of bytes into the store returning their offset
51    pub fn write(&self, bytes: &[u8]) -> io::Result<u64> {
52        self.write_aligned(bytes, 1)
53    }
54
55    /// Get a reference to the data at offset and length
56    pub fn get(&self, offset: u64, len: u32) -> &[u8] {
57        self.bytes
58            .read(offset, len)
59            .expect("Fatal Error: invalid offset or length!")
60    }
61}