mito2/memtable/
version.rs1use std::sync::Arc;
18use std::sync::atomic::{AtomicBool, Ordering};
19use std::time::Duration;
20
21use common_time::Timestamp;
22use smallvec::SmallVec;
23use store_api::metadata::RegionMetadataRef;
24use store_api::storage::SequenceNumber;
25
26use crate::error::Result;
27use crate::memtable::bulk::part::BulkPart;
28use crate::memtable::time_partition::TimePartitions;
29use crate::memtable::{KeyValues, MemtableBuilderRef, MemtableId, MemtableRef};
30
31pub(crate) type SmallMemtableVec = SmallVec<[MemtableRef; 2]>;
32
33#[derive(Debug, Clone)]
35pub(crate) struct MemtableVersion {
36 pub(crate) mutable: MutableMemtablesRef,
38 immutables: SmallMemtableVec,
44 immutable_has_skip_wal_writes: bool,
47}
48
49pub(crate) type MemtableVersionRef = Arc<MemtableVersion>;
50
51impl MemtableVersion {
52 pub(crate) fn new(mutable: TimePartitions) -> MemtableVersion {
54 MemtableVersion {
55 mutable: Arc::new(MutableMemtables::new(mutable)),
56 immutables: SmallVec::new(),
57 immutable_has_skip_wal_writes: false,
58 }
59 }
60
61 pub(crate) fn has_skip_wal_writes(&self) -> bool {
63 self.mutable.has_skip_wal_writes() || self.immutable_has_skip_wal_writes
64 }
65
66 pub(crate) fn immutables(&self) -> &[MemtableRef] {
68 &self.immutables
69 }
70
71 pub(crate) fn list_memtables(&self) -> Vec<MemtableRef> {
73 let mut mems = Vec::with_capacity(self.immutables.len() + self.mutable.num_partitions());
74 self.mutable.list_memtables(&mut mems);
75 mems.extend_from_slice(&self.immutables);
76 mems
77 }
78
79 pub(crate) fn min_sequence(&self) -> Option<SequenceNumber> {
82 self.list_memtables()
83 .iter()
84 .filter(|mem| !mem.is_empty())
85 .map(|mem| mem.min_sequence())
86 .min()
87 }
88
89 pub(crate) fn freeze_mutable(
96 &self,
97 metadata: &RegionMetadataRef,
98 time_window: Option<Duration>,
99 ) -> Result<Option<MemtableVersion>> {
100 if self.mutable.is_empty() {
101 if Some(self.mutable.part_duration()) == time_window {
103 return Ok(None);
105 }
106
107 let mutable = self
109 .mutable
110 .partitions
111 .new_with_part_duration(time_window, None);
112 common_telemetry::debug!(
113 "Freeze empty memtable, update partition duration from {:?} to {:?}",
114 self.mutable.part_duration(),
115 time_window
116 );
117 return Ok(Some(MemtableVersion {
118 mutable: Arc::new(MutableMemtables::new(mutable)),
119 immutables: self.immutables.clone(),
120 immutable_has_skip_wal_writes: self.immutable_has_skip_wal_writes,
121 }));
122 }
123
124 self.mutable.partitions.freeze()?;
127 if Some(self.mutable.part_duration()) != time_window {
129 common_telemetry::debug!(
130 "Fork memtable, update partition duration from {:?}, to {:?}",
131 self.mutable.part_duration(),
132 time_window
133 );
134 }
135 let mutable = Arc::new(MutableMemtables::new(
136 self.mutable.partitions.fork(metadata, time_window),
137 ));
138
139 let mut immutables =
140 SmallVec::with_capacity(self.immutables.len() + self.mutable.num_partitions());
141 immutables.extend(self.immutables.iter().cloned());
142 self.mutable
144 .partitions
145 .list_memtables_to_small_vec(&mut immutables);
146
147 Ok(Some(MemtableVersion {
148 mutable,
149 immutables,
150 immutable_has_skip_wal_writes: self.immutable_has_skip_wal_writes
151 || self.mutable.has_skip_wal_writes(),
152 }))
153 }
154
155 pub(crate) fn remove_memtables(&mut self, ids: &[MemtableId]) {
157 self.immutables = self
158 .immutables
159 .iter()
160 .filter(|mem| !ids.contains(&mem.id()))
161 .cloned()
162 .collect();
163 if self.immutables.is_empty() {
164 self.immutable_has_skip_wal_writes = false;
165 }
166 }
167
168 pub(crate) fn mutable_usage(&self) -> usize {
170 self.mutable.memory_usage()
171 }
172
173 pub(crate) fn immutables_usage(&self) -> usize {
175 self.immutables
176 .iter()
177 .map(|mem| mem.stats().estimated_bytes)
178 .sum()
179 }
180
181 pub(crate) fn num_rows(&self) -> u64 {
183 self.immutables
184 .iter()
185 .map(|mem| mem.stats().num_rows as u64)
186 .sum::<u64>()
187 + self.mutable.num_rows()
188 }
189
190 pub(crate) fn time_range(&self) -> Option<(Timestamp, Timestamp)> {
192 let mut mutables = Vec::new();
193 self.mutable.list_memtables(&mut mutables);
194 self.immutables
195 .iter()
196 .chain(mutables.iter())
197 .filter_map(|mem| mem.stats().time_range())
198 .reduce(|(min_a, max_a), (min_b, max_b)| (min_a.min(min_b), max_a.max(max_b)))
199 }
200
201 pub(crate) fn is_empty(&self) -> bool {
206 self.mutable.is_empty() && self.immutables.is_empty()
207 }
208}
209
210#[derive(Debug)]
215pub(crate) struct MutableMemtables {
216 partitions: TimePartitions,
217 has_skip_wal_writes: AtomicBool,
219}
220
221pub(crate) type MutableMemtablesRef = Arc<MutableMemtables>;
222
223impl MutableMemtables {
224 fn new(partitions: TimePartitions) -> Self {
225 Self {
226 partitions,
227 has_skip_wal_writes: AtomicBool::new(false),
228 }
229 }
230
231 pub(crate) fn mark_skip_wal_writes(&self) {
233 self.has_skip_wal_writes.store(true, Ordering::Relaxed);
234 }
235
236 fn has_skip_wal_writes(&self) -> bool {
237 self.has_skip_wal_writes.load(Ordering::Relaxed)
238 }
239
240 pub(crate) fn write(&self, kvs: &KeyValues) -> Result<()> {
242 self.partitions.write(kvs)
243 }
244
245 pub(crate) fn write_bulk(&self, part: BulkPart) -> Result<()> {
247 self.partitions.write_bulk(part)
248 }
249
250 pub(crate) fn is_empty(&self) -> bool {
252 self.partitions.is_empty()
253 }
254
255 pub(crate) fn memtable_builder(&self) -> &MemtableBuilderRef {
257 self.partitions.memtable_builder()
258 }
259
260 pub(crate) fn next_memtable_id(&self) -> MemtableId {
262 self.partitions.next_memtable_id()
263 }
264
265 pub(crate) fn part_duration(&self) -> Duration {
267 self.partitions.part_duration()
268 }
269
270 pub(crate) fn new_with_part_duration(
273 &self,
274 part_duration: Option<Duration>,
275 memtable_builder: Option<MemtableBuilderRef>,
276 ) -> TimePartitions {
277 self.partitions
278 .new_with_part_duration(part_duration, memtable_builder)
279 }
280
281 pub(crate) fn memory_usage(&self) -> usize {
283 self.partitions.memory_usage()
284 }
285
286 pub(crate) fn series_count(&self) -> usize {
288 self.partitions.series_count()
289 }
290
291 fn num_rows(&self) -> u64 {
292 self.partitions.num_rows()
293 }
294
295 fn num_partitions(&self) -> usize {
296 self.partitions.num_partitions()
297 }
298
299 fn list_memtables(&self, memtables: &mut Vec<MemtableRef>) {
300 self.partitions.list_memtables(memtables);
301 }
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307 use crate::memtable::time_series::TimeSeriesMemtableBuilder;
308 use crate::test_util::memtable_util;
309
310 #[test]
311 fn test_skip_wal_writes_follow_memtable_lifecycle() {
312 for new_skip_wal_writes in [false, true] {
313 let metadata = memtable_util::metadata_for_test();
314 let partitions = TimePartitions::new(
315 metadata.clone(),
316 Arc::new(TimeSeriesMemtableBuilder::default()),
317 0,
318 Some(Duration::from_secs(5)),
319 );
320 let version = MemtableVersion::new(partitions);
321 let snapshot = version.clone();
322 assert!(!version.has_skip_wal_writes());
323
324 let kvs = memtable_util::build_key_values(
325 &metadata,
326 "hello".to_string(),
327 0,
328 &[1000, 7000],
329 1,
330 );
331 version.mutable.mark_skip_wal_writes();
332 version.mutable.write(&kvs).unwrap();
333 assert!(snapshot.has_skip_wal_writes());
334
335 let mut frozen = version
336 .freeze_mutable(&metadata, Some(Duration::from_secs(5)))
337 .unwrap()
338 .unwrap();
339 assert_eq!(2, frozen.immutables().len());
340 assert!(frozen.has_skip_wal_writes());
341 assert!(!frozen.mutable.has_skip_wal_writes());
342 assert!(!Arc::ptr_eq(&version.mutable, &frozen.mutable));
343
344 let during_flush = frozen.clone();
345 if new_skip_wal_writes {
346 frozen.mutable.mark_skip_wal_writes();
347 }
348 frozen.mutable.write(&kvs).unwrap();
349 let ids: Vec<_> = frozen.immutables().iter().map(|mem| mem.id()).collect();
350 frozen.remove_memtables(&ids);
351 assert_eq!(new_skip_wal_writes, frozen.has_skip_wal_writes());
352 assert_eq!(
353 new_skip_wal_writes,
354 during_flush.mutable.has_skip_wal_writes()
355 );
356 assert_eq!(2, during_flush.immutables().len());
358 assert!(during_flush.has_skip_wal_writes());
359
360 let mut next_flush = frozen
361 .freeze_mutable(&metadata, Some(Duration::from_secs(5)))
362 .unwrap()
363 .unwrap();
364 let ids: Vec<_> = next_flush.immutables().iter().map(|mem| mem.id()).collect();
365 next_flush.remove_memtables(&ids);
366 assert!(!next_flush.has_skip_wal_writes());
367 }
368 }
369
370 #[test]
371 fn test_skip_wal_writes_survive_flush_retry() {
372 let metadata = memtable_util::metadata_for_test();
373 let partitions = TimePartitions::new(
374 metadata.clone(),
375 Arc::new(TimeSeriesMemtableBuilder::default()),
376 0,
377 Some(Duration::from_secs(5)),
378 );
379 let version = MemtableVersion::new(partitions);
380 let kvs = memtable_util::build_key_values(&metadata, "hello".to_string(), 0, &[1000], 1);
381 version.mutable.mark_skip_wal_writes();
382 version.mutable.write(&kvs).unwrap();
383 let frozen = version
384 .freeze_mutable(&metadata, Some(Duration::from_secs(5)))
385 .unwrap()
386 .unwrap();
387
388 let frozen = frozen
391 .freeze_mutable(&metadata, Some(Duration::from_secs(10)))
392 .unwrap()
393 .unwrap();
394 assert!(frozen.has_skip_wal_writes());
395 assert!(!frozen.mutable.has_skip_wal_writes());
396
397 frozen.mutable.write(&kvs).unwrap();
399 let mut retried = frozen
400 .freeze_mutable(&metadata, Some(Duration::from_secs(10)))
401 .unwrap()
402 .unwrap();
403 assert_eq!(2, retried.immutables().len());
404 assert!(retried.has_skip_wal_writes());
405 let ids: Vec<_> = retried.immutables().iter().map(|mem| mem.id()).collect();
406 retried.remove_memtables(&ids);
407 assert!(!retried.has_skip_wal_writes());
408
409 let replacement = MemtableVersion::new(TimePartitions::new(
410 metadata,
411 frozen.mutable.memtable_builder().clone(),
412 frozen.mutable.next_memtable_id(),
413 None,
414 ));
415 assert!(!replacement.has_skip_wal_writes());
416 assert!(frozen.has_skip_wal_writes());
417 }
418}