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_from(&(row_id, Epoch::ZERO)) {
84 if *rid != row_id {
85 break;
86 }
87 if *ep <= snapshot_epoch {
88 best = Some((*ep, row.clone()));
89 }
90 }
91 best
92 }
93
94 pub fn visible_versions(&self, snapshot_epoch: Epoch) -> Vec<Row> {
97 let mut by_row: BTreeMap<RowId, Row> = BTreeMap::new();
98 for ((rid, ep), row) in self.pma.iter() {
99 if *ep <= snapshot_epoch {
100 by_row.insert(*rid, row.clone()); }
102 }
103 by_row.into_values().collect()
104 }
105
106 pub fn drain_sorted(&mut self) -> Vec<Row> {
109 let out: Vec<Row> = self
110 .pma
111 .drain_sorted()
112 .into_iter()
113 .map(|(_, r)| r)
114 .collect();
115 self.byte_size = 0;
116 out
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::memtable::Value;
124
125 fn row(id: u64, epoch: u64, v: i64) -> Row {
126 Row::new(RowId(id), Epoch(epoch)).with_column(1, Value::Int64(v))
127 }
128
129 fn tomb(id: u64, epoch: u64) -> Row {
130 Row {
131 row_id: RowId(id),
132 committed_epoch: Epoch(epoch),
133 columns: std::collections::HashMap::new(),
134 deleted: true,
135 }
136 }
137
138 fn int_of(r: &Row) -> i64 {
139 match r.columns.get(&1) {
140 Some(Value::Int64(x)) => *x,
141 _ => panic!("expected Int64 column"),
142 }
143 }
144
145 #[test]
146 fn get_version_returns_newest_visible() {
147 let mut mr = MutableRun::new();
148 mr.insert_many(vec![row(1, 1, 10), row(1, 3, 30), row(1, 9, 90)]);
149 assert_eq!(int_of(&mr.get_version(RowId(1), Epoch(5)).unwrap().1), 30);
151 assert_eq!(int_of(&mr.get_version(RowId(1), Epoch(9)).unwrap().1), 90);
153 assert!(mr.get_version(RowId(1), Epoch(0)).is_none());
155 assert!(mr.get_version(RowId(2), Epoch(100)).is_none());
157 }
158
159 #[test]
160 fn tombstone_is_returned_as_a_version() {
161 let mut mr = MutableRun::new();
162 mr.insert_many(vec![row(1, 1, 10), tomb(1, 2)]);
163 let v = mr.get_version(RowId(1), Epoch(5)).unwrap().1;
164 assert!(v.deleted);
165 let v0 = mr.get_version(RowId(1), Epoch(1)).unwrap().1;
167 assert!(!v0.deleted);
168 }
169
170 #[test]
171 fn visible_versions_dedups_to_newest_ascending() {
172 let mut mr = MutableRun::new();
173 mr.insert_many(vec![
174 row(3, 1, 30),
175 row(1, 1, 10),
176 row(2, 9, 20), row(1, 3, 11), row(3, 2, 31),
179 ]);
180 let out = mr.visible_versions(Epoch(5));
181 let got: Vec<(u64, i64)> = out.iter().map(|r| (r.row_id.0, int_of(r))).collect();
182 assert_eq!(got, vec![(1, 11), (3, 31)], "row 2 hidden, newest wins");
183 }
184
185 #[test]
186 fn drain_sorted_is_ascending_version_order_and_empties() {
187 let mut mr = MutableRun::new();
188 mr.insert_many(vec![row(3, 1, 0), row(1, 2, 0), row(1, 1, 0), row(2, 1, 0)]);
189 let out = mr.drain_sorted();
190 let keys: Vec<(u64, u64)> = out
191 .iter()
192 .map(|r| (r.row_id.0, r.committed_epoch.0))
193 .collect();
194 assert_eq!(keys, vec![(1, 1), (1, 2), (2, 1), (3, 1)]);
195 assert!(mr.is_empty());
196 assert_eq!(mr.approx_bytes(), 0);
197 }
198
199 #[test]
200 fn many_inserts_stay_queryable() {
201 let mut mr = MutableRun::new();
202 let mut rows = Vec::new();
203 for i in 0..500u64 {
204 rows.push(row(i, 1, i as i64));
205 }
206 mr.insert_many(rows);
207 assert_eq!(mr.len(), 500);
208 for i in 0..500u64 {
209 assert_eq!(
210 int_of(&mr.get_version(RowId(i), Epoch(1)).unwrap().1),
211 i as i64
212 );
213 }
214 assert!(mr.approx_bytes() > 0);
215 }
216}