dustdata 1.3.2

A data concurrency control storage engine to Rustbase
Documentation
use lz4::{Decoder, EncoderBuilder};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::fs;
use std::io::{Read, Write};
use std::path::PathBuf;

use crate::bloom::BloomFilter;

use super::Lsm;

#[derive(Clone, Debug)]
pub struct SnapshotManager {
    path: PathBuf,
}

impl SnapshotManager {
    pub fn new(path: PathBuf) -> Self {
        SnapshotManager { path }
    }

    pub fn load_last_snapshot(&self) -> Snapshot {
        let mut paths = fs::read_dir(&self.path).unwrap();

        let mut last_snapshot = paths.next().unwrap().unwrap().path();

        for path in paths {
            let path = path.unwrap().path();

            if path.metadata().unwrap().modified().unwrap()
                > last_snapshot.metadata().unwrap().modified().unwrap()
            {
                last_snapshot = path;
            }
        }

        let snapshot: Snapshot = Snapshot::load_snapshot(last_snapshot);

        snapshot
    }

    pub fn load_snapshot_by_index(&self, index: usize) -> Snapshot {
        let mut paths = fs::read_dir(&self.path).unwrap();

        let snapshot = paths.nth(index).unwrap().unwrap().path();

        let snapshot: Snapshot = Snapshot::load_snapshot(snapshot);

        snapshot
    }
}

#[derive(Clone, Serialize, Deserialize)]
pub struct Snapshot {
    pub memtable: BTreeMap<String, bson::Bson>,
    pub bloom_filter: BloomFilter,
    pub dense_index: HashMap<String, String>,
}

impl Snapshot {
    pub fn new(
        memtable: BTreeMap<String, bson::Bson>,
        bloom_filter: BloomFilter,
        dense_index: HashMap<String, String>,
    ) -> Snapshot {
        Snapshot {
            memtable,
            bloom_filter,
            dense_index,
        }
    }

    pub fn load_snapshot(path: PathBuf) -> Snapshot {
        let file = fs::File::open(path).unwrap();

        let mut decoder = Decoder::new(file).unwrap();
        let mut contents = Vec::new();
        decoder.read_to_end(&mut contents).unwrap();
        let snapshot: Snapshot = bson::from_slice(&contents).unwrap();

        snapshot
    }

    pub fn create_snapshot(lsm: &Lsm, path: PathBuf) -> String {
        if !path.exists() {
            std::fs::create_dir_all(path.clone()).unwrap();
        }

        let snapshot = Snapshot::new(
            lsm.memtable.read().unwrap().clone(),
            lsm.bloom_filter.read().unwrap().clone(),
            lsm.dense_index.read().unwrap().clone(),
        );

        let now = chrono::Local::now();
        let timestamp = now.format("%Y-%m-%d-%H-%M-%S").to_string();

        let snapshot_path = path.join(timestamp.clone());
        let file = fs::File::create(snapshot_path).unwrap();

        let snapshot = bson::to_vec(&snapshot).unwrap();

        let mut encoder = EncoderBuilder::new()
            .build(file)
            .expect("cannot create encoder");

        encoder.write_all(&snapshot).unwrap();
        encoder.flush().unwrap();

        timestamp
    }

    pub fn get_memtable(&self) -> &BTreeMap<String, bson::Bson> {
        &self.memtable
    }

    pub fn get_bloom_filter(&self) -> &BloomFilter {
        &self.bloom_filter
    }

    pub fn get_dense_index(&self) -> &HashMap<String, String> {
        &self.dense_index
    }

    pub fn timestamp(&self) -> String {
        let now = chrono::Local::now();
        now.format("%Y-%m-%d-%H-%M-%S").to_string()
    }
}