tempest-kv 0.0.2

Key-Value storage layer for TempestDB
Documentation
use std::collections::HashSet;

use serde::{Deserialize, Serialize};
use tempest_core::journal::Replayable;

#[derive(Serialize, Deserialize)]
pub(super) enum WalDataEditV1 {
    AddFile(u64),
    RemoveFile(u64),
    Snapshot(Vec<WalDataEdit>),
}

#[repr(u8)]
#[derive(Serialize, Deserialize)]
pub(super) enum WalDataEdit {
    V1(WalDataEditV1) = 1,
}

impl WalDataEdit {
    pub(super) fn add_file(filenum: u64) -> Self {
        Self::V1(WalDataEditV1::AddFile(filenum))
    }

    pub(super) fn remove_file(filenum: u64) -> Self {
        Self::V1(WalDataEditV1::RemoveFile(filenum))
    }

    pub(super) fn snapshot(edits: Vec<Self>) -> Self {
        Self::V1(WalDataEditV1::Snapshot(edits))
    }
}

#[derive(Debug, Default)]
pub(super) struct WalData {
    pub(super) next_filenum: u64,
    pub(super) live_files: HashSet<u64>,
}

impl Replayable for WalData {
    type Edit = WalDataEdit;

    fn apply(&mut self, edit: Self::Edit) {
        match edit {
            WalDataEdit::V1(WalDataEditV1::AddFile(filenum)) => {
                self.live_files.insert(filenum);
                // NB: in the event that the file with the highest filenum could be removed at one
                // point, we must add something like SetNextFilenum(u64) to the snapshot, to
                // prevent it from decrementing, or we could have collisions between WAL and file
                // GC in the future, i.e. next_filenum goes 3->0, GC is deleting 0, but WAL tries
                // using 0, so it would race.
                self.next_filenum = self.next_filenum.max(filenum);
            }
            WalDataEdit::V1(WalDataEditV1::RemoveFile(filenum)) => {
                self.live_files.remove(&filenum);
            }
            WalDataEdit::V1(WalDataEditV1::Snapshot(snapshot)) => {
                for edit in snapshot {
                    self.apply(edit);
                }
            }
        }
    }

    fn snapshot(&self) -> Self::Edit {
        let mut edits = Vec::new();
        edits.extend(
            self.live_files
                .iter()
                .map(|n| WalDataEdit::V1(WalDataEditV1::AddFile(*n))),
        );
        WalDataEdit::snapshot(edits)
    }

    fn filename_prefix() -> &'static str {
        "wal-journal"
    }

    fn initial() -> Self {
        Self::default()
    }
}