add key abstraction and prepare for MVCC (#28)

* add key abstraction and prepare for MVCC

Signed-off-by: Alex Chi <iskyzh@gmail.com>

* a little bit type exercise

Signed-off-by: Alex Chi <iskyzh@gmail.com>

* refactor tests

Signed-off-by: Alex Chi <iskyzh@gmail.com>

* fix clippy warnings

Signed-off-by: Alex Chi <iskyzh@gmail.com>

* refactor starter code

Signed-off-by: Alex Chi <iskyzh@gmail.com>

* final touch docs

Signed-off-by: Alex Chi <iskyzh@gmail.com>

---------

Signed-off-by: Alex Chi <iskyzh@gmail.com>
This commit is contained in:
Alex Chi Z
2024-01-25 10:59:08 +08:00
committed by GitHub
parent 2fefe3e505
commit a3a92359e1
42 changed files with 824 additions and 281 deletions

View File

@@ -5,6 +5,7 @@ use bytes::Bytes;
use crate::{
iterators::StorageIterator,
key::KeySlice,
lsm_storage::{BlockCache, LsmStorageInner},
table::{SsTable, SsTableBuilder},
};
@@ -35,6 +36,8 @@ impl MockIterator {
}
impl StorageIterator for MockIterator {
type KeyType<'a> = KeySlice<'a>;
fn next(&mut self) -> Result<()> {
if self.index < self.data.len() {
self.index += 1;
@@ -47,13 +50,13 @@ impl StorageIterator for MockIterator {
Ok(())
}
fn key(&self) -> &[u8] {
fn key(&self) -> KeySlice {
if let Some(error_when) = self.error_when {
if self.index >= error_when {
panic!("invalid access after next returns an error!");
}
}
self.data[self.index].0.as_ref()
KeySlice::for_testing_from_slice_no_ts(self.data[self.index].0.as_ref())
}
fn value(&self) -> &[u8] {
@@ -79,7 +82,35 @@ pub fn as_bytes(x: &[u8]) -> Bytes {
Bytes::copy_from_slice(x)
}
pub fn check_iter_result(iter: &mut impl StorageIterator, expected: Vec<(Bytes, Bytes)>) {
pub fn check_iter_result_by_key<I>(iter: &mut I, expected: Vec<(Bytes, Bytes)>)
where
I: for<'a> StorageIterator<KeyType<'a> = KeySlice<'a>>,
{
for (k, v) in expected {
assert!(iter.is_valid());
assert_eq!(
k,
iter.key().for_testing_key_ref(),
"expected key: {:?}, actual key: {:?}",
k,
as_bytes(iter.key().for_testing_key_ref()),
);
assert_eq!(
v,
iter.value(),
"expected value: {:?}, actual value: {:?}",
v,
as_bytes(iter.value()),
);
iter.next().unwrap();
}
assert!(!iter.is_valid());
}
pub fn check_lsm_iter_result_by_key<I>(iter: &mut I, expected: Vec<(Bytes, Bytes)>)
where
I: for<'a> StorageIterator<KeyType<'a> = &'a [u8]>,
{
for (k, v) in expected {
assert!(iter.is_valid());
assert_eq!(
@@ -119,7 +150,7 @@ pub fn generate_sst(
) -> SsTable {
let mut builder = SsTableBuilder::new(128);
for (key, value) in data {
builder.add(&key[..], &value[..]);
builder.add(KeySlice::for_testing_from_slice_no_ts(&key[..]), &value[..]);
}
builder.build(id, block_cache, path.as_ref()).unwrap()
}

View File

@@ -8,9 +8,10 @@ use crate::{
lsm_iterator::FusedIterator,
lsm_storage::{LsmStorageInner, LsmStorageOptions},
mem_table::MemTable,
tests::harness::check_lsm_iter_result_by_key,
};
use super::harness::{check_iter_result, expect_iter_error, MockIterator};
use super::harness::{check_iter_result_by_key, expect_iter_error, MockIterator};
#[test]
fn test_task1_memtable_iter() {
@@ -22,15 +23,15 @@ fn test_task1_memtable_iter() {
{
let mut iter = memtable.scan(Bound::Unbounded, Bound::Unbounded);
assert_eq!(iter.key(), b"key1");
assert_eq!(iter.key().for_testing_key_ref(), b"key1");
assert_eq!(iter.value(), b"value1");
assert!(iter.is_valid());
iter.next().unwrap();
assert_eq!(iter.key(), b"key2");
assert_eq!(iter.key().for_testing_key_ref(), b"key2");
assert_eq!(iter.value(), b"value2");
assert!(iter.is_valid());
iter.next().unwrap();
assert_eq!(iter.key(), b"key3");
assert_eq!(iter.key().for_testing_key_ref(), b"key3");
assert_eq!(iter.value(), b"value3");
assert!(iter.is_valid());
iter.next().unwrap();
@@ -39,11 +40,11 @@ fn test_task1_memtable_iter() {
{
let mut iter = memtable.scan(Bound::Included(b"key1"), Bound::Included(b"key2"));
assert_eq!(iter.key(), b"key1");
assert_eq!(iter.key().for_testing_key_ref(), b"key1");
assert_eq!(iter.value(), b"value1");
assert!(iter.is_valid());
iter.next().unwrap();
assert_eq!(iter.key(), b"key2");
assert_eq!(iter.key().for_testing_key_ref(), b"key2");
assert_eq!(iter.value(), b"value2");
assert!(iter.is_valid());
iter.next().unwrap();
@@ -52,7 +53,7 @@ fn test_task1_memtable_iter() {
{
let mut iter = memtable.scan(Bound::Excluded(b"key1"), Bound::Excluded(b"key3"));
assert_eq!(iter.key(), b"key2");
assert_eq!(iter.key().for_testing_key_ref(), b"key2");
assert_eq!(iter.value(), b"value2");
assert!(iter.is_valid());
iter.next().unwrap();
@@ -104,7 +105,7 @@ fn test_task2_merge_1() {
Box::new(i3.clone()),
]);
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from("a"), Bytes::from("1.1")),
@@ -117,7 +118,7 @@ fn test_task2_merge_1() {
let mut iter = MergeIterator::create(vec![Box::new(i3), Box::new(i1), Box::new(i2)]);
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from("a"), Bytes::from("1.1")),
@@ -169,7 +170,7 @@ fn test_task2_merge_2() {
Box::new(i3.clone()),
Box::new(i4.clone()),
]);
check_iter_result(&mut iter, result.clone());
check_iter_result_by_key(&mut iter, result.clone());
let mut iter = MergeIterator::create(vec![
Box::new(i2.clone()),
@@ -177,17 +178,17 @@ fn test_task2_merge_2() {
Box::new(i3.clone()),
Box::new(i1.clone()),
]);
check_iter_result(&mut iter, result.clone());
check_iter_result_by_key(&mut iter, result.clone());
let mut iter =
MergeIterator::create(vec![Box::new(i4), Box::new(i3), Box::new(i2), Box::new(i1)]);
check_iter_result(&mut iter, result);
check_iter_result_by_key(&mut iter, result);
}
#[test]
fn test_task2_merge_empty() {
let mut iter = MergeIterator::<MockIterator>::create(vec![]);
check_iter_result(&mut iter, vec![]);
check_iter_result_by_key(&mut iter, vec![]);
let i1 = MockIterator::new(vec![
(Bytes::from("a"), Bytes::from("1.1")),
@@ -196,7 +197,7 @@ fn test_task2_merge_empty() {
]);
let i2 = MockIterator::new(vec![]);
let mut iter = MergeIterator::<MockIterator>::create(vec![Box::new(i1), Box::new(i2)]);
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from("a"), Bytes::from("1.1")),
@@ -209,7 +210,7 @@ fn test_task2_merge_empty() {
#[test]
fn test_task2_merge_error() {
let mut iter = MergeIterator::<MockIterator>::create(vec![]);
check_iter_result(&mut iter, vec![]);
check_iter_result_by_key(&mut iter, vec![]);
let i1 = MockIterator::new(vec![
(Bytes::from("a"), Bytes::from("1.1")),
@@ -276,7 +277,7 @@ fn test_task4_integration() {
storage.put(b"3", b"233333").unwrap();
{
let mut iter = storage.scan(Bound::Unbounded, Bound::Unbounded).unwrap();
check_iter_result(
check_lsm_iter_result_by_key(
&mut iter,
vec![
(Bytes::from_static(b"1"), Bytes::from_static(b"233333")),
@@ -294,7 +295,7 @@ fn test_task4_integration() {
let mut iter = storage
.scan(Bound::Included(b"2"), Bound::Included(b"3"))
.unwrap();
check_iter_result(
check_lsm_iter_result_by_key(
&mut iter,
vec![(Bytes::from_static(b"3"), Bytes::from_static(b"233333"))],
);

View File

@@ -2,39 +2,48 @@ use std::sync::Arc;
use bytes::Bytes;
use crate::block::{Block, BlockBuilder, BlockIterator};
use crate::{
block::{Block, BlockBuilder, BlockIterator},
key::{KeySlice, KeyVec},
};
#[test]
fn test_block_build_single_key() {
let mut builder = BlockBuilder::new(16);
assert!(builder.add(b"233", b"233333"));
assert!(builder.add(KeySlice::for_testing_from_slice_no_ts(b"233"), b"233333"));
builder.build();
}
#[test]
fn test_block_build_full() {
let mut builder = BlockBuilder::new(16);
assert!(builder.add(b"11", b"11"));
assert!(!builder.add(b"22", b"22"));
assert!(builder.add(KeySlice::for_testing_from_slice_no_ts(b"11"), b"11"));
assert!(!builder.add(KeySlice::for_testing_from_slice_no_ts(b"22"), b"22"));
builder.build();
}
#[test]
fn test_block_build_large_1() {
let mut builder = BlockBuilder::new(16);
assert!(builder.add(b"11", &b"1".repeat(100)));
assert!(builder.add(
KeySlice::for_testing_from_slice_no_ts(b"11"),
&b"1".repeat(100)
));
builder.build();
}
#[test]
fn test_block_build_large_2() {
let mut builder = BlockBuilder::new(16);
assert!(builder.add(b"11", b"1"));
assert!(!builder.add(b"11", &b"1".repeat(100)));
assert!(builder.add(KeySlice::for_testing_from_slice_no_ts(b"11"), b"1"));
assert!(!builder.add(
KeySlice::for_testing_from_slice_no_ts(b"11"),
&b"1".repeat(100)
));
}
fn key_of(idx: usize) -> Vec<u8> {
format!("key_{:03}", idx * 5).into_bytes()
fn key_of(idx: usize) -> KeyVec {
KeyVec::for_testing_from_vec_no_ts(format!("key_{:03}", idx * 5).into_bytes())
}
fn value_of(idx: usize) -> Vec<u8> {
@@ -50,7 +59,7 @@ fn generate_block() -> Block {
for idx in 0..num_of_keys() {
let key = key_of(idx);
let value = value_of(idx);
assert!(builder.add(&key[..], &value[..]));
assert!(builder.add(key.as_key_slice(), &value[..]));
}
builder.build()
}
@@ -88,11 +97,11 @@ fn test_block_iterator() {
let key = iter.key();
let value = iter.value();
assert_eq!(
key,
key_of(i),
key.for_testing_key_ref(),
key_of(i).for_testing_key_ref(),
"expected key: {:?}, actual key: {:?}",
as_bytes(&key_of(i)),
as_bytes(key)
as_bytes(key_of(i).for_testing_key_ref()),
as_bytes(key.for_testing_key_ref())
);
assert_eq!(
value,
@@ -110,17 +119,17 @@ fn test_block_iterator() {
#[test]
fn test_block_seek_key() {
let block = Arc::new(generate_block());
let mut iter = BlockIterator::create_and_seek_to_key(block, &key_of(0));
let mut iter = BlockIterator::create_and_seek_to_key(block, key_of(0).as_key_slice());
for offset in 1..=5 {
for i in 0..num_of_keys() {
let key = iter.key();
let value = iter.value();
assert_eq!(
key,
key_of(i),
key.for_testing_key_ref(),
key_of(i).for_testing_key_ref(),
"expected key: {:?}, actual key: {:?}",
as_bytes(&key_of(i)),
as_bytes(key)
as_bytes(key_of(i).for_testing_key_ref()),
as_bytes(key.for_testing_key_ref())
);
assert_eq!(
value,
@@ -129,8 +138,10 @@ fn test_block_seek_key() {
as_bytes(&value_of(i)),
as_bytes(value)
);
iter.seek_to_key(&format!("key_{:03}", i * 5 + offset).into_bytes());
iter.seek_to_key(KeySlice::for_testing_from_slice_no_ts(
&format!("key_{:03}", i * 5 + offset).into_bytes(),
));
}
iter.seek_to_key(b"k");
iter.seek_to_key(KeySlice::for_testing_from_slice_no_ts(b"k"));
}
}

View File

@@ -4,12 +4,13 @@ use bytes::Bytes;
use tempfile::{tempdir, TempDir};
use crate::iterators::StorageIterator;
use crate::key::{KeySlice, KeyVec};
use crate::table::{SsTable, SsTableBuilder, SsTableIterator};
#[test]
fn test_sst_build_single_key() {
let mut builder = SsTableBuilder::new(16);
builder.add(b"233", b"233333");
builder.add(KeySlice::for_testing_from_slice_no_ts(b"233"), b"233333");
let dir = tempdir().unwrap();
builder.build_for_test(dir.path().join("1.sst")).unwrap();
}
@@ -17,19 +18,19 @@ fn test_sst_build_single_key() {
#[test]
fn test_sst_build_two_blocks() {
let mut builder = SsTableBuilder::new(16);
builder.add(b"11", b"11");
builder.add(b"22", b"22");
builder.add(b"33", b"11");
builder.add(b"44", b"22");
builder.add(b"55", b"11");
builder.add(b"66", b"22");
builder.add(KeySlice::for_testing_from_slice_no_ts(b"11"), b"11");
builder.add(KeySlice::for_testing_from_slice_no_ts(b"22"), b"22");
builder.add(KeySlice::for_testing_from_slice_no_ts(b"33"), b"11");
builder.add(KeySlice::for_testing_from_slice_no_ts(b"44"), b"22");
builder.add(KeySlice::for_testing_from_slice_no_ts(b"55"), b"11");
builder.add(KeySlice::for_testing_from_slice_no_ts(b"66"), b"22");
assert!(builder.meta.len() >= 2);
let dir = tempdir().unwrap();
builder.build_for_test(dir.path().join("1.sst")).unwrap();
}
fn key_of(idx: usize) -> Vec<u8> {
format!("key_{:03}", idx * 5).into_bytes()
fn key_of(idx: usize) -> KeyVec {
KeyVec::for_testing_from_vec_no_ts(format!("key_{:03}", idx * 5).into_bytes())
}
fn value_of(idx: usize) -> Vec<u8> {
@@ -45,7 +46,7 @@ fn generate_sst() -> (TempDir, SsTable) {
for idx in 0..num_of_keys() {
let key = key_of(idx);
let value = value_of(idx);
builder.add(&key[..], &value[..]);
builder.add(key.as_key_slice(), &value[..]);
}
let dir = tempdir().unwrap();
let path = dir.path().join("1.sst");
@@ -63,8 +64,14 @@ fn test_sst_decode() {
let meta = sst.block_meta.clone();
let new_sst = SsTable::open_for_test(sst.file).unwrap();
assert_eq!(new_sst.block_meta, meta);
assert_eq!(new_sst.first_key(), &key_of(0));
assert_eq!(new_sst.last_key(), &key_of(num_of_keys() - 1));
assert_eq!(
new_sst.first_key().for_testing_key_ref(),
key_of(0).for_testing_key_ref()
);
assert_eq!(
new_sst.last_key().for_testing_key_ref(),
key_of(num_of_keys() - 1).for_testing_key_ref()
);
}
fn as_bytes(x: &[u8]) -> Bytes {
@@ -81,11 +88,11 @@ fn test_sst_iterator() {
let key = iter.key();
let value = iter.value();
assert_eq!(
key,
key_of(i),
key.for_testing_key_ref(),
key_of(i).for_testing_key_ref(),
"expected key: {:?}, actual key: {:?}",
as_bytes(&key_of(i)),
as_bytes(key)
as_bytes(key_of(i).for_testing_key_ref()),
as_bytes(key.for_testing_key_ref())
);
assert_eq!(
value,
@@ -104,17 +111,17 @@ fn test_sst_iterator() {
fn test_sst_seek_key() {
let (_dir, sst) = generate_sst();
let sst = Arc::new(sst);
let mut iter = SsTableIterator::create_and_seek_to_key(sst, &key_of(0)).unwrap();
let mut iter = SsTableIterator::create_and_seek_to_key(sst, key_of(0).as_key_slice()).unwrap();
for offset in 1..=5 {
for i in 0..num_of_keys() {
let key = iter.key();
let value = iter.value();
assert_eq!(
key,
key_of(i),
key.for_testing_key_ref(),
key_of(i).for_testing_key_ref(),
"expected key: {:?}, actual key: {:?}",
as_bytes(&key_of(i)),
as_bytes(key)
as_bytes(key_of(i).for_testing_key_ref()),
as_bytes(key.for_testing_key_ref())
);
assert_eq!(
value,
@@ -123,9 +130,12 @@ fn test_sst_seek_key() {
as_bytes(&value_of(i)),
as_bytes(value)
);
iter.seek_to_key(&format!("key_{:03}", i * 5 + offset).into_bytes())
.unwrap();
iter.seek_to_key(KeySlice::for_testing_from_slice_no_ts(
&format!("key_{:03}", i * 5 + offset).into_bytes(),
))
.unwrap();
}
iter.seek_to_key(b"k").unwrap();
iter.seek_to_key(KeySlice::for_testing_from_slice_no_ts(b"k"))
.unwrap();
}
}

View File

@@ -1,7 +1,7 @@
use std::ops::Bound;
use self::harness::generate_sst;
use self::harness::{check_iter_result, MockIterator};
use self::harness::{check_iter_result_by_key, MockIterator};
use self::harness::{check_lsm_iter_result_by_key, generate_sst};
use bytes::Bytes;
use tempfile::tempdir;
@@ -25,7 +25,7 @@ fn test_task1_merge_1() {
(Bytes::from("d"), Bytes::from("4.2")),
]);
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from("a"), Bytes::from("1.1")),
@@ -50,7 +50,7 @@ fn test_task1_merge_2() {
(Bytes::from("d"), Bytes::from("4.2")),
]);
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from("a"), Bytes::from("1.2")),
@@ -74,7 +74,7 @@ fn test_task1_merge_3() {
(Bytes::from("d"), Bytes::from("4.2")),
]);
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from("a"), Bytes::from("1.1")),
@@ -94,7 +94,7 @@ fn test_task1_merge_4() {
(Bytes::from("d"), Bytes::from("4.2")),
]);
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from("b"), Bytes::from("2.2")),
@@ -109,7 +109,7 @@ fn test_task1_merge_4() {
(Bytes::from("d"), Bytes::from("4.2")),
]);
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from("b"), Bytes::from("2.2")),
@@ -124,7 +124,7 @@ fn test_task1_merge_5() {
let i2 = MockIterator::new(vec![]);
let i1 = MockIterator::new(vec![]);
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
check_iter_result(&mut iter, vec![])
check_iter_result_by_key(&mut iter, vec![])
}
#[test]
@@ -164,7 +164,7 @@ fn test_task2_storage_scan() {
snapshot.sstables.insert(sst1.sst_id(), sst1.into());
*state = snapshot.into();
}
check_iter_result(
check_lsm_iter_result_by_key(
&mut storage.scan(Bound::Unbounded, Bound::Unbounded).unwrap(),
vec![
(Bytes::from("0"), Bytes::from("2333333")),
@@ -173,13 +173,13 @@ fn test_task2_storage_scan() {
(Bytes::from("3"), Bytes::from("23333")),
],
);
check_iter_result(
check_lsm_iter_result_by_key(
&mut storage
.scan(Bound::Included(b"1"), Bound::Included(b"2"))
.unwrap(),
vec![(Bytes::from("2"), Bytes::from("2333"))],
);
check_iter_result(
check_lsm_iter_result_by_key(
&mut storage
.scan(Bound::Excluded(b"1"), Bound::Excluded(b"3"))
.unwrap(),

View File

@@ -3,7 +3,7 @@ use std::{ops::Bound, time::Duration};
use bytes::Bytes;
use tempfile::tempdir;
use self::harness::{check_iter_result, sync};
use self::harness::{check_lsm_iter_result_by_key, sync};
use super::*;
use crate::{
@@ -41,7 +41,7 @@ fn test_task1_storage_scan() {
assert_eq!(state.imm_memtables.len(), 2);
}
check_iter_result(
check_lsm_iter_result_by_key(
&mut storage.scan(Bound::Unbounded, Bound::Unbounded).unwrap(),
vec![
(Bytes::from("0"), Bytes::from("2333333")),
@@ -50,13 +50,13 @@ fn test_task1_storage_scan() {
(Bytes::from("3"), Bytes::from("23333")),
],
);
check_iter_result(
check_lsm_iter_result_by_key(
&mut storage
.scan(Bound::Included(b"1"), Bound::Included(b"2"))
.unwrap(),
vec![(Bytes::from("2"), Bytes::from("2333"))],
);
check_iter_result(
check_lsm_iter_result_by_key(
&mut storage
.scan(Bound::Excluded(b"1"), Bound::Excluded(b"3"))
.unwrap(),

View File

@@ -1,6 +1,9 @@
use tempfile::tempdir;
use crate::table::{bloom::Bloom, FileObject, SsTable, SsTableBuilder};
use crate::{
key::KeySlice,
table::{bloom::Bloom, FileObject, SsTable, SsTableBuilder},
};
fn key_of(idx: usize) -> Vec<u8> {
format!("key_{:010}", idx * 5).into_bytes()
@@ -49,7 +52,7 @@ fn test_task2_sst_decode() {
for idx in 0..num_of_keys() {
let key = key_of(idx);
let value = value_of(idx);
builder.add(&key[..], &value[..]);
builder.add(KeySlice::for_testing_from_slice_no_ts(&key[..]), &value[..]);
}
let dir = tempdir().unwrap();
let path = dir.path().join("1.sst");
@@ -67,7 +70,7 @@ fn test_task3_block_key_compression() {
for idx in 0..num_of_keys() {
let key = key_of(idx);
let value = value_of(idx);
builder.add(&key[..], &value[..]);
builder.add(KeySlice::for_testing_from_slice_no_ts(&key[..]), &value[..]);
}
let dir = tempdir().unwrap();
let path = dir.path().join("1.sst");

View File

@@ -1,16 +1,15 @@
use std::{ops::Bound, path::Path, sync::Arc};
use self::harness::{check_iter_result_by_key, check_lsm_iter_result_by_key, sync};
use bytes::Bytes;
use tempfile::tempdir;
use week2_day1::harness::sync;
use self::harness::check_iter_result;
use super::*;
use crate::{
iterators::{
concat_iterator::SstConcatIterator, merge_iterator::MergeIterator, StorageIterator,
},
key::KeySlice,
lsm_storage::{LsmStorageInner, LsmStorageOptions, LsmStorageState},
table::{SsTable, SsTableBuilder, SsTableIterator},
};
@@ -51,7 +50,7 @@ fn test_task1_full_compaction() {
sync(&storage);
assert_eq!(storage.state.read().l0_sstables.len(), 3);
let mut iter = construct_merge_iterator_over_storage(&storage.state.read());
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from_static(b"0"), Bytes::from_static(b"")),
@@ -62,7 +61,7 @@ fn test_task1_full_compaction() {
storage.force_full_compaction().unwrap();
assert!(storage.state.read().l0_sstables.is_empty());
let mut iter = construct_merge_iterator_over_storage(&storage.state.read());
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![(Bytes::from_static(b"1"), Bytes::from_static(b"v2"))],
);
@@ -72,7 +71,7 @@ fn test_task1_full_compaction() {
storage.delete(b"1").unwrap();
sync(&storage);
let mut iter = construct_merge_iterator_over_storage(&storage.state.read());
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from_static(b"0"), Bytes::from_static(b"v3")),
@@ -83,7 +82,7 @@ fn test_task1_full_compaction() {
storage.force_full_compaction().unwrap();
assert!(storage.state.read().l0_sstables.is_empty());
let mut iter = construct_merge_iterator_over_storage(&storage.state.read());
check_iter_result(
check_iter_result_by_key(
&mut iter,
vec![
(Bytes::from_static(b"0"), Bytes::from_static(b"v3")),
@@ -101,7 +100,10 @@ fn generate_concat_sst(
let mut builder = SsTableBuilder::new(128);
for idx in start_key..end_key {
let key = format!("{:05}", idx);
builder.add(key.as_bytes(), b"test");
builder.add(
KeySlice::for_testing_from_slice_no_ts(key.as_bytes()),
b"test",
);
}
let path = dir.as_ref().join(format!("{id}.sst"));
builder.build_for_test(path).unwrap()
@@ -122,22 +124,25 @@ fn test_task2_concat_iterator() {
for key in 0..120 {
let iter = SstConcatIterator::create_and_seek_to_key(
sstables.clone(),
format!("{:05}", key).as_bytes(),
KeySlice::for_testing_from_slice_no_ts(format!("{:05}", key).as_bytes()),
)
.unwrap();
if key < 10 {
assert!(iter.is_valid());
assert_eq!(iter.key(), b"00010");
assert_eq!(iter.key().for_testing_key_ref(), b"00010");
} else if key >= 110 {
assert!(!iter.is_valid());
} else {
assert!(iter.is_valid());
assert_eq!(iter.key(), format!("{:05}", key).as_bytes());
assert_eq!(
iter.key().for_testing_key_ref(),
format!("{:05}", key).as_bytes()
);
}
}
let iter = SstConcatIterator::create_and_seek_to_first(sstables.clone()).unwrap();
assert!(iter.is_valid());
assert_eq!(iter.key(), b"00010");
assert_eq!(iter.key().for_testing_key_ref(), b"00010");
}
#[test]
@@ -169,7 +174,7 @@ fn test_task3_integration() {
assert!(storage.state.read().l0_sstables.is_empty());
assert!(!storage.state.read().levels[0].1.is_empty());
check_iter_result(
check_lsm_iter_result_by_key(
&mut storage.scan(Bound::Unbounded, Bound::Unbounded).unwrap(),
vec![
(Bytes::from("0"), Bytes::from("2333333")),