1use crate::be_tree::BeTree;
13use crate::epoch::Epoch;
14use crate::rowid::RowId;
15use serde::{Deserialize, Serialize};
16use std::collections::{BTreeMap, HashMap};
17use std::sync::Arc;
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
22pub enum Value {
23 Null,
24 Bool(bool),
25 Int64(i64),
26 Float64(f64),
27 Bytes(Vec<u8>),
28 Embedding(Vec<f32>),
29 Decimal(i128),
32 Interval {
34 months: i64,
35 days: i32,
36 nanos: i64,
37 },
38 Uuid([u8; 16]),
40 Json(Vec<u8>),
42}
43
44impl Value {
45 pub fn encode_key(&self) -> Vec<u8> {
48 match self {
49 Value::Null => Vec::new(),
50 Value::Bool(b) => vec![*b as u8],
51 Value::Int64(n) => n.to_be_bytes().to_vec(),
52 Value::Float64(f) => f.to_bits().to_be_bytes().to_vec(),
53 Value::Bytes(b) => b.clone(),
54 Value::Embedding(v) => {
55 let mut out = Vec::with_capacity(v.len() * 4);
56 for x in v {
57 out.extend_from_slice(&x.to_bits().to_be_bytes());
58 }
59 out
60 }
61 Value::Decimal(d) => d.to_be_bytes().to_vec(),
62 Value::Interval {
63 months,
64 days,
65 nanos,
66 } => {
67 let mut out = Vec::with_capacity(20);
68 out.extend_from_slice(&months.to_be_bytes());
69 out.extend_from_slice(&days.to_be_bytes());
70 out.extend_from_slice(&nanos.to_be_bytes());
71 out
72 }
73 Value::Uuid(b) => b.to_vec(),
74 Value::Json(b) => b.clone(),
75 }
76 }
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct Row {
82 pub row_id: RowId,
83 pub committed_epoch: Epoch,
84 pub columns: HashMap<u16, Value>,
85 pub deleted: bool,
86}
87
88impl Row {
89 pub fn new(row_id: RowId, committed_epoch: Epoch) -> Self {
90 Self {
91 row_id,
92 committed_epoch,
93 columns: HashMap::new(),
94 deleted: false,
95 }
96 }
97
98 pub fn with_column(mut self, column_id: u16, value: Value) -> Self {
99 self.columns.insert(column_id, value);
100 self
101 }
102
103 pub fn estimated_bytes(&self) -> u64 {
105 let mut n = 32; for v in self.columns.values() {
107 n += match v {
108 Value::Null => 1,
109 Value::Bool(_) => 1,
110 Value::Int64(_) => 8,
111 Value::Float64(_) => 8,
112 Value::Bytes(b) => 16 + b.len() as u64,
113 Value::Embedding(v) => 16 + (v.len() as u64) * 4,
114 Value::Decimal(_) => 16,
115 Value::Interval { .. } => 20,
116 Value::Uuid(_) => 16,
117 Value::Json(b) => 16 + b.len() as u64,
118 };
119 }
120 n
121 }
122}
123
124#[derive(Clone)]
128struct MemtableSegment {
129 tree: BeTree,
130 byte_size: u64,
131}
132
133#[derive(Clone)]
135pub struct Memtable {
136 frozen: Arc<Vec<Arc<MemtableSegment>>>,
137 active: MemtableSegment,
138 byte_size: u64,
139}
140
141impl Default for Memtable {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146
147impl Memtable {
148 pub fn new() -> Self {
149 Self {
150 frozen: Arc::new(Vec::new()),
151 active: MemtableSegment {
152 tree: BeTree::new(),
153 byte_size: 0,
154 },
155 byte_size: 0,
156 }
157 }
158
159 pub fn upsert(&mut self, row: Row) {
162 let bytes = row.estimated_bytes();
163 self.byte_size = self.byte_size.saturating_add(bytes);
164 self.active.byte_size = self.active.byte_size.saturating_add(bytes);
165 self.active.tree.insert_row(row);
166 }
167
168 pub fn tombstone(&mut self, row_id: RowId, epoch: Epoch) {
172 let mut columns = HashMap::new();
173 if let Some(live) = self.get(row_id, Epoch(epoch.0.saturating_sub(1))) {
174 columns = live.columns;
175 }
176 let row = Row {
177 row_id,
178 committed_epoch: epoch,
179 columns,
180 deleted: true,
181 };
182 self.upsert(row);
183 }
184
185 pub fn get(&self, row_id: RowId, snapshot_epoch: Epoch) -> Option<Row> {
189 self.get_version(row_id, snapshot_epoch)
190 .and_then(|(_, row)| (!row.deleted).then_some(row))
191 }
192
193 pub fn get_version(&self, row_id: RowId, snapshot_epoch: Epoch) -> Option<(Epoch, Row)> {
197 let mut best = self.active.tree.get_version(row_id, snapshot_epoch);
198 for segment in self.frozen.iter().rev() {
199 let Some(candidate) = segment.tree.get_version(row_id, snapshot_epoch) else {
200 continue;
201 };
202 if best
203 .as_ref()
204 .map_or(true, |(epoch, _)| candidate.0 > *epoch)
205 {
206 best = Some(candidate);
207 }
208 }
209 best
210 }
211
212 pub fn len(&self) -> usize {
214 self.active.tree.mutations()
215 + self
216 .frozen
217 .iter()
218 .map(|segment| segment.tree.mutations())
219 .sum::<usize>()
220 }
221
222 pub fn is_empty(&self) -> bool {
223 self.active.tree.is_empty() && self.frozen.is_empty()
224 }
225
226 pub fn approx_bytes(&self) -> u64 {
227 self.byte_size
228 }
229
230 pub fn visible_rows(&self, snapshot_epoch: Epoch) -> Vec<Row> {
233 self.visible_versions(snapshot_epoch)
234 .into_iter()
235 .filter(|r| !r.deleted)
236 .collect()
237 }
238
239 pub fn visible_versions(&self, snapshot_epoch: Epoch) -> Vec<Row> {
243 let mut by_row: BTreeMap<RowId, Row> = BTreeMap::new();
244 for segment in self
245 .frozen
246 .iter()
247 .map(|segment| &segment.tree)
248 .chain(std::iter::once(&self.active.tree))
249 {
250 for row in segment.versions() {
251 if row.committed_epoch <= snapshot_epoch {
252 by_row
253 .entry(row.row_id)
254 .and_modify(|existing| {
255 if row.committed_epoch > existing.committed_epoch {
256 *existing = row.clone();
257 }
258 })
259 .or_insert(row);
260 }
261 }
262 }
263 by_row.into_values().collect()
264 }
265
266 pub(crate) fn seal(&mut self) {
268 if self.active.tree.is_empty() {
269 return;
270 }
271 let active = std::mem::replace(
272 &mut self.active,
273 MemtableSegment {
274 tree: BeTree::new(),
275 byte_size: 0,
276 },
277 );
278 Arc::make_mut(&mut self.frozen).push(Arc::new(active));
279 if self.frozen.len() >= crate::MAX_READ_GENERATION_LAYERS {
280 self.consolidate();
281 }
282 }
283
284 fn consolidate(&mut self) {
285 let mut tree = BeTree::new();
286 for row in self
287 .frozen
288 .iter()
289 .flat_map(|segment| segment.tree.versions())
290 {
291 tree.insert_row(row);
292 }
293 self.frozen = Arc::new(vec![Arc::new(MemtableSegment {
294 tree,
295 byte_size: self.byte_size,
296 })]);
297 }
298
299 #[cfg(test)]
300 pub(crate) fn frozen_layer_count(&self) -> usize {
301 self.frozen.len()
302 }
303
304 pub fn drain_sorted(&mut self) -> Vec<Row> {
307 let mut out = self
308 .frozen
309 .iter()
310 .flat_map(|segment| segment.tree.versions())
311 .chain(self.active.tree.versions())
312 .collect::<Vec<_>>();
313 out.sort_by_key(|row| (row.row_id, row.committed_epoch));
314 self.frozen = Arc::new(Vec::new());
315 self.active = MemtableSegment {
316 tree: BeTree::new(),
317 byte_size: 0,
318 };
319 self.byte_size = 0;
320 out
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::*;
327
328 fn row(id: u64, epoch: u64) -> Row {
329 Row::new(RowId(id), Epoch(epoch)).with_column(1, Value::Int64(id as i64 * 10))
330 }
331
332 #[test]
333 fn upsert_get_and_visibility() {
334 let mut m = Memtable::new();
335 m.upsert(row(1, 5));
336 assert_eq!(m.len(), 1);
337 assert!(m.get(RowId(1), Epoch(5)).is_some());
338 assert!(m.get(RowId(1), Epoch(4)).is_none()); assert!(m.get(RowId(2), Epoch(9)).is_none()); }
341
342 #[test]
343 fn tombstone_supersedes_at_its_epoch() {
344 let mut m = Memtable::new();
345 m.upsert(row(1, 1));
346 assert!(m.get(RowId(1), Epoch(1)).is_some());
348 m.tombstone(RowId(1), Epoch(2));
349 assert!(m.get(RowId(1), Epoch(2)).is_none());
351 assert!(m.get(RowId(1), Epoch(9)).is_none());
352 assert!(m.get(RowId(1), Epoch(1)).is_some());
354 }
355
356 #[test]
357 fn sealed_generations_share_rows_and_consolidate() {
358 let mut writer = Memtable::new();
359 for id in 0..crate::MAX_READ_GENERATION_LAYERS as u64 + 2 {
360 writer.upsert(row(id, id + 1));
361 writer.seal();
362 }
363 assert!(writer.frozen_layer_count() < crate::MAX_READ_GENERATION_LAYERS);
364 let generation = writer.clone();
365 writer.upsert(row(99, 99));
366 assert!(generation.get(RowId(99), Epoch(99)).is_none());
367 assert!(writer.get(RowId(99), Epoch(99)).is_some());
368 }
369
370 #[test]
371 fn drain_sorted_is_ascending_and_empties() {
372 let mut m = Memtable::new();
373 m.upsert(row(3, 1));
374 m.upsert(row(1, 1));
375 m.upsert(row(2, 1));
376 let out = m.drain_sorted();
377 let ids: Vec<u64> = out.iter().map(|r| r.row_id.0).collect();
378 assert_eq!(ids, vec![1, 2, 3]);
379 assert!(m.is_empty());
380 assert_eq!(m.approx_bytes(), 0);
381 }
382
383 #[test]
384 fn visible_rows_dedups_to_newest_version() {
385 let mut m = Memtable::new();
386 m.upsert(row(1, 1));
387 m.upsert(row(2, 9)); m.upsert(row(3, 1));
389 m.upsert(row(1, 3)); let ids: Vec<u64> = m
391 .visible_rows(Epoch(5))
392 .iter()
393 .map(|r| r.row_id.0)
394 .collect();
395 assert_eq!(ids, vec![1, 3]);
396 }
397}