1use crate::epoch::Epoch;
19use crate::memtable::Row;
20use crate::pma::Pma;
21use crate::rowid::RowId;
22use std::collections::BTreeMap;
23
24type VersionKey = (RowId, Epoch);
27
28pub struct MutableRun {
31 pma: Pma<VersionKey, Row>,
32 byte_size: u64,
33}
34
35impl Default for MutableRun {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
41impl MutableRun {
42 pub fn new() -> Self {
43 Self {
44 pma: Pma::new(),
45 byte_size: 0,
46 }
47 }
48
49 pub fn insert_many(&mut self, rows: Vec<Row>) {
53 let batch: Vec<(VersionKey, Row)> = rows
54 .into_iter()
55 .map(|r| {
56 self.byte_size = self.byte_size.saturating_add(r.estimated_bytes());
57 ((r.row_id, r.committed_epoch), r)
58 })
59 .collect();
60 self.pma.extend_sorted(batch);
61 }
62
63 pub fn len(&self) -> usize {
65 self.pma.len()
66 }
67
68 pub fn is_empty(&self) -> bool {
69 self.pma.is_empty()
70 }
71
72 pub fn approx_bytes(&self) -> u64 {
74 self.byte_size
75 }
76
77 pub fn get_version(&self, row_id: RowId, snapshot_epoch: Epoch) -> Option<(Epoch, Row)> {
82 let mut best: Option<(Epoch, Row)> = None;
83 for ((rid, ep), row) in self.pma.iter() {
84 match rid.cmp(&row_id) {
85 std::cmp::Ordering::Less => continue,
86 std::cmp::Ordering::Greater => break,
87 std::cmp::Ordering::Equal => {
88 if *ep <= snapshot_epoch {
89 best = Some((*ep, row.clone()));
90 }
91 }
92 }
93 }
94 best
95 }
96
97 pub fn visible_versions(&self, snapshot_epoch: Epoch) -> Vec<Row> {
100 let mut by_row: BTreeMap<RowId, Row> = BTreeMap::new();
101 for ((rid, ep), row) in self.pma.iter() {
102 if *ep <= snapshot_epoch {
103 by_row.insert(*rid, row.clone()); }
105 }
106 by_row.into_values().collect()
107 }
108
109 pub fn drain_sorted(&mut self) -> Vec<Row> {
112 let out: Vec<Row> = self
113 .pma
114 .drain_sorted()
115 .into_iter()
116 .map(|(_, r)| r)
117 .collect();
118 self.byte_size = 0;
119 out
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126 use crate::memtable::Value;
127
128 fn row(id: u64, epoch: u64, v: i64) -> Row {
129 Row::new(RowId(id), Epoch(epoch)).with_column(1, Value::Int64(v))
130 }
131
132 fn tomb(id: u64, epoch: u64) -> Row {
133 Row {
134 row_id: RowId(id),
135 committed_epoch: Epoch(epoch),
136 columns: std::collections::HashMap::new(),
137 deleted: true,
138 }
139 }
140
141 fn int_of(r: &Row) -> i64 {
142 match r.columns.get(&1) {
143 Some(Value::Int64(x)) => *x,
144 _ => panic!("expected Int64 column"),
145 }
146 }
147
148 #[test]
149 fn get_version_returns_newest_visible() {
150 let mut mr = MutableRun::new();
151 mr.insert_many(vec![row(1, 1, 10), row(1, 3, 30), row(1, 9, 90)]);
152 assert_eq!(int_of(&mr.get_version(RowId(1), Epoch(5)).unwrap().1), 30);
154 assert_eq!(int_of(&mr.get_version(RowId(1), Epoch(9)).unwrap().1), 90);
156 assert!(mr.get_version(RowId(1), Epoch(0)).is_none());
158 assert!(mr.get_version(RowId(2), Epoch(100)).is_none());
160 }
161
162 #[test]
163 fn tombstone_is_returned_as_a_version() {
164 let mut mr = MutableRun::new();
165 mr.insert_many(vec![row(1, 1, 10), tomb(1, 2)]);
166 let v = mr.get_version(RowId(1), Epoch(5)).unwrap().1;
167 assert!(v.deleted);
168 let v0 = mr.get_version(RowId(1), Epoch(1)).unwrap().1;
170 assert!(!v0.deleted);
171 }
172
173 #[test]
174 fn visible_versions_dedups_to_newest_ascending() {
175 let mut mr = MutableRun::new();
176 mr.insert_many(vec![
177 row(3, 1, 30),
178 row(1, 1, 10),
179 row(2, 9, 20), row(1, 3, 11), row(3, 2, 31),
182 ]);
183 let out = mr.visible_versions(Epoch(5));
184 let got: Vec<(u64, i64)> = out.iter().map(|r| (r.row_id.0, int_of(r))).collect();
185 assert_eq!(got, vec![(1, 11), (3, 31)], "row 2 hidden, newest wins");
186 }
187
188 #[test]
189 fn drain_sorted_is_ascending_version_order_and_empties() {
190 let mut mr = MutableRun::new();
191 mr.insert_many(vec![row(3, 1, 0), row(1, 2, 0), row(1, 1, 0), row(2, 1, 0)]);
192 let out = mr.drain_sorted();
193 let keys: Vec<(u64, u64)> = out
194 .iter()
195 .map(|r| (r.row_id.0, r.committed_epoch.0))
196 .collect();
197 assert_eq!(keys, vec![(1, 1), (1, 2), (2, 1), (3, 1)]);
198 assert!(mr.is_empty());
199 assert_eq!(mr.approx_bytes(), 0);
200 }
201
202 #[test]
203 fn many_inserts_stay_queryable() {
204 let mut mr = MutableRun::new();
205 let mut rows = Vec::new();
206 for i in 0..500u64 {
207 rows.push(row(i, 1, i as i64));
208 }
209 mr.insert_many(rows);
210 assert_eq!(mr.len(), 500);
211 for i in 0..500u64 {
212 assert_eq!(
213 int_of(&mr.get_version(RowId(i), Epoch(1)).unwrap().1),
214 i as i64
215 );
216 }
217 assert!(mr.approx_bytes() > 0);
218 }
219}