Skip to content

Commit 5d023fd

Browse files
authored
Merge pull request #81 from fjall-rs/2.5.0
2.5.0
2 parents c7164d2 + abddb10 commit 5d023fd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1771
-1020
lines changed

Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "lsm-tree"
33
description = "A K.I.S.S. implementation of log-structured merge trees (LSM-trees/LSMTs)"
44
license = "MIT OR Apache-2.0"
5-
version = "2.4.0"
5+
version = "2.5.0"
66
edition = "2021"
77
rust-version = "1.74.0"
88
readme = "README.md"
@@ -38,7 +38,7 @@ quick_cache = { version = "0.6.5", default-features = false, features = [] }
3838
rustc-hash = "2.0.0"
3939
self_cell = "1.0.4"
4040
tempfile = "3.12.0"
41-
value-log = "1.3.0"
41+
value-log = "1.4.1"
4242
varint-rs = "2.2.0"
4343
xxhash-rust = { version = "0.8.12", features = ["xxh3"] }
4444

@@ -57,6 +57,12 @@ harness = false
5757
path = "benches/tli.rs"
5858
required-features = []
5959

60+
[[bench]]
61+
name = "merge"
62+
harness = false
63+
path = "benches/merge.rs"
64+
required-features = []
65+
6066
[[bench]]
6167
name = "memtable"
6268
harness = false

