finish week 1 day 5 read path
Signed-off-by: Alex Chi Z <iskyzh@gmail.com>
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use bytes::Bytes;
|
||||
|
||||
use crate::iterators::StorageIterator;
|
||||
use crate::{
|
||||
iterators::StorageIterator,
|
||||
lsm_storage::BlockCache,
|
||||
table::{SsTable, SsTableBuilder},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MockIterator {
|
||||
@@ -68,3 +74,52 @@ impl StorageIterator for MockIterator {
|
||||
self.index < self.data.len()
|
||||
}
|
||||
}
|
||||
|
||||
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)>) {
|
||||
for (k, v) in expected {
|
||||
assert!(iter.is_valid());
|
||||
assert_eq!(
|
||||
k,
|
||||
iter.key(),
|
||||
"expected key: {:?}, actual key: {:?}",
|
||||
k,
|
||||
as_bytes(iter.key()),
|
||||
);
|
||||
assert_eq!(
|
||||
v,
|
||||
iter.value(),
|
||||
"expected value: {:?}, actual value: {:?}",
|
||||
v,
|
||||
as_bytes(iter.value()),
|
||||
);
|
||||
iter.next().unwrap();
|
||||
}
|
||||
assert!(!iter.is_valid());
|
||||
}
|
||||
|
||||
pub fn expect_iter_error(mut iter: impl StorageIterator) {
|
||||
loop {
|
||||
match iter.next() {
|
||||
Ok(_) if iter.is_valid() => continue,
|
||||
Ok(_) => panic!("expect an error"),
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_sst(
|
||||
id: usize,
|
||||
path: impl AsRef<Path>,
|
||||
data: Vec<(Bytes, Bytes)>,
|
||||
block_cache: Option<Arc<BlockCache>>,
|
||||
) -> SsTable {
|
||||
let mut builder = SsTableBuilder::new(128);
|
||||
for (key, value) in data {
|
||||
builder.add(&key[..], &value[..]);
|
||||
}
|
||||
builder.build(id, block_cache, path.as_ref()).unwrap()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
mem_table::MemTable,
|
||||
};
|
||||
|
||||
use super::harness::MockIterator;
|
||||
use super::harness::{check_iter_result, expect_iter_error, MockIterator};
|
||||
|
||||
#[test]
|
||||
fn test_task1_memtable_iter() {
|
||||
@@ -78,42 +78,6 @@ fn test_task1_empty_memtable_iter() {
|
||||
}
|
||||
}
|
||||
|
||||
fn as_bytes(x: &[u8]) -> Bytes {
|
||||
Bytes::copy_from_slice(x)
|
||||
}
|
||||
|
||||
fn check_iter_result(iter: &mut impl StorageIterator, expected: Vec<(Bytes, Bytes)>) {
|
||||
for (k, v) in expected {
|
||||
assert!(iter.is_valid());
|
||||
assert_eq!(
|
||||
k,
|
||||
iter.key(),
|
||||
"expected key: {:?}, actual key: {:?}",
|
||||
k,
|
||||
as_bytes(iter.key()),
|
||||
);
|
||||
assert_eq!(
|
||||
v,
|
||||
iter.value(),
|
||||
"expected value: {:?}, actual value: {:?}",
|
||||
v,
|
||||
as_bytes(iter.value()),
|
||||
);
|
||||
iter.next().unwrap();
|
||||
}
|
||||
assert!(!iter.is_valid());
|
||||
}
|
||||
|
||||
fn expect_iter_error(mut iter: impl StorageIterator) {
|
||||
loop {
|
||||
match iter.next() {
|
||||
Ok(_) if iter.is_valid() => continue,
|
||||
Ok(_) => panic!("expect an error"),
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task2_merge_1() {
|
||||
let i1 = MockIterator::new(vec![
|
||||
|
||||
187
mini-lsm/src/tests/week1_day5.rs
Normal file
187
mini-lsm/src/tests/week1_day5.rs
Normal file
@@ -0,0 +1,187 @@
|
||||
use std::ops::Bound;
|
||||
|
||||
use bytes::Bytes;
|
||||
use tempfile::tempdir;
|
||||
use week1_day5::harness::generate_sst;
|
||||
|
||||
use self::harness::{check_iter_result, MockIterator};
|
||||
|
||||
use super::*;
|
||||
use crate::{iterators::two_merge_iterator::TwoMergeIterator, lsm_storage::LsmStorageOptions};
|
||||
|
||||
#[test]
|
||||
fn test_task1_merge_1() {
|
||||
let i1 = MockIterator::new(vec![
|
||||
(Bytes::from("a"), Bytes::from("1.1")),
|
||||
(Bytes::from("b"), Bytes::from("2.1")),
|
||||
(Bytes::from("c"), Bytes::from("3.1")),
|
||||
]);
|
||||
let i2 = MockIterator::new(vec![
|
||||
(Bytes::from("a"), Bytes::from("1.2")),
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
]);
|
||||
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
|
||||
check_iter_result(
|
||||
&mut iter,
|
||||
vec![
|
||||
(Bytes::from("a"), Bytes::from("1.1")),
|
||||
(Bytes::from("b"), Bytes::from("2.1")),
|
||||
(Bytes::from("c"), Bytes::from("3.1")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task1_merge_2() {
|
||||
let i2 = MockIterator::new(vec![
|
||||
(Bytes::from("a"), Bytes::from("1.1")),
|
||||
(Bytes::from("b"), Bytes::from("2.1")),
|
||||
(Bytes::from("c"), Bytes::from("3.1")),
|
||||
]);
|
||||
let i1 = MockIterator::new(vec![
|
||||
(Bytes::from("a"), Bytes::from("1.2")),
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
]);
|
||||
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
|
||||
check_iter_result(
|
||||
&mut iter,
|
||||
vec![
|
||||
(Bytes::from("a"), Bytes::from("1.2")),
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task1_merge_3() {
|
||||
let i2 = MockIterator::new(vec![
|
||||
(Bytes::from("a"), Bytes::from("1.1")),
|
||||
(Bytes::from("b"), Bytes::from("2.1")),
|
||||
(Bytes::from("c"), Bytes::from("3.1")),
|
||||
]);
|
||||
let i1 = MockIterator::new(vec![
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
]);
|
||||
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
|
||||
check_iter_result(
|
||||
&mut iter,
|
||||
vec![
|
||||
(Bytes::from("a"), Bytes::from("1.1")),
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task1_merge_4() {
|
||||
let i2 = MockIterator::new(vec![]);
|
||||
let i1 = MockIterator::new(vec![
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
]);
|
||||
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
|
||||
check_iter_result(
|
||||
&mut iter,
|
||||
vec![
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
],
|
||||
);
|
||||
let i1 = MockIterator::new(vec![]);
|
||||
let i2 = MockIterator::new(vec![
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
]);
|
||||
let mut iter = TwoMergeIterator::create(i1, i2).unwrap();
|
||||
check_iter_result(
|
||||
&mut iter,
|
||||
vec![
|
||||
(Bytes::from("b"), Bytes::from("2.2")),
|
||||
(Bytes::from("c"), Bytes::from("3.2")),
|
||||
(Bytes::from("d"), Bytes::from("4.2")),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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![])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task2_storage_scan() {
|
||||
use crate::lsm_storage::LsmStorageInner;
|
||||
let dir = tempdir().unwrap();
|
||||
let storage = LsmStorageInner::open(&dir, LsmStorageOptions::default_for_week1_test()).unwrap();
|
||||
storage.put(b"1", b"233").unwrap();
|
||||
storage.put(b"2", b"2333").unwrap();
|
||||
storage.put(b"00", b"2333").unwrap();
|
||||
storage
|
||||
.force_freeze_memtable(&storage.state_lock.lock())
|
||||
.unwrap();
|
||||
storage.put(b"3", b"23333").unwrap();
|
||||
storage.delete(b"1").unwrap();
|
||||
let sst1 = generate_sst(
|
||||
10,
|
||||
dir.path().join("10.sst"),
|
||||
vec![
|
||||
(Bytes::from_static(b"0"), Bytes::from_static(b"2333333")),
|
||||
(Bytes::from_static(b"00"), Bytes::from_static(b"2333333")),
|
||||
(Bytes::from_static(b"4"), Bytes::from_static(b"23")),
|
||||
],
|
||||
Some(storage.block_cache.clone()),
|
||||
);
|
||||
let sst2 = generate_sst(
|
||||
11,
|
||||
dir.path().join("11.sst"),
|
||||
vec![(Bytes::from_static(b"4"), Bytes::from_static(b""))],
|
||||
Some(storage.block_cache.clone()),
|
||||
);
|
||||
{
|
||||
let mut state = storage.state.write();
|
||||
let mut snapshot = state.as_ref().clone();
|
||||
snapshot.l0_sstables.push(sst2.sst_id()); // this is the latest SST
|
||||
snapshot.l0_sstables.push(sst1.sst_id());
|
||||
snapshot.sstables.insert(sst2.sst_id(), sst2.into());
|
||||
snapshot.sstables.insert(sst1.sst_id(), sst1.into());
|
||||
*state = snapshot.into();
|
||||
}
|
||||
check_iter_result(
|
||||
&mut storage.scan(Bound::Unbounded, Bound::Unbounded).unwrap(),
|
||||
vec![
|
||||
(Bytes::from("0"), Bytes::from("2333333")),
|
||||
(Bytes::from("00"), Bytes::from("2333")),
|
||||
(Bytes::from("2"), Bytes::from("2333")),
|
||||
(Bytes::from("3"), Bytes::from("23333")),
|
||||
],
|
||||
);
|
||||
check_iter_result(
|
||||
&mut storage
|
||||
.scan(Bound::Included(b"1"), Bound::Included(b"2"))
|
||||
.unwrap(),
|
||||
vec![(Bytes::from("2"), Bytes::from("2333"))],
|
||||
);
|
||||
check_iter_result(
|
||||
&mut storage
|
||||
.scan(Bound::Excluded(b"1"), Bound::Excluded(b"3"))
|
||||
.unwrap(),
|
||||
vec![(Bytes::from("2"), Bytes::from("2333"))],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user