1use crate::epoch::Epoch;
19use crate::memtable::Row;
20use crate::pma::Pma;
21use crate::rowid::RowId;
22use std::collections::BTreeMap;
23use std::sync::Arc;
24
25type VersionKey = (RowId, Epoch);
28
29#[derive(Clone)]
32struct MutableRunSegment {
33 pma: Pma<VersionKey, Row>,
34 byte_size: u64,
35}
36
37#[derive(Clone)]
38pub struct MutableRun {
39 frozen: Arc<Vec<Arc<MutableRunSegment>>>,
40 active: MutableRunSegment,
41 byte_size: u64,
42}
43
44impl Default for MutableRun {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl MutableRun {
51 pub fn new() -> Self {
52 Self {
53 frozen: Arc::new(Vec::new()),
54 active: MutableRunSegment {
55 pma: Pma::new(),
56 byte_size: 0,
57 },
58 byte_size: 0,
59 }
60 }
61
62 pub fn insert_many(&mut self, rows: Vec<Row>) {
66 let batch: Vec<(VersionKey, Row)> = rows
67 .into_iter()
68 .map(|r| {
69 let bytes = r.estimated_bytes();
70 self.byte_size = self.byte_size.saturating_add(bytes);
71 self.active.byte_size = self.active.byte_size.saturating_add(bytes);
72 ((r.row_id, r.committed_epoch), r)
73 })
74 .collect();
75 self.active.pma.extend_sorted(batch);
76 }
77
78 pub fn len(&self) -> usize {
80 self.active.pma.len()
81 + self
82 .frozen
83 .iter()
84 .map(|segment| segment.pma.len())
85 .sum::<usize>()
86 }
87
88 pub fn is_empty(&self) -> bool {
89 self.active.pma.is_empty() && self.frozen.is_empty()
90 }
91
92 pub fn approx_bytes(&self) -> u64 {
94 self.byte_size
95 }
96
97 pub fn get_version(&self, row_id: RowId, snapshot_epoch: Epoch) -> Option<(Epoch, Row)> {
102 let mut best: Option<(Epoch, Row)> = None;
103 for pma in self
104 .frozen
105 .iter()
106 .map(|segment| &segment.pma)
107 .chain(std::iter::once(&self.active.pma))
108 {
109 for ((rid, epoch), row) in pma.iter_from(&(row_id, Epoch::ZERO)) {
110 if *rid != row_id {
111 break;
112 }
113 if *epoch <= snapshot_epoch
114 && best.as_ref().is_none_or(|(current, _)| *epoch > *current)
115 {
116 best = Some((*epoch, row.clone()));
117 }
118 }
119 }
120 best
121 }
122
123 pub fn visible_versions(&self, snapshot_epoch: Epoch) -> Vec<Row> {
126 let mut by_row: BTreeMap<RowId, Row> = BTreeMap::new();
127 for pma in self
128 .frozen
129 .iter()
130 .map(|segment| &segment.pma)
131 .chain(std::iter::once(&self.active.pma))
132 {
133 for ((rid, epoch), row) in pma.iter() {
134 if *epoch <= snapshot_epoch
135 && by_row
136 .get(rid)
137 .is_none_or(|current| *epoch > current.committed_epoch)
138 {
139 by_row.insert(*rid, row.clone());
140 }
141 }
142 }
143 by_row.into_values().collect()
144 }
145
146 pub(crate) fn seal(&mut self) {
147 if self.active.pma.is_empty() {
148 return;
149 }
150 let active = std::mem::replace(
151 &mut self.active,
152 MutableRunSegment {
153 pma: Pma::new(),
154 byte_size: 0,
155 },
156 );
157 Arc::make_mut(&mut self.frozen).push(Arc::new(active));
158 if self.frozen.len() >= crate::MAX_READ_GENERATION_LAYERS {
159 self.consolidate();
160 }
161 }
162
163 fn consolidate(&mut self) {
164 let mut rows = self
165 .frozen
166 .iter()
167 .flat_map(|segment| segment.pma.iter().map(|(_, row)| row.clone()))
168 .collect::<Vec<_>>();
169 rows.sort_by_key(|row| (row.row_id, row.committed_epoch));
170 let mut pma = Pma::new();
171 pma.extend_sorted(
172 rows.into_iter()
173 .map(|row| ((row.row_id, row.committed_epoch), row))
174 .collect(),
175 );
176 self.frozen = Arc::new(vec![Arc::new(MutableRunSegment {
177 pma,
178 byte_size: self.byte_size,
179 })]);
180 }
181
182 #[cfg(test)]
183 pub(crate) fn frozen_layer_count(&self) -> usize {
184 self.frozen.len()
185 }
186
187 pub fn drain_sorted(&mut self) -> Vec<Row> {
190 let mut out = self
191 .frozen
192 .iter()
193 .flat_map(|segment| segment.pma.iter().map(|(_, row)| row.clone()))
194 .chain(self.active.pma.iter().map(|(_, row)| row.clone()))
195 .collect::<Vec<_>>();
196 out.sort_by_key(|row| (row.row_id, row.committed_epoch));
197 self.frozen = Arc::new(Vec::new());
198 self.active = MutableRunSegment {
199 pma: Pma::new(),
200 byte_size: 0,
201 };
202 self.byte_size = 0;
203 out
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 use crate::memtable::Value;
211
212 fn row(id: u64, epoch: u64, v: i64) -> Row {
213 Row::new(RowId(id), Epoch(epoch)).with_column(1, Value::Int64(v))
214 }
215
216 fn tomb(id: u64, epoch: u64) -> Row {
217 Row {
218 row_id: RowId(id),
219 committed_epoch: Epoch(epoch),
220 columns: std::collections::HashMap::new(),
221 deleted: true,
222 }
223 }
224
225 fn int_of(r: &Row) -> i64 {
226 match r.columns.get(&1) {
227 Some(Value::Int64(x)) => *x,
228 _ => panic!("expected Int64 column"),
229 }
230 }
231
232 #[test]
233 fn get_version_returns_newest_visible() {
234 let mut mr = MutableRun::new();
235 mr.insert_many(vec![row(1, 1, 10), row(1, 3, 30), row(1, 9, 90)]);
236 assert_eq!(int_of(&mr.get_version(RowId(1), Epoch(5)).unwrap().1), 30);
238 assert_eq!(int_of(&mr.get_version(RowId(1), Epoch(9)).unwrap().1), 90);
240 assert!(mr.get_version(RowId(1), Epoch(0)).is_none());
242 assert!(mr.get_version(RowId(2), Epoch(100)).is_none());
244 }
245
246 #[test]
247 fn tombstone_is_returned_as_a_version() {
248 let mut mr = MutableRun::new();
249 mr.insert_many(vec![row(1, 1, 10), tomb(1, 2)]);
250 let v = mr.get_version(RowId(1), Epoch(5)).unwrap().1;
251 assert!(v.deleted);
252 let v0 = mr.get_version(RowId(1), Epoch(1)).unwrap().1;
254 assert!(!v0.deleted);
255 }
256
257 #[test]
258 fn sealed_generations_share_rows_and_consolidate() {
259 let mut writer = MutableRun::new();
260 for id in 0..crate::MAX_READ_GENERATION_LAYERS as u64 + 2 {
261 writer.insert_many(vec![row(id, id + 1, id as i64)]);
262 writer.seal();
263 }
264 assert!(writer.frozen_layer_count() < crate::MAX_READ_GENERATION_LAYERS);
265 let generation = writer.clone();
266 writer.insert_many(vec![row(99, 99, 99)]);
267 assert!(generation.get_version(RowId(99), Epoch(99)).is_none());
268 assert!(writer.get_version(RowId(99), Epoch(99)).is_some());
269 }
270
271 #[test]
272 fn visible_versions_dedups_to_newest_ascending() {
273 let mut mr = MutableRun::new();
274 mr.insert_many(vec![
275 row(3, 1, 30),
276 row(1, 1, 10),
277 row(2, 9, 20), row(1, 3, 11), row(3, 2, 31),
280 ]);
281 let out = mr.visible_versions(Epoch(5));
282 let got: Vec<(u64, i64)> = out.iter().map(|r| (r.row_id.0, int_of(r))).collect();
283 assert_eq!(got, vec![(1, 11), (3, 31)], "row 2 hidden, newest wins");
284 }
285
286 #[test]
287 fn drain_sorted_is_ascending_version_order_and_empties() {
288 let mut mr = MutableRun::new();
289 mr.insert_many(vec![row(3, 1, 0), row(1, 2, 0), row(1, 1, 0), row(2, 1, 0)]);
290 let out = mr.drain_sorted();
291 let keys: Vec<(u64, u64)> = out
292 .iter()
293 .map(|r| (r.row_id.0, r.committed_epoch.0))
294 .collect();
295 assert_eq!(keys, vec![(1, 1), (1, 2), (2, 1), (3, 1)]);
296 assert!(mr.is_empty());
297 assert_eq!(mr.approx_bytes(), 0);
298 }
299
300 #[test]
301 fn many_inserts_stay_queryable() {
302 let mut mr = MutableRun::new();
303 let mut rows = Vec::new();
304 for i in 0..500u64 {
305 rows.push(row(i, 1, i as i64));
306 }
307 mr.insert_many(rows);
308 assert_eq!(mr.len(), 500);
309 for i in 0..500u64 {
310 assert_eq!(
311 int_of(&mr.get_version(RowId(i), Epoch(1)).unwrap().1),
312 i as i64
313 );
314 }
315 assert!(mr.approx_bytes() > 0);
316 }
317}