benches/merge.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use criterion::{criterion_group, criterion_main, Criterion};
2+
use lsm_tree::merge::{BoxedIterator, Merger};
3+
use lsm_tree::{mvcc_stream::MvccStream, InternalValue, Memtable};
4+
use nanoid::nanoid;
5+
6+
fn merger(c: &mut Criterion) {
7+
for num in [2, 4, 8, 16, 30] {
8+
c.bench_function(&format!("Merge {num}"), |b| {
9+
let memtables = (0..num)
10+
.map(|_| {
11+
let table = Memtable::default();
12+
13+
for _ in 0..100 {
14+
table.insert(InternalValue::from_components(
15+
nanoid!(),
16+
vec![],
17+
0,
18+
lsm_tree::ValueType::Value,
19+
));
20+
}
21+
22+
table
23+
})
24+
.collect::<Vec<_>>();
25+
26+
b.iter_with_large_drop(|| {
27+
let iters = memtables
28+
.iter()
29+
.map(|x| x.iter().map(Ok))
30+
.map(|x| Box::new(x) as BoxedIterator<'_>)
31+
.collect();
32+
33+
let merger = Merger::new(iters);
34+
35+
assert_eq!(num * 100, merger.count());
36+
})
37+
});
38+
}
39+
}
40+
41+
fn mvcc_stream(c: &mut Criterion) {
42+
for num in [2, 4, 8, 16, 30] {
43+
c.bench_function(&format!("MVCC stream {num} versions"), |b| {
44+
let memtables = (0..num)
45+
.map(|_| {
46+
let table = Memtable::default();
47+
48+
for key in 'a'..='z' {
49+
table.insert(InternalValue::from_components(
50+
key.to_string(),
51+
vec![],
52+
num,
53+
lsm_tree::ValueType::Value,
54+
));
55+
}
56+
57+
table
58+
})
59+
.collect::<Vec<_>>();
60+
61+
b.iter_with_large_drop(|| {
62+
let iters = memtables
63+
.iter()
64+
.map(|x| x.iter().map(Ok))
65+
.map(|x| Box::new(x) as BoxedIterator<'_>)
66+
.collect();
67+
68+
let merger = MvccStream::new(Merger::new(iters));
69+
70+
assert_eq!(26, merger.count());
71+
})
72+
});
73+
}
74+
}
75+
76+
criterion_group!(benches, merger, mvcc_stream);
77+
criterion_main!(benches);

benches/tli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use criterion::{criterion_group, criterion_main, Criterion};
22
use lsm_tree::segment::{
3-
block_index::BlockIndex, value_block::BlockOffset, value_block::CachePolicy,
3+
block_index::KeyedBlockIndex, value_block::BlockOffset, value_block::CachePolicy,
44
};
55

66
fn tli_find_item(c: &mut Criterion) {

src/abstract.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -559,16 +559,11 @@ pub trait AbstractTree {
559559
/// # Errors
560560
///
561561
/// Will return `Err` if an IO error occurs.
562-
fn insert<K: AsRef<[u8]>, V: AsRef<[u8]>>(&self, key: K, value: V, seqno: SeqNo) -> (u32, u32);
563-
564-
/// Inserts a key-value pair.
565-
fn raw_insert_with_lock<K: AsRef<[u8]>, V: AsRef<[u8]>>(
562+
fn insert<K: Into<UserKey>, V: Into<UserValue>>(
566563
&self,
567-
lock: &RwLockWriteGuard<'_, Memtable>,
568564
key: K,
569565
value: V,
570566
seqno: SeqNo,
571-
r#type: ValueType,
572567
) -> (u32, u32);
573568

574569
/// Removes an item from the tree.
@@ -598,7 +593,7 @@ pub trait AbstractTree {
598593
/// # Errors
599594
///
600595
/// Will return `Err` if an IO error occurs.
601-
fn remove<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> (u32, u32);
596+
fn remove<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u32, u32);
602597

603598
/// Removes an item from the tree.
604599
///
@@ -632,5 +627,5 @@ pub trait AbstractTree {
632627
/// # Errors
633628
///
634629
/// Will return `Err` if an IO error occurs.
635-
fn remove_weak<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> (u32, u32);
630+
fn remove_weak<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u32, u32);
636631
}

src/blob_tree/gc/reader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl<'a> GcReader<'a> {
2020
fn get_internal(&self, key: &[u8]) -> crate::Result<Option<MaybeInlineValue>> {
2121
let Some(item) = self
2222
.tree
23-
.get_internal_entry_with_lock(self.memtable, key, true, None)?
23+
.get_internal_entry_with_lock(self.memtable, key, None)?
2424
.map(|x| x.value)
2525
else {
2626
return Ok(None);

src/blob_tree/mod.rs

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -596,34 +596,18 @@ impl AbstractTree for BlobTree {
596596
)
597597
}
598598

599-
fn raw_insert_with_lock<K: AsRef<[u8]>, V: AsRef<[u8]>>(
599+
fn insert<K: Into<UserKey>, V: Into<UserValue>>(
600600
&self,
601-
lock: &RwLockWriteGuard<'_, Memtable>,
602601
key: K,
603602
value: V,
604603
seqno: SeqNo,
605-
r#type: ValueType,
606604
) -> (u32, u32) {
607605
use value::MaybeInlineValue;
608606

609607
// NOTE: Initially, we always write an inline value
610608
// On memtable flush, depending on the values' sizes, they will be separated
611609
// into inline or indirect values
612-
let item = MaybeInlineValue::Inline(value.as_ref().into());
613-
614-
let value = item.encode_into_vec();
615-
616-
let value = InternalValue::from_components(key.as_ref(), value, seqno, r#type);
617-
lock.insert(value)
618-
}
619-
620-
fn insert<K: AsRef<[u8]>, V: AsRef<[u8]>>(&self, key: K, value: V, seqno: SeqNo) -> (u32, u32) {
621-
use value::MaybeInlineValue;
622-
623-
// NOTE: Initially, we always write an inline value
624-
// On memtable flush, depending on the values' sizes, they will be separated
625-
// into inline or indirect values
626-
let item = MaybeInlineValue::Inline(value.as_ref().into());
610+
let item = MaybeInlineValue::Inline(value.into());
627611

628612
let value = item.encode_into_vec();
629613

@@ -680,11 +664,11 @@ impl AbstractTree for BlobTree {
680664
}
681665
}
682666

683-
fn remove<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> (u32, u32) {
667+
fn remove<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u32, u32) {
684668
self.index.remove(key, seqno)
685669
}
686670

687-
fn remove_weak<K: AsRef<[u8]>>(&self, key: K, seqno: SeqNo) -> (u32, u32) {
671+
fn remove_weak<K: Into<UserKey>>(&self, key: K, seqno: SeqNo) -> (u32, u32) {
688672
self.index.remove_weak(key, seqno)
689673
}
690674
}

src/bloom/bit_array.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,6 @@ impl BitArray {
3939
Self(bytes)
4040
}
4141

42-
/// Size in bytes
43-
#[must_use]
44-
pub fn len(&self) -> usize {
45-
self.0.len()
46-
}
47-
48-
#[allow(unused)]
49-
#[must_use]
50-
pub fn is_empty(&self) -> bool {
51-
self.len() == 0
52-
}
53-
5442
#[must_use]
5543
pub fn bytes(&self) -> &[u8] {
5644
&self.0

src/bloom/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl BloomFilter {
8888
/// Size of bloom filter in bytes.
8989
#[must_use]
9090
pub fn len(&self) -> usize {
91-
self.inner.len()
91+
self.inner.bytes().len()
9292
}
9393

9494
fn from_raw(m: usize, k: usize, bytes: Box<[u8]>) -> Self {

src/compaction/fifo.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ impl Strategy {
4040
}
4141

4242
impl CompactionStrategy for Strategy {
43+
fn get_name(&self) -> &'static str {
44+
"FifoStrategy"
45+
}
46+
4347
fn choose(&self, levels: &LevelManifest, config: &Config) -> Choice {
4448
let resolved_view = levels.resolved_view();
4549

@@ -58,11 +62,8 @@ impl CompactionStrategy for Strategy {
5862
let lifetime_sec = lifetime_us / 1000 / 1000;
5963

6064
if lifetime_sec > ttl_seconds.into() {
61-
log::warn!(
62-
"segment is older than configured TTL: {:?}",
63-
segment.metadata.id,
64-
);
65-
segment_ids_to_delete.insert(segment.metadata.id);
65+
log::warn!("segment is older than configured TTL: {:?}", segment.id(),);
66+
segment_ids_to_delete.insert(segment.id());
6667
}
6768
}
6869
}
@@ -86,11 +87,11 @@ impl CompactionStrategy for Strategy {
8687

8788
bytes_to_delete = bytes_to_delete.saturating_sub(segment.metadata.file_size);
8889

89-
segment_ids_to_delete.insert(segment.metadata.id);
90+
segment_ids_to_delete.insert(segment.id());
9091

9192
log::debug!(
9293
"dropping segment to reach configured size limit: {:?}",
93-
segment.metadata.id,
94+
segment.id(),
9495
);
9596
}
9697
}
@@ -124,7 +125,7 @@ mod tests {
124125
key_range::KeyRange,
125126
level_manifest::LevelManifest,
126127
segment::{
127-
block_index::two_level_index::TwoLevelBlockIndex,
128+
block_index::{two_level_index::TwoLevelBlockIndex, BlockIndexImpl},
128129
file_offsets::FileOffsets,
129130
meta::{Metadata, SegmentId},
130131
value_block::BlockOffset,
@@ -136,18 +137,18 @@ mod tests {
136137
use std::sync::Arc;
137138
use test_log::test;
138139

139-
#[cfg(feature = "bloom")]
140-
use crate::bloom::BloomFilter;
141-
142140
#[allow(clippy::expect_used)]
143141
#[allow(clippy::cast_possible_truncation)]
144142
fn fixture_segment(id: SegmentId, created_at: u128) -> Segment {
145143
let block_cache = Arc::new(BlockCache::with_capacity_bytes(10 * 1_024 * 1_024));
146144

145+
let block_index = TwoLevelBlockIndex::new((0, id).into(), block_cache.clone());
146+
let block_index = Arc::new(BlockIndexImpl::TwoLevel(block_index));
147+
147148
SegmentInner {
148149
tree_id: 0,
149150
descriptor_table: Arc::new(FileDescriptorTable::new(512, 1)),
150-
block_index: Arc::new(TwoLevelBlockIndex::new((0, id).into(), block_cache.clone())),
151+
block_index,
151152

152153
offsets: FileOffsets {
153154
bloom_ptr: BlockOffset(0),
@@ -180,7 +181,7 @@ mod tests {
180181
block_cache,
181182

182183
#[cfg(feature = "bloom")]
183-
bloom_filter: Some(BloomFilter::with_fp_rate(1, 0.1)),
184+
bloom_filter: Some(crate::bloom::BloomFilter::with_fp_rate(1, 0.1)),
184185
}
185186
.into()
186187
}

0 commit comments

Comments
 (0)