@@ -6,7 +6,7 @@ use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
pub use builder::SsTableBuilder;
|
||||
use bytes::{Buf, BufMut};
|
||||
pub use iterator::SsTableIterator;
|
||||
@@ -30,7 +30,7 @@ pub struct BlockMeta {
|
||||
impl BlockMeta {
|
||||
/// Encode block meta to a buffer.
|
||||
pub fn encode_block_meta(block_meta: &[BlockMeta], buf: &mut Vec<u8>) {
|
||||
let mut estimated_size = 0;
|
||||
let mut estimated_size = std::mem::size_of::<u32>();
|
||||
for meta in block_meta {
|
||||
// The size of offset
|
||||
estimated_size += std::mem::size_of::<u32>();
|
||||
@@ -43,10 +43,12 @@ impl BlockMeta {
|
||||
// The size of actual key
|
||||
estimated_size += meta.last_key.len();
|
||||
}
|
||||
estimated_size += std::mem::size_of::<u32>();
|
||||
// Reserve the space to improve performance, especially when the size of incoming data is
|
||||
// large
|
||||
buf.reserve(estimated_size);
|
||||
let original_len = buf.len();
|
||||
buf.put_u32(block_meta.len() as u32);
|
||||
for meta in block_meta {
|
||||
buf.put_u32(meta.offset as u32);
|
||||
buf.put_u16(meta.first_key.len() as u16);
|
||||
@@ -54,13 +56,16 @@ impl BlockMeta {
|
||||
buf.put_u16(meta.last_key.len() as u16);
|
||||
buf.put_slice(meta.last_key.raw_ref());
|
||||
}
|
||||
buf.put_u32(crc32fast::hash(&buf[original_len + 4..]));
|
||||
assert_eq!(estimated_size, buf.len() - original_len);
|
||||
}
|
||||
|
||||
/// Decode block meta from a buffer.
|
||||
pub fn decode_block_meta(mut buf: impl Buf) -> Vec<BlockMeta> {
|
||||
pub fn decode_block_meta(mut buf: &[u8]) -> Result<Vec<BlockMeta>> {
|
||||
let mut block_meta = Vec::new();
|
||||
while buf.has_remaining() {
|
||||
let num = buf.get_u32() as usize;
|
||||
let checksum = crc32fast::hash(&buf[..buf.remaining() - 4]);
|
||||
for _ in 0..num {
|
||||
let offset = buf.get_u32() as usize;
|
||||
let first_key_len = buf.get_u16() as usize;
|
||||
let first_key = KeyBytes::from_bytes(buf.copy_to_bytes(first_key_len));
|
||||
@@ -72,7 +77,11 @@ impl BlockMeta {
|
||||
last_key,
|
||||
});
|
||||
}
|
||||
block_meta
|
||||
if buf.get_u32() != checksum {
|
||||
bail!("meta checksum mismatched");
|
||||
}
|
||||
|
||||
Ok(block_meta)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +150,7 @@ impl SsTable {
|
||||
let raw_meta_offset = file.read(bloom_offset - 4, 4)?;
|
||||
let block_meta_offset = (&raw_meta_offset[..]).get_u32() as u64;
|
||||
let raw_meta = file.read(block_meta_offset, bloom_offset - 4 - block_meta_offset)?;
|
||||
let block_meta = BlockMeta::decode_block_meta(&raw_meta[..]);
|
||||
let block_meta = BlockMeta::decode_block_meta(&raw_meta[..])?;
|
||||
Ok(Self {
|
||||
file,
|
||||
first_key: block_meta.first().unwrap().first_key.clone(),
|
||||
@@ -180,10 +189,16 @@ impl SsTable {
|
||||
.block_meta
|
||||
.get(block_idx + 1)
|
||||
.map_or(self.block_meta_offset, |x| x.offset);
|
||||
let block_data = self
|
||||
let block_len = offset_end - offset - 4;
|
||||
let block_data_with_chksum: Vec<u8> = self
|
||||
.file
|
||||
.read(offset as u64, (offset_end - offset) as u64)?;
|
||||
Ok(Arc::new(Block::decode(&block_data[..])))
|
||||
let block_data = &block_data_with_chksum[..block_len];
|
||||
let checksum = (&block_data_with_chksum[block_len..]).get_u32();
|
||||
if checksum != crc32fast::hash(block_data) {
|
||||
bail!("block checksum mismatched");
|
||||
}
|
||||
Ok(Arc::new(Block::decode(block_data)))
|
||||
}
|
||||
|
||||
/// Read a block from disk, with block cache.
|
||||
|
||||
Reference in New Issue
Block a user