spacedb_store/
mem_engine.rs1use std::collections::BTreeMap;
16use std::ops::Bound;
17use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
18
19use crate::engine::{Durability, KvEngine, ReadTx, Readable, WriteTx};
20use crate::error::{StoreError, StoreResult};
21
22type Table = BTreeMap<Vec<u8>, Vec<u8>>;
23type Tables = BTreeMap<String, Table>;
24
25#[derive(Default)]
27pub struct MemEngine {
28 tables: RwLock<Tables>,
29}
30
31impl MemEngine {
32 pub fn new() -> Self {
33 Self::default()
34 }
35}
36
37fn poisoned() -> StoreError {
38 StoreError::engine("in-memory lock poisoned")
39}
40
41fn range_table(table: &Table, lo: &[u8], hi: &[u8]) -> Vec<(Vec<u8>, Vec<u8>)> {
43 table
44 .range::<[u8], _>((Bound::Included(lo), Bound::Excluded(hi)))
45 .map(|(k, v)| (k.clone(), v.clone()))
46 .collect()
47}
48
49pub struct MemReadTx<'a> {
53 guard: RwLockReadGuard<'a, Tables>,
54}
55
56impl Readable for MemReadTx<'_> {
57 fn get_raw(&self, table: &str, key: &[u8]) -> StoreResult<Option<Vec<u8>>> {
58 Ok(self.guard.get(table).and_then(|t| t.get(key).cloned()))
59 }
60
61 fn range_raw(&self, table: &str, lo: &[u8], hi: &[u8]) -> StoreResult<Vec<(Vec<u8>, Vec<u8>)>> {
62 Ok(self
63 .guard
64 .get(table)
65 .map(|t| range_table(t, lo, hi))
66 .unwrap_or_default())
67 }
68}
69
70impl ReadTx for MemReadTx<'_> {}
71
72type Overlay = BTreeMap<String, BTreeMap<Vec<u8>, Option<Vec<u8>>>>;
76
77pub struct MemWriteTx<'a> {
80 base: RwLockWriteGuard<'a, Tables>,
81 overlay: Overlay,
82 _durability: Durability,
83}
84
85impl Readable for MemWriteTx<'_> {
86 fn get_raw(&self, table: &str, key: &[u8]) -> StoreResult<Option<Vec<u8>>> {
87 if let Some(t) = self.overlay.get(table) {
89 if let Some(slot) = t.get(key) {
90 return Ok(slot.clone());
91 }
92 }
93 Ok(self.base.get(table).and_then(|t| t.get(key).cloned()))
94 }
95
96 fn range_raw(&self, table: &str, lo: &[u8], hi: &[u8]) -> StoreResult<Vec<(Vec<u8>, Vec<u8>)>> {
97 let mut merged: BTreeMap<Vec<u8>, Vec<u8>> = self
100 .base
101 .get(table)
102 .map(|t| range_table(t, lo, hi).into_iter().collect())
103 .unwrap_or_default();
104 if let Some(t) = self.overlay.get(table) {
105 for (k, slot) in t.range::<[u8], _>((Bound::Included(lo), Bound::Excluded(hi))) {
106 match slot {
107 Some(v) => {
108 merged.insert(k.clone(), v.clone());
109 }
110 None => {
111 merged.remove(k);
112 }
113 }
114 }
115 }
116 Ok(merged.into_iter().collect())
117 }
118}
119
120impl WriteTx for MemWriteTx<'_> {
121 fn put_raw(&mut self, table: &str, key: &[u8], val: &[u8]) -> StoreResult<()> {
122 self.overlay
123 .entry(table.to_string())
124 .or_default()
125 .insert(key.to_vec(), Some(val.to_vec()));
126 Ok(())
127 }
128
129 fn delete_raw(&mut self, table: &str, key: &[u8]) -> StoreResult<bool> {
130 let existed = self.get_raw(table, key)?.is_some();
131 self.overlay
132 .entry(table.to_string())
133 .or_default()
134 .insert(key.to_vec(), None);
135 Ok(existed)
136 }
137
138 fn commit(mut self) -> StoreResult<()> {
139 let overlay = std::mem::take(&mut self.overlay);
142 for (table, edits) in overlay {
143 let t = self.base.entry(table).or_default();
144 for (key, slot) in edits {
145 match slot {
146 Some(v) => {
147 t.insert(key, v);
148 }
149 None => {
150 t.remove(&key);
151 }
152 }
153 }
154 }
155 Ok(())
156 }
157}
158
159impl KvEngine for MemEngine {
162 type RTx<'a> = MemReadTx<'a>;
163 type WTx<'a> = MemWriteTx<'a>;
164
165 fn begin_read(&self) -> StoreResult<Self::RTx<'_>> {
166 let guard = self.tables.read().map_err(|_| poisoned())?;
167 Ok(MemReadTx { guard })
168 }
169
170 fn begin_write(&self, durability: Durability) -> StoreResult<Self::WTx<'_>> {
171 let base = self.tables.write().map_err(|_| poisoned())?;
172 Ok(MemWriteTx {
173 base,
174 overlay: Overlay::new(),
175 _durability: durability,
176 })
177 }
178}