1use crate::be_tree::BeTree;
13use crate::epoch::Epoch;
14use crate::rowid::RowId;
15use serde::{Deserialize, Serialize};
16use std::collections::{BTreeMap, HashMap};
17
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21pub enum Value {
22 Null,
23 Bool(bool),
24 Int64(i64),
25 Float64(f64),
26 Bytes(Vec<u8>),
27 Embedding(Vec<f32>),
28 Decimal(i128),
31 Interval {
33 months: i64,
34 days: i32,
35 nanos: i64,
36 },
37 Uuid([u8; 16]),
39 Json(Vec<u8>),
41}
42
43impl Value {
44 pub fn encode_key(&self) -> Vec<u8> {
47 match self {
48 Value::Null => Vec::new(),
49 Value::Bool(b) => vec![*b as u8],
50 Value::Int64(n) => n.to_be_bytes().to_vec(),
51 Value::Float64(f) => f.to_bits().to_be_bytes().to_vec(),
52 Value::Bytes(b) => b.clone(),
53 Value::Embedding(v) => {
54 let mut out = Vec::with_capacity(v.len() * 4);
55 for x in v {
56 out.extend_from_slice(&x.to_bits().to_be_bytes());
57 }
58 out
59 }
60 Value::Decimal(d) => d.to_be_bytes().to_vec(),
61 Value::Interval {
62 months,
63 days,
64 nanos,
65 } => {
66 let mut out = Vec::with_capacity(20);
67 out.extend_from_slice(&months.to_be_bytes());
68 out.extend_from_slice(&days.to_be_bytes());
69 out.extend_from_slice(&nanos.to_be_bytes());
70 out
71 }
72 Value::Uuid(b) => b.to_vec(),
73 Value::Json(b) => b.clone(),
74 }
75 }
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct Row {
81 pub row_id: RowId,
82 pub committed_epoch: Epoch,
83 pub columns: HashMap<u16, Value>,
84 pub deleted: bool,
85}
86
87impl Row {
88 pub fn new(row_id: RowId, committed_epoch: Epoch) -> Self {
89 Self {
90 row_id,
91 committed_epoch,
92 columns: HashMap::new(),
93 deleted: false,
94 }
95 }
96
97 pub fn with_column(mut self, column_id: u16, value: Value) -> Self {
98 self.columns.insert(column_id, value);
99 self
100 }
101
102 pub fn estimated_bytes(&self) -> u64 {
104 let mut n = 32; for v in self.columns.values() {
106 n += match v {
107 Value::Null => 1,
108 Value::Bool(_) => 1,
109 Value::Int64(_) => 8,
110 Value::Float64(_) => 8,
111 Value::Bytes(b) => 16 + b.len() as u64,
112 Value::Embedding(v) => 16 + (v.len() as u64) * 4,
113 Value::Decimal(_) => 16,
114 Value::Interval { .. } => 20,
115 Value::Uuid(_) => 16,
116 Value::Json(b) => 16 + b.len() as u64,
117 };
118 }
119 n
120 }
121}
122
123pub struct Memtable {
127 tree: BeTree,
128 byte_size: u64,
129}
130
131impl Default for Memtable {
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137impl Memtable {
138 pub fn new() -> Self {
139 Self {
140 tree: BeTree::new(),
141 byte_size: 0,
142 }
143 }
144
145 pub fn upsert(&mut self, row: Row) {
148 self.byte_size += row.estimated_bytes();
149 self.tree.insert_row(row);
150 }
151
152 pub fn tombstone(&mut self, row_id: RowId, epoch: Epoch) {
156 let mut columns = HashMap::new();
157 if let Some(live) = self.get(row_id, Epoch(epoch.0.saturating_sub(1))) {
158 columns = live.columns;
159 }
160 let row = Row {
161 row_id,
162 committed_epoch: epoch,
163 columns,
164 deleted: true,
165 };
166 self.upsert(row);
167 }
168
169 pub fn get(&self, row_id: RowId, snapshot_epoch: Epoch) -> Option<Row> {
173 self.tree.get_visible(row_id, snapshot_epoch)
174 }
175
176 pub fn get_version(&self, row_id: RowId, snapshot_epoch: Epoch) -> Option<(Epoch, Row)> {
180 self.tree.get_version(row_id, snapshot_epoch)
181 }
182
183 pub fn len(&self) -> usize {
185 self.tree.mutations()
186 }
187
188 pub fn is_empty(&self) -> bool {
189 self.tree.is_empty()
190 }
191
192 pub fn approx_bytes(&self) -> u64 {
193 self.byte_size
194 }
195
196 pub fn visible_rows(&self, snapshot_epoch: Epoch) -> Vec<Row> {
199 self.visible_versions(snapshot_epoch)
200 .into_iter()
201 .filter(|r| !r.deleted)
202 .collect()
203 }
204
205 pub fn visible_versions(&self, snapshot_epoch: Epoch) -> Vec<Row> {
209 let mut by_row: BTreeMap<RowId, Row> = BTreeMap::new();
210 for row in self.tree.versions() {
211 if row.committed_epoch <= snapshot_epoch {
212 by_row
213 .entry(row.row_id)
214 .and_modify(|e| {
215 if row.committed_epoch > e.committed_epoch {
216 *e = row.clone();
217 }
218 })
219 .or_insert(row);
220 }
221 }
222 by_row.into_values().collect()
223 }
224
225 pub fn drain_sorted(&mut self) -> Vec<Row> {
228 let out = std::mem::take(&mut self.tree).into_sorted_rows();
229 self.byte_size = 0;
230 out
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237
238 fn row(id: u64, epoch: u64) -> Row {
239 Row::new(RowId(id), Epoch(epoch)).with_column(1, Value::Int64(id as i64 * 10))
240 }
241
242 #[test]
243 fn upsert_get_and_visibility() {
244 let mut m = Memtable::new();
245 m.upsert(row(1, 5));
246 assert_eq!(m.len(), 1);
247 assert!(m.get(RowId(1), Epoch(5)).is_some());
248 assert!(m.get(RowId(1), Epoch(4)).is_none()); assert!(m.get(RowId(2), Epoch(9)).is_none()); }
251
252 #[test]
253 fn tombstone_supersedes_at_its_epoch() {
254 let mut m = Memtable::new();
255 m.upsert(row(1, 1));
256 assert!(m.get(RowId(1), Epoch(1)).is_some());
258 m.tombstone(RowId(1), Epoch(2));
259 assert!(m.get(RowId(1), Epoch(2)).is_none());
261 assert!(m.get(RowId(1), Epoch(9)).is_none());
262 assert!(m.get(RowId(1), Epoch(1)).is_some());
264 }
265
266 #[test]
267 fn drain_sorted_is_ascending_and_empties() {
268 let mut m = Memtable::new();
269 m.upsert(row(3, 1));
270 m.upsert(row(1, 1));
271 m.upsert(row(2, 1));
272 let out = m.drain_sorted();
273 let ids: Vec<u64> = out.iter().map(|r| r.row_id.0).collect();
274 assert_eq!(ids, vec![1, 2, 3]);
275 assert!(m.is_empty());
276 assert_eq!(m.approx_bytes(), 0);
277 }
278
279 #[test]
280 fn visible_rows_dedups_to_newest_version() {
281 let mut m = Memtable::new();
282 m.upsert(row(1, 1));
283 m.upsert(row(2, 9)); m.upsert(row(3, 1));
285 m.upsert(row(1, 3)); let ids: Vec<u64> = m
287 .visible_rows(Epoch(5))
288 .iter()
289 .map(|r| r.row_id.0)
290 .collect();
291 assert_eq!(ids, vec![1, 3]);
292 }
293}