2022-12-23 21:14:11 -05:00
|
|
|
mod builder;
|
|
|
|
|
mod iterator;
|
|
|
|
|
|
|
|
|
|
use std::{path::Path, sync::Arc};
|
|
|
|
|
|
|
|
|
|
pub use builder::SsTableBuilder;
|
|
|
|
|
use bytes::{Buf, BufMut, Bytes};
|
|
|
|
|
pub use iterator::SsTableIterator;
|
|
|
|
|
|
|
|
|
|
use crate::block::Block;
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
|
pub struct BlockMeta {
|
2022-12-23 22:32:30 -05:00
|
|
|
/// Offset of this data block.
|
2022-12-23 21:14:11 -05:00
|
|
|
pub offset: usize,
|
2022-12-23 22:32:30 -05:00
|
|
|
/// The first key of the data block.
|
2022-12-23 21:14:11 -05:00
|
|
|
pub first_key: Bytes,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl BlockMeta {
|
2022-12-23 22:32:30 -05:00
|
|
|
/// Encode block meta to a buffer.
|
2022-12-23 21:14:11 -05:00
|
|
|
pub fn encode_block_meta(block_meta: &[BlockMeta], buf: &mut Vec<u8>) {
|
|
|
|
|
let mut estimated_size = 0;
|
|
|
|
|
for meta in block_meta {
|
|
|
|
|
estimated_size += std::mem::size_of::<u32>();
|
|
|
|
|
estimated_size += std::mem::size_of::<u16>();
|
|
|
|
|
estimated_size += meta.first_key.len();
|
|
|
|
|
}
|
|
|
|
|
buf.reserve(estimated_size);
|
|
|
|
|
let original_len = buf.len();
|
|
|
|
|
for meta in block_meta {
|
|
|
|
|
buf.put_u32(meta.offset as u32);
|
|
|
|
|
buf.put_u16(meta.first_key.len() as u16);
|
|
|
|
|
buf.put_slice(&meta.first_key);
|
|
|
|
|
}
|
|
|
|
|
assert_eq!(estimated_size, buf.len() - original_len);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-23 22:32:30 -05:00
|
|
|
/// Decode block meta from a buffer.
|
2022-12-23 21:14:11 -05:00
|
|
|
pub fn decode_block_meta(mut buf: impl Buf) -> Vec<BlockMeta> {
|
|
|
|
|
let mut block_meta = Vec::new();
|
|
|
|
|
while buf.has_remaining() {
|
|
|
|
|
let offset = buf.get_u32() as usize;
|
|
|
|
|
let first_key_len = buf.get_u16() as usize;
|
|
|
|
|
let first_key = buf.copy_to_bytes(first_key_len);
|
|
|
|
|
block_meta.push(BlockMeta { offset, first_key });
|
|
|
|
|
}
|
|
|
|
|
block_meta
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-23 22:32:30 -05:00
|
|
|
/// A file object.
|
2022-12-23 21:14:11 -05:00
|
|
|
pub struct FileObject(Bytes);
|
|
|
|
|
|
|
|
|
|
impl FileObject {
|
|
|
|
|
pub fn read(&self, offset: u64, len: u64) -> Result<Vec<u8>> {
|
|
|
|
|
Ok(self.0[offset as usize..(offset + len) as usize].to_vec())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn size(&self) -> u64 {
|
|
|
|
|
self.0.len() as u64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn create(_path: &Path, data: Vec<u8>) -> Result<Self> {
|
|
|
|
|
Ok(FileObject(data.into()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn open(_path: &Path) -> Result<Self> {
|
|
|
|
|
unimplemented!()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct SsTable {
|
|
|
|
|
file: FileObject,
|
|
|
|
|
block_metas: Vec<BlockMeta>,
|
|
|
|
|
block_meta_offset: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl SsTable {
|
2022-12-23 22:32:30 -05:00
|
|
|
/// Open SSTable from a file.
|
2022-12-23 21:14:11 -05:00
|
|
|
pub fn open(file: FileObject) -> Result<Self> {
|
|
|
|
|
let len = file.size();
|
|
|
|
|
let raw_meta_offset = file.read(len - 4, 4)?;
|
|
|
|
|
let block_meta_offset = (&raw_meta_offset[..]).get_u32() as u64;
|
|
|
|
|
let raw_meta = file.read(block_meta_offset, len - 4 - block_meta_offset)?;
|
|
|
|
|
Ok(Self {
|
|
|
|
|
file,
|
|
|
|
|
block_metas: BlockMeta::decode_block_meta(&raw_meta[..]),
|
|
|
|
|
block_meta_offset: block_meta_offset as usize,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-23 22:32:30 -05:00
|
|
|
/// Read a block from the disk.
|
|
|
|
|
pub fn read_block(&self, block_idx: usize) -> Result<Arc<Block>> {
|
2022-12-23 21:14:11 -05:00
|
|
|
let offset = self.block_metas[block_idx].offset;
|
|
|
|
|
let offset_end = self
|
|
|
|
|
.block_metas
|
|
|
|
|
.get(block_idx + 1)
|
|
|
|
|
.map(|x| x.offset)
|
|
|
|
|
.unwrap_or(self.block_meta_offset);
|
|
|
|
|
let block_data = self
|
|
|
|
|
.file
|
|
|
|
|
.read(offset as u64, (offset_end - offset) as u64)?;
|
|
|
|
|
Ok(Arc::new(Block::decode(&block_data[..])))
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-23 22:32:30 -05:00
|
|
|
/// Find the block that may contain `key`.
|
|
|
|
|
pub fn find_block_idx(&self, key: &[u8]) -> usize {
|
2022-12-23 21:14:11 -05:00
|
|
|
self.block_metas
|
|
|
|
|
.partition_point(|meta| meta.first_key <= key)
|
|
|
|
|
.saturating_sub(1)
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-23 22:32:30 -05:00
|
|
|
/// Get number of data blocks.
|
|
|
|
|
pub fn num_of_blocks(&self) -> usize {
|
2022-12-23 21:14:11 -05:00
|
|
|
self.block_metas.len()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests;
|