@@ -4,6 +4,7 @@ members = [
|
|||||||
"xtask",
|
"xtask",
|
||||||
"mini-lsm-starter",
|
"mini-lsm-starter",
|
||||||
]
|
]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@@ -19,6 +19,7 @@ impl<I: StorageIterator> PartialEq for HeapWrapper<I> {
|
|||||||
impl<I: StorageIterator> Eq for HeapWrapper<I> {}
|
impl<I: StorageIterator> Eq for HeapWrapper<I> {}
|
||||||
|
|
||||||
impl<I: StorageIterator> PartialOrd for HeapWrapper<I> {
|
impl<I: StorageIterator> PartialOrd for HeapWrapper<I> {
|
||||||
|
#[allow(clippy::non_canonical_partial_ord_impl)]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||||
match self.1.key().cmp(other.1.key()) {
|
match self.1.key().cmp(other.1.key()) {
|
||||||
cmp::Ordering::Greater => Some(cmp::Ordering::Greater),
|
cmp::Ordering::Greater => Some(cmp::Ordering::Greater),
|
||||||
|
@@ -27,13 +27,16 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(data: &[u8]) -> Self {
|
pub fn decode(data: &[u8]) -> Self {
|
||||||
|
// get number of elements in the block
|
||||||
let entry_offsets_len = (&data[data.len() - SIZEOF_U16..]).get_u16() as usize;
|
let entry_offsets_len = (&data[data.len() - SIZEOF_U16..]).get_u16() as usize;
|
||||||
let data_end = data.len() - SIZEOF_U16 - entry_offsets_len * SIZEOF_U16;
|
let data_end = data.len() - SIZEOF_U16 - entry_offsets_len * SIZEOF_U16;
|
||||||
let offsets_raw = &data[data_end..data.len() - SIZEOF_U16];
|
let offsets_raw = &data[data_end..data.len() - SIZEOF_U16];
|
||||||
|
// get offset array
|
||||||
let offsets = offsets_raw
|
let offsets = offsets_raw
|
||||||
.chunks(SIZEOF_U16)
|
.chunks(SIZEOF_U16)
|
||||||
.map(|mut x| x.get_u16())
|
.map(|mut x| x.get_u16())
|
||||||
.collect();
|
.collect();
|
||||||
|
// retrieve data
|
||||||
let data = data[0..data_end].to_vec();
|
let data = data[0..data_end].to_vec();
|
||||||
Self { data, offsets }
|
Self { data, offsets }
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,7 @@ use super::{Block, SIZEOF_U16};
|
|||||||
pub struct BlockBuilder {
|
pub struct BlockBuilder {
|
||||||
/// Offsets of each key-value entries.
|
/// Offsets of each key-value entries.
|
||||||
offsets: Vec<u16>,
|
offsets: Vec<u16>,
|
||||||
/// All key-value pairs in the block.
|
/// All serialized key-value pairs in the block.
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
/// The expected block size.
|
/// The expected block size.
|
||||||
block_size: usize,
|
block_size: usize,
|
||||||
@@ -23,29 +23,33 @@ impl BlockBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn estimated_size(&self) -> usize {
|
fn estimated_size(&self) -> usize {
|
||||||
self.offsets.len() * SIZEOF_U16 + self.data.len() + SIZEOF_U16
|
SIZEOF_U16 /* number of key-value pairs in the block */ + self.offsets.len() * SIZEOF_U16 /* offsets */ + self.data.len()
|
||||||
|
/* key-value pairs */
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a key-value pair to the block. Returns false when the block is full.
|
/// Adds a key-value pair to the block. Returns false when the block is full.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn add(&mut self, key: &[u8], value: &[u8]) -> bool {
|
pub fn add(&mut self, key: &[u8], value: &[u8]) -> bool {
|
||||||
assert!(!key.is_empty(), "key must not be empty");
|
assert!(!key.is_empty(), "key must not be empty");
|
||||||
// The overhead here is `key_len` + `val_len` + `offset`, each is of type `u16`
|
if self.estimated_size() + key.len() + value.len() + SIZEOF_U16 * 3 /* key_len, value_len and offset */ > self.block_size
|
||||||
if self.estimated_size() + key.len() + value.len() + SIZEOF_U16 * 3 > self.block_size
|
|
||||||
&& !self.is_empty()
|
&& !self.is_empty()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// The offsets should be updated at first, to maintain the correct offset
|
// Add the offset of the data into the offset array.
|
||||||
self.offsets.push(self.data.len() as u16);
|
self.offsets.push(self.data.len() as u16);
|
||||||
|
// Encode key length.
|
||||||
self.data.put_u16(key.len() as u16);
|
self.data.put_u16(key.len() as u16);
|
||||||
|
// Encode key content.
|
||||||
self.data.put(key);
|
self.data.put(key);
|
||||||
|
// Encode value length.
|
||||||
self.data.put_u16(value.len() as u16);
|
self.data.put_u16(value.len() as u16);
|
||||||
|
// Encode value content.
|
||||||
self.data.put(value);
|
self.data.put(value);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if there is no key-value pair in the block.
|
/// Check if there are no key-value pairs in the block.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.offsets.is_empty()
|
self.offsets.is_empty()
|
||||||
}
|
}
|
||||||
|
@@ -6,9 +6,13 @@ use super::Block;
|
|||||||
|
|
||||||
/// Iterates on a block.
|
/// Iterates on a block.
|
||||||
pub struct BlockIterator {
|
pub struct BlockIterator {
|
||||||
|
/// reference to the block
|
||||||
block: Arc<Block>,
|
block: Arc<Block>,
|
||||||
|
/// the current key at the iterator position
|
||||||
key: Vec<u8>,
|
key: Vec<u8>,
|
||||||
|
/// the current value at the iterator position
|
||||||
value: Vec<u8>,
|
value: Vec<u8>,
|
||||||
|
/// the current index at the iterator position
|
||||||
idx: usize,
|
idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@ impl<I: StorageIterator> PartialEq for HeapWrapper<I> {
|
|||||||
impl<I: StorageIterator> Eq for HeapWrapper<I> {}
|
impl<I: StorageIterator> Eq for HeapWrapper<I> {}
|
||||||
|
|
||||||
impl<I: StorageIterator> PartialOrd for HeapWrapper<I> {
|
impl<I: StorageIterator> PartialOrd for HeapWrapper<I> {
|
||||||
|
#[allow(clippy::non_canonical_partial_ord_impl)]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||||
match self.1.key().cmp(other.1.key()) {
|
match self.1.key().cmp(other.1.key()) {
|
||||||
cmp::Ordering::Greater => Some(cmp::Ordering::Greater),
|
cmp::Ordering::Greater => Some(cmp::Ordering::Greater),
|
||||||
|
@@ -86,8 +86,7 @@ impl LsmStorage {
|
|||||||
return Ok(Some(value));
|
return Ok(Some(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut iters = Vec::new();
|
let mut iters = Vec::with_capacity(snapshot.l0_sstables.len());
|
||||||
iters.reserve(snapshot.l0_sstables.len());
|
|
||||||
for table in snapshot.l0_sstables.iter().rev() {
|
for table in snapshot.l0_sstables.iter().rev() {
|
||||||
iters.push(Box::new(SsTableIterator::create_and_seek_to_key(
|
iters.push(Box::new(SsTableIterator::create_and_seek_to_key(
|
||||||
table.clone(),
|
table.clone(),
|
||||||
@@ -190,16 +189,14 @@ impl LsmStorage {
|
|||||||
Arc::clone(&guard)
|
Arc::clone(&guard)
|
||||||
}; // drop global lock here
|
}; // drop global lock here
|
||||||
|
|
||||||
let mut memtable_iters = Vec::new();
|
let mut memtable_iters = Vec::with_capacity(snapshot.imm_memtables.len() + 1);
|
||||||
memtable_iters.reserve(snapshot.imm_memtables.len() + 1);
|
|
||||||
memtable_iters.push(Box::new(snapshot.memtable.scan(lower, upper)));
|
memtable_iters.push(Box::new(snapshot.memtable.scan(lower, upper)));
|
||||||
for memtable in snapshot.imm_memtables.iter().rev() {
|
for memtable in snapshot.imm_memtables.iter().rev() {
|
||||||
memtable_iters.push(Box::new(memtable.scan(lower, upper)));
|
memtable_iters.push(Box::new(memtable.scan(lower, upper)));
|
||||||
}
|
}
|
||||||
let memtable_iter = MergeIterator::create(memtable_iters);
|
let memtable_iter = MergeIterator::create(memtable_iters);
|
||||||
|
|
||||||
let mut table_iters = Vec::new();
|
let mut table_iters = Vec::with_capacity(snapshot.l0_sstables.len());
|
||||||
table_iters.reserve(snapshot.l0_sstables.len());
|
|
||||||
for table in snapshot.l0_sstables.iter().rev() {
|
for table in snapshot.l0_sstables.iter().rev() {
|
||||||
let iter = match lower {
|
let iter = match lower {
|
||||||
Bound::Included(key) => {
|
Bound::Included(key) => {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.70.0"
|
channel = "stable"
|
||||||
components = [ "rustfmt", "clippy" ]
|
components = [ "rustfmt", "clippy" ]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
|
Reference in New Issue
Block a user