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:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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"))],
|
||||
);
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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")),
|
||||
|
||||
Reference in New Issue
Block a user