1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use std::collections::BTreeMap;
use bson::{Document, DateTime};
use bson::oid::ObjectId;
use anyhow::{anyhow, Result};

use crate::storage::record::*;
use crate::storage::sstable::*;


/// The in-memory buffer for an LSM Tree.
/// 
/// This buffer is comprised of a red-black tree of records, sorted by key.
pub struct MemTable {
    pub records: BTreeMap<ObjectId, Value<Document>>,
}

impl MemTable {
    /// Creates a new MemTable.
    pub fn new() -> Self {
        Self::default()
    }

    pub fn insert(&mut self, key: ObjectId, value: Value<Document>) {
        self.records.insert(key, value);
    }

    pub fn set(&mut self, key: ObjectId, doc: Document) {
        self.insert(key, Value::Data(doc));
    }

    pub fn del(&mut self, key: ObjectId) {
        self.insert(key, Value::Tombstone);
    }

    pub fn get(&self, key: ObjectId) -> Option<Value<Document>> {
        self.records
            .get(&key)
            .map(|value| value.clone())
    }

    /// Flushes the contents of the MemTable to disk, returning an SSTable.
    pub fn flush(&mut self) -> Result<SSTable> {
        // Create a vector of records from the BTreeMap...
        let records: Vec<_> = self.records
            .iter()
            .map(|(key, value)| {
                Record {
                    key: *key,
                    value: value.clone(),
                }
            })
            .collect();

        // Get the min/max keys and count from the records...
        let min_key = records
            .first()
            .ok_or(anyhow!("records vec was empty"))?
            .key;
        let max_key = records
            .last()
            .ok_or(anyhow!("records vec was empty"))?
            .key;
        let num_records = records.len();
        let meta = SSTableMeta {
            id: ObjectId::new(),
            created_at: DateTime::now(),
            min_key,
            max_key,
            num_records,
        };

        // Create and return!
        Ok(SSTable {
            meta,
            records,
        })
    }
}

impl Default for MemTable {
    fn default() -> Self {
        MemTable {
            records: BTreeMap::new(),
        }
    }
}


#[cfg(test)]
mod test {
    use super::*;
    use bson::doc;

    #[test]
    fn create() {
        let _mt = MemTable::new();
    }

    #[test]
    fn set_and_get() {
        // Define a key/value pair to add to the memtable...
        let k = ObjectId::new();
        let v = doc! {
            "msg": "Hello, World!",
            "num": 42,
            "skyIsBlue": true,
        };
        let exp = Some(Value::Data(v.clone()));

        // Create an empty memtable...
        let mut mt = MemTable::new();

        // Add it to the memtable...
        mt.set(k, v);

        // Check that the BTree contains the key...
        assert!(mt.records.contains_key(&k), "Key doesn't exist in the btree");

        // Get the value back from the memtable...
        let res = mt.get(k);

        // Check that it matches...
        assert_eq!(res, exp);
    }

    #[test]
    fn set_del_get() {
        // Define a key/value pair to add to the memtable...
        let k = ObjectId::new();
        let v = doc! {
            "msg": "Hello, World!",
            "num": 42,
            "skyIsBlue": true,
        };

        // Create an empty memtable...
        let mut mt = MemTable::new();

        // Add it to the memtable...
        mt.set(k, v);

        // Check that the BTree contains the key...
        assert!(mt.records.contains_key(&k), "Key doesn't exist in the btree");

        // Delete the value from the memtable...
        mt.del(k);

        // Check that the key is still in the btree...
        assert!(mt.records.contains_key(&k), "Key should still exist in the btree after 'deletion'");
        
        // Check that the returned value is a tombstone...
        let res = mt.get(k);
        let exp = Some(Value::<Document>::Tombstone);
        assert_eq!(res, exp, "Expecting a present tombstone");
    }
}