finish week 1 day 5 read path

Signed-off-by: Alex Chi Z <iskyzh@gmail.com>
This commit is contained in:
Alex Chi Z
2024-01-21 15:26:22 +08:00
parent 99da8855b8
commit 8be0a2d475
11 changed files with 307 additions and 53 deletions

View File

@@ -23,7 +23,7 @@ impl<A: StorageIterator, B: StorageIterator> TwoMergeIterator<A, B> {
fn skip_b(&mut self) -> Result<()> {
if self.a.is_valid() {
while self.b.is_valid() && self.b.key() == self.a.key() {
if self.b.is_valid() && self.b.key() == self.a.key() {
self.b.next()?;
}
}

View File

@@ -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()
}

View File

@@ -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![

View 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"))],
);
}