Skip to content

Commit e481f07

Browse files
authored
feat: Implement dedup for the new memtable and expose the config (#3377)
* fix: KeyValues num_fields() is incorrect * chore: fix warnings * feat: support dedup * feat: allow using the new memtable * feat: serde default for config * fix: resets pk index after finishing a dict
1 parent 606309f commit e481f07

11 files changed

Lines changed: 223 additions & 146 deletions

File tree

‎src/mito2/src/config.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use serde::{Deserialize, Serialize};
2424
use serde_with::{serde_as, NoneAsEmptyString};
2525

2626
use crate::error::Result;
27+
use crate::memtable::merge_tree::MergeTreeConfig;
2728
use crate::sst::DEFAULT_WRITE_BUFFER_SIZE;
2829

2930
/// Default max running background job.
@@ -102,6 +103,9 @@ pub struct MitoConfig {
102103

103104
/// Inverted index configs.
104105
pub inverted_index: InvertedIndexConfig,
106+
107+
/// Experimental memtable.
108+
pub experimental_memtable: Option<MergeTreeConfig>,
105109
}
106110

107111
impl Default for MitoConfig {
@@ -127,6 +131,7 @@ impl Default for MitoConfig {
127131
parallel_scan_channel_size: DEFAULT_SCAN_CHANNEL_SIZE,
128132
allow_stale_entries: false,
129133
inverted_index: InvertedIndexConfig::default(),
134+
experimental_memtable: None,
130135
};
131136

132137
// Adjust buffer and cache size according to system memory if we can.

‎src/mito2/src/engine/basic_test.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -550,11 +550,11 @@ async fn test_region_usage() {
550550
flush_region(&engine, region_id, None).await;
551551

552552
let region_stat = region.region_usage().await;
553-
assert_eq!(region_stat.wal_usage, 0);
554553
assert_eq!(region_stat.sst_usage, 2962);
555554

556555
// region total usage
557-
assert_eq!(region_stat.disk_usage(), 4028);
556+
// Some memtables may share items.
557+
assert!(region_stat.disk_usage() >= 4028);
558558
}
559559

560560
#[tokio::test]

‎src/mito2/src/memtable/key_values.rs‎

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl<'a> KeyValue<'a> {
124124

125125
/// Get number of field columns.
126126
pub fn num_fields(&self) -> usize {
127-
self.row.values.len() - self.helper.num_primary_key_column - 1
127+
self.helper.indices.len() - self.helper.num_primary_key_column - 1
128128
}
129129

130130
/// Get sequence.
@@ -261,7 +261,13 @@ mod tests {
261261
}
262262
}
263263

264-
fn check_key_values(kvs: &KeyValues, num_rows: usize, keys: &[i64], ts: i64, values: &[i64]) {
264+
fn check_key_values(
265+
kvs: &KeyValues,
266+
num_rows: usize,
267+
keys: &[Option<i64>],
268+
ts: i64,
269+
values: &[Option<i64>],
270+
) {
265271
assert_eq!(num_rows, kvs.num_rows());
266272
let mut expect_seq = START_SEQ;
267273
let expect_ts = ValueRef::Int64(ts);
@@ -273,10 +279,10 @@ mod tests {
273279
assert_eq!(values.len(), kv.num_fields());
274280

275281
assert_eq!(expect_ts, kv.timestamp());
276-
let expect_keys: Vec<_> = keys.iter().map(|k| ValueRef::Int64(*k)).collect();
282+
let expect_keys: Vec<_> = keys.iter().map(|k| ValueRef::from(*k)).collect();
277283
let actual_keys: Vec<_> = kv.primary_keys().collect();
278284
assert_eq!(expect_keys, actual_keys);
279-
let expect_values: Vec<_> = values.iter().map(|v| ValueRef::Int64(*v)).collect();
285+
let expect_values: Vec<_> = values.iter().map(|v| ValueRef::from(*v)).collect();
280286
let actual_values: Vec<_> = kv.fields().collect();
281287
assert_eq!(expect_values, actual_values);
282288
}
@@ -312,7 +318,7 @@ mod tests {
312318
// KeyValues
313319
// keys: [k0=2, k1=0]
314320
// ts: 1,
315-
check_key_values(&kvs, 3, &[2, 0], 1, &[]);
321+
check_key_values(&kvs, 3, &[Some(2), Some(0)], 1, &[]);
316322
}
317323

318324
#[test]
@@ -325,7 +331,7 @@ mod tests {
325331
// KeyValues (note that v0 is in front of v1 in region schema)
326332
// ts: 2,
327333
// fields: [v0=1, v1=0]
328-
check_key_values(&kvs, 3, &[], 2, &[1, 0]);
334+
check_key_values(&kvs, 3, &[], 2, &[Some(1), Some(0)]);
329335
}
330336

331337
#[test]
@@ -339,6 +345,34 @@ mod tests {
339345
// keys: [k0=0, k1=3]
340346
// ts: 2,
341347
// fields: [v0=1, v1=4]
342-
check_key_values(&kvs, 3, &[0, 3], 2, &[1, 4]);
348+
check_key_values(&kvs, 3, &[Some(0), Some(3)], 2, &[Some(1), Some(4)]);
349+
}
350+
351+
#[test]
352+
fn test_sparse_field() {
353+
let meta = new_region_metadata(2, 2);
354+
// The value of each row:
355+
// k0=0, v0=1, ts=2, k1=3, (v1 will be null)
356+
let mutation = new_mutation(&["k0", "v0", "ts", "k1"], 3);
357+
let kvs = KeyValues::new(&meta, mutation).unwrap();
358+
// KeyValues
359+
// keys: [k0=0, k1=3]
360+
// ts: 2,
361+
// fields: [v0=1, v1=null]
362+
check_key_values(&kvs, 3, &[Some(0), Some(3)], 2, &[Some(1), None]);
363+
}
364+
365+
#[test]
366+
fn test_sparse_tag_field() {
367+
let meta = new_region_metadata(2, 2);
368+
// The value of each row:
369+
// k0 = 0, v0=1, ts=2, (k1, v1 will be null)
370+
let mutation = new_mutation(&["k0", "v0", "ts"], 3);
371+
let kvs = KeyValues::new(&meta, mutation).unwrap();
372+
// KeyValues
373+
// keys: [k0=0, k1=null]
374+
// ts: 2,
375+
// fields: [v0=1, v1=null]
376+
check_key_values(&kvs, 3, &[Some(0), None], 2, &[Some(1), None]);
343377
}
344378
}

‎src/mito2/src/memtable/merge_tree.rs‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use std::fmt;
2828
use std::sync::atomic::{AtomicI64, Ordering};
2929
use std::sync::Arc;
3030

31+
use serde::{Deserialize, Serialize};
3132
use store_api::metadata::RegionMetadataRef;
3233
use store_api::storage::ColumnId;
3334
use table::predicate::Predicate;
@@ -54,7 +55,8 @@ struct PkId {
5455
}
5556

5657
/// Config for the merge tree memtable.
57-
#[derive(Debug, Clone)]
58+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
59+
#[serde(default)]
5860
pub struct MergeTreeConfig {
5961
/// Max keys in an index shard.
6062
pub index_max_keys_per_shard: usize,
@@ -248,16 +250,19 @@ impl MergeTreeMemtable {
248250
/// Builder to build a [MergeTreeMemtable].
249251
#[derive(Debug, Default)]
250252
pub struct MergeTreeMemtableBuilder {
251-
write_buffer_manager: Option<WriteBufferManagerRef>,
252253
config: MergeTreeConfig,
254+
write_buffer_manager: Option<WriteBufferManagerRef>,
253255
}
254256

255257
impl MergeTreeMemtableBuilder {
256258
/// Creates a new builder with specific `write_buffer_manager`.
257-
pub fn new(write_buffer_manager: Option<WriteBufferManagerRef>) -> Self {
259+
pub fn new(
260+
config: MergeTreeConfig,
261+
write_buffer_manager: Option<WriteBufferManagerRef>,
262+
) -> Self {
258263
Self {
264+
config,
259265
write_buffer_manager,
260-
config: MergeTreeConfig::default(),
261266
}
262267
}
263268
}
@@ -420,7 +425,8 @@ mod tests {
420425
memtable_util::metadata_with_primary_key(vec![], false)
421426
};
422427
// Try to build a memtable via the builder.
423-
let memtable = MergeTreeMemtableBuilder::new(None).build(1, &metadata);
428+
let memtable =
429+
MergeTreeMemtableBuilder::new(MergeTreeConfig::default(), None).build(1, &metadata);
424430

425431
let expect = (0..100).collect::<Vec<_>>();
426432
let kvs = memtable_util::build_key_values(&metadata, "hello".to_string(), 10, &expect, 1);

‎src/mito2/src/memtable/merge_tree/data.rs‎

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -883,29 +883,6 @@ impl DataPartsReader {
883883
}
884884
}
885885

886-
#[cfg(test)]
887-
pub(crate) fn write_rows_to_buffer(
888-
buffer: &mut DataBuffer,
889-
schema: &RegionMetadataRef,
890-
pk_index: u16,
891-
ts: Vec<i64>,
892-
v0: Vec<Option<f64>>,
893-
sequence: u64,
894-
) {
895-
let kvs = crate::test_util::memtable_util::build_key_values_with_ts_seq_values(
896-
schema,
897-
"whatever".to_string(),
898-
1,
899-
ts.into_iter(),
900-
v0.into_iter(),
901-
sequence,
902-
);
903-
904-
for kv in kvs.iter() {
905-
buffer.write_row(pk_index, kv);
906-
}
907-
}
908-
909886
#[cfg(test)]
910887
mod tests {
911888
use datafusion::arrow::array::Float64Array;
@@ -914,7 +891,9 @@ mod tests {
914891
use parquet::data_type::AsBytes;
915892

916893
use super::*;
917-
use crate::test_util::memtable_util::{extract_data_batch, metadata_for_test};
894+
use crate::test_util::memtable_util::{
895+
extract_data_batch, metadata_for_test, write_rows_to_buffer,
896+
};
918897

919898
#[test]
920899
fn test_lazy_mutable_vector_builder() {

‎src/mito2/src/memtable/merge_tree/dedup.rs‎

Lines changed: 35 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,19 @@ use std::ops::Range;
1616

1717
use crate::error::Result;
1818
use crate::memtable::merge_tree::data::DataBatch;
19+
use crate::memtable::merge_tree::shard::DataBatchSource;
1920
use crate::memtable::merge_tree::PkId;
2021

21-
pub trait DedupSource {
22-
/// Returns whether current source is still valid.
23-
fn is_valid(&self) -> bool;
24-
25-
/// Advances source to next data batch.
26-
fn next(&mut self) -> Result<()>;
27-
28-
/// Returns current pk id.
29-
/// # Panics
30-
/// If source is not valid.
31-
fn current_pk_id(&self) -> PkId;
32-
33-
/// Returns the current primary key bytes.
34-
/// # Panics
35-
/// If source is not valid.
36-
fn current_key(&self) -> &[u8];
37-
38-
/// Returns the data part.
39-
/// # Panics
40-
/// If source is not valid.
41-
fn current_data_batch(&self) -> DataBatch;
42-
}
43-
44-
struct DedupReader<T> {
22+
/// A reader that dedup sorted batches from a merger.
23+
pub struct DedupReader<T> {
4524
prev_batch_last_row: Option<(PkId, i64)>,
4625
current_batch_range: Option<Range<usize>>,
4726
inner: T,
4827
}
4928

50-
impl<T: DedupSource> DedupReader<T> {
51-
fn try_new(inner: T) -> Result<Self> {
29+
impl<T: DataBatchSource> DedupReader<T> {
30+
/// Creates a new dedup reader.
31+
pub fn try_new(inner: T) -> Result<Self> {
5232
let mut res = Self {
5333
prev_batch_last_row: None,
5434
current_batch_range: None,
@@ -57,24 +37,13 @@ impl<T: DedupSource> DedupReader<T> {
5737
res.next()?;
5838
Ok(res)
5939
}
40+
}
6041

42+
impl<T: DataBatchSource> DataBatchSource for DedupReader<T> {
6143
fn is_valid(&self) -> bool {
6244
self.current_batch_range.is_some()
6345
}
6446

65-
/// Returns current encoded primary key.
66-
/// # Panics
67-
/// If inner reader is exhausted.
68-
fn current_key(&self) -> &[u8] {
69-
self.inner.current_key()
70-
}
71-
72-
fn current_data_batch(&self) -> DataBatch {
73-
let range = self.current_batch_range.as_ref().unwrap();
74-
let data_batch = self.inner.current_data_batch();
75-
data_batch.slice(range.start, range.len())
76-
}
77-
7847
fn next(&mut self) -> Result<()> {
7948
loop {
8049
match &mut self.prev_batch_last_row {
@@ -122,40 +91,56 @@ impl<T: DedupSource> DedupReader<T> {
12291
}
12392
Ok(())
12493
}
94+
95+
fn current_pk_id(&self) -> PkId {
96+
self.inner.current_pk_id()
97+
}
98+
99+
fn current_key(&self) -> Option<&[u8]> {
100+
self.inner.current_key()
101+
}
102+
103+
fn current_data_batch(&self) -> DataBatch {
104+
let range = self.current_batch_range.as_ref().unwrap();
105+
let data_batch = self.inner.current_data_batch();
106+
data_batch.slice(range.start, range.len())
107+
}
125108
}
126109

127110
#[cfg(test)]
128111
mod tests {
129112
use store_api::metadata::RegionMetadataRef;
130113

131114
use super::*;
132-
use crate::memtable::merge_tree::data::{
133-
write_rows_to_buffer, DataBuffer, DataParts, DataPartsReader,
115+
use crate::memtable::merge_tree::data::{DataBuffer, DataParts, DataPartsReader};
116+
use crate::test_util::memtable_util::{
117+
extract_data_batch, metadata_for_test, write_rows_to_buffer,
134118
};
135-
use crate::test_util::memtable_util::{extract_data_batch, metadata_for_test};
136119

137-
impl DedupSource for DataPartsReader {
120+
struct MockSource(DataPartsReader);
121+
122+
impl DataBatchSource for MockSource {
138123
fn is_valid(&self) -> bool {
139-
self.is_valid()
124+
self.0.is_valid()
140125
}
141126

142127
fn next(&mut self) -> Result<()> {
143-
self.next()
128+
self.0.next()
144129
}
145130

146131
fn current_pk_id(&self) -> PkId {
147132
PkId {
148133
shard_id: 0,
149-
pk_index: self.current_data_batch().pk_index(),
134+
pk_index: self.0.current_data_batch().pk_index(),
150135
}
151136
}
152137

153-
fn current_key(&self) -> &[u8] {
154-
b"abcf"
138+
fn current_key(&self) -> Option<&[u8]> {
139+
None
155140
}
156141

157142
fn current_data_batch(&self) -> DataBatch {
158-
self.current_data_batch()
143+
self.0.current_data_batch()
159144
}
160145
}
161146

@@ -194,7 +179,7 @@ mod tests {
194179
let mut parts = DataParts::new(meta, 10, true).with_frozen(frozens);
195180

196181
let mut res = Vec::with_capacity(expected.len());
197-
let mut reader = DedupReader::try_new(parts.read().unwrap()).unwrap();
182+
let mut reader = DedupReader::try_new(MockSource(parts.read().unwrap())).unwrap();
198183
while reader.is_valid() {
199184
let batch = reader.current_data_batch();
200185
res.push(extract_data_batch(&batch));

0 commit comments

Comments
 (0)