use std::cmp::Ordering;
use std::sync::Arc;
use integer_encoding::{FixedInt, FixedIntWriter, VarInt, VarIntWriter};
use crate::error::{Error, Result};
use crate::sstable::error::SSTableError;
use crate::{Comparator, InternalKey, InternalKeyRef, LSMIterator};
pub(crate) type BlockData = Vec<u8>;
#[derive(Eq, PartialEq, Debug, Clone, Default)]
pub(crate) struct BlockHandle {
pub(crate) offset: usize,
pub(crate) size: usize,
}
impl BlockHandle {
pub(crate) fn new(offset: usize, size: usize) -> BlockHandle {
BlockHandle {
offset,
size,
}
}
pub(crate) fn offset(&self) -> usize {
self.offset
}
pub(crate) fn size(&self) -> usize {
self.size
}
#[inline]
pub(crate) fn encode_into(&self, dst: &mut [u8]) -> usize {
assert!(dst.len() >= self.offset.required_space() + self.size.required_space());
let off = self.offset.encode_var(dst);
let size = self.size.encode_var(&mut dst[off..]);
off + size
}
#[inline]
pub(crate) fn encode(&self) -> Vec<u8> {
let cap = self.offset.required_space() + self.size.required_space();
let mut v = vec![0; cap];
self.encode_into(&mut v);
v
}
pub(crate) fn decode(src: &[u8]) -> Result<(Self, usize)> {
let (off, offsize) = usize::decode_var(src).ok_or(SSTableError::CorruptedBlockHandle)?;
let (sz, szsize) =
usize::decode_var(&src[offsize..]).ok_or(SSTableError::CorruptedBlockHandle)?;
Ok((
BlockHandle {
offset: off,
size: sz,
},
offsize + szsize,
))
}
}
#[derive(Clone)]
pub(crate) struct Block {
pub(crate) block: BlockData,
comparator: Arc<dyn Comparator>,
}
impl Block {
pub(crate) fn new(data: BlockData, comparator: Arc<dyn Comparator>) -> Block {
assert!(data.len() > 4);
Block {
block: data,
comparator,
}
}
pub(crate) fn iter(&self) -> Result<BlockIterator> {
BlockIterator::new(Arc::clone(&self.comparator), self.block.clone())
}
pub(crate) fn size(&self) -> usize {
self.block.len()
}
}
pub(crate) struct BlockWriter {
restart_interval: usize,
buffer: Vec<u8>,
restart_points: Vec<u32>,
restart_counter: usize,
pub(crate) last_key: Vec<u8>,
num_entries: usize,
internal_cmp: Arc<dyn Comparator>,
}
impl BlockWriter {
pub(crate) fn new(
size: usize,
restart_interval: usize,
internal_cmp: Arc<dyn Comparator>,
) -> Self {
BlockWriter {
internal_cmp,
buffer: Vec::with_capacity(size),
restart_interval,
restart_points: vec![0], last_key: Vec::new(),
restart_counter: 0,
num_entries: 0,
}
}
pub(crate) fn add(&mut self, key: &[u8], value: &[u8]) -> Result<()> {
assert!(self.restart_counter <= self.restart_interval);
if !self.buffer.is_empty() {
let cmp_result = self.internal_cmp.compare(self.last_key.as_slice(), key);
if cmp_result != Ordering::Less {
let last_internal_key = InternalKey::decode(self.last_key.as_slice());
let current_internal_key = InternalKey::decode(key);
log::error!(
"[BLOCK] Key ordering violation detected!\n\
Last Key:\n\
User Key (UTF-8): {:?}\n\
User Key (bytes): {:?}\n\
Seq Num: {}\n\
Kind: {:?}\n\
Timestamp: {}\n\
Full InternalKey: {:?}\n\
Current Key:\n\
User Key (UTF-8): {:?}\n\
User Key (bytes): {:?}\n\
Seq Num: {}\n\
Kind: {:?}\n\
Timestamp: {}\n\
Full InternalKey: {:?}\n\
Comparison result: {:?} (expected: Less)\n\
Block state:\n\
Entries in block: {}\n\
Buffer size: {} bytes",
String::from_utf8_lossy(&last_internal_key.user_key),
last_internal_key.user_key.as_slice(),
last_internal_key.seq_num(),
last_internal_key.kind(),
last_internal_key.timestamp,
self.last_key.as_slice(),
String::from_utf8_lossy(¤t_internal_key.user_key),
current_internal_key.user_key.as_slice(),
current_internal_key.seq_num(),
current_internal_key.kind(),
current_internal_key.timestamp,
key,
cmp_result,
self.num_entries,
self.buffer.len()
);
return Err(Error::KeyNotInOrder);
}
assert!(cmp_result == Ordering::Less);
}
let mut shared_prefix_length = 0;
if self.restart_counter < self.restart_interval {
shared_prefix_length = self.calculate_shared_prefix_length(&self.last_key, key);
} else {
self.restart_points.push(self.buffer.len() as u32);
self.restart_counter = 0;
}
self.write_key_value_pair_to_buffer(shared_prefix_length, key, value)?;
self.last_key.clear();
self.last_key.extend_from_slice(key);
self.restart_counter += 1;
self.num_entries += 1;
Ok(())
}
fn calculate_shared_prefix_length(&self, a: &[u8], b: &[u8]) -> usize {
a.iter().zip(b.iter()).take_while(|&(a, b)| a == b).count()
}
fn write_key_value_pair_to_buffer(
&mut self,
shared_prefix_length: usize,
key: &[u8],
value: &[u8],
) -> Result<()> {
let non_shared_key_length = key.len() - shared_prefix_length;
self.buffer.write_varint(shared_prefix_length as u64)?;
self.buffer.write_varint(non_shared_key_length as u64)?;
self.buffer.write_varint(value.len() as u64)?;
self.buffer.extend_from_slice(&key[shared_prefix_length..]);
self.buffer.extend_from_slice(value);
Ok(())
}
pub(crate) fn finish(mut self) -> Result<BlockData> {
for &r in self.restart_points.iter() {
self.buffer.write_fixedint(r).map_err(|e| {
let err = Error::Io(Arc::new(std::io::Error::other(format!(
"Failed to write restart point {}: {}",
r, e
))));
log::error!("[BLOCK] {}", err);
err
})?;
}
self.buffer.write_fixedint(self.restart_points.len() as u32).expect("block write failed");
Ok(self.buffer)
}
pub(crate) fn size_estimate(&self) -> usize {
self.buffer.len() + self.restart_points.len() * 4 + 4
}
pub(crate) fn entries(&self) -> usize {
self.num_entries
}
}
pub(crate) struct BlockIterator {
block: BlockData,
restart_points: Vec<u32>,
offset: usize,
current_key: Vec<u8>,
current_entry_offset: usize,
current_restart_index: usize,
restart_offset: usize,
current_value_offset_start: usize,
current_value_offset_end: usize,
internal_cmp: Arc<dyn Comparator>,
}
impl BlockIterator {
pub(crate) fn new(comparator: Arc<dyn Comparator>, block: BlockData) -> Result<Self> {
if block.len() < 4 {
let err = Error::from(SSTableError::BlockTooSmall {
size: block.len(),
min_size: 4,
});
log::error!("[BLOCK] {}", err);
return Err(err);
}
let num_restarts = u32::decode_fixed(&block[block.len() - 4..]).ok_or_else(|| {
Error::from(SSTableError::FailedToDecodeRestartCount {
block_size: block.len(),
})
})? as usize;
let restart_offset = block.len().checked_sub(4 * (num_restarts + 1)).ok_or_else(|| {
Error::from(SSTableError::InvalidRestartCount {
count: num_restarts,
block_size: block.len(),
})
})?;
let mut restart_points = vec![0; num_restarts];
for (i, restart_point) in restart_points.iter_mut().enumerate().take(num_restarts) {
let start_point = restart_offset + (i * 4);
let end_point = start_point + 4;
if end_point > block.len() {
let err = Error::from(SSTableError::RestartPointExceedsBounds {
index: i,
offset: start_point,
block_size: block.len(),
});
log::error!("[BLOCK] {}", err);
return Err(err);
}
*restart_point =
u32::decode_fixed(&block[start_point..end_point]).ok_or_else(|| {
Error::from(SSTableError::FailedToDecodeRestartPoint {
index: i,
offset: start_point,
})
})?;
}
Ok(BlockIterator {
block,
restart_points,
current_key: Vec::new(),
offset: 0,
current_entry_offset: 0,
current_restart_index: 0,
restart_offset,
current_value_offset_start: 0,
current_value_offset_end: 0,
internal_cmp: comparator,
})
}
fn get_restart_point(&self, index: usize) -> usize {
self.restart_points[index] as usize
}
fn seek_to_restart_point(&mut self, restart_index: usize) {
self.current_restart_index = restart_index;
let offset = self.restart_points[restart_index] as usize;
self.offset = offset;
self.current_entry_offset = offset;
}
fn decode_entry_lengths(&self, offset: usize) -> Result<(usize, usize, usize, usize)> {
let mut i = 0;
let (shared_prefix_length, shared_prefix_length_size) =
usize::decode_var(&self.block[offset..]).ok_or_else(|| {
Error::from(SSTableError::FailedToDecodeSharedPrefix {
offset,
})
})?;
i += shared_prefix_length_size;
let (non_shared_key_length, non_shared_key_length_size) =
usize::decode_var(&self.block[offset + i..]).ok_or_else(|| {
Error::from(SSTableError::FailedToDecodeNonSharedKeyLength {
offset: offset + i,
})
})?;
i += non_shared_key_length_size;
let (value_size, value_size_size) = usize::decode_var(&self.block[offset + i..])
.ok_or_else(|| {
Error::from(SSTableError::FailedToDecodeValueSize {
offset: offset + i,
})
})?;
i += value_size_size;
Ok((shared_prefix_length, non_shared_key_length, value_size, i))
}
fn seek_next_entry(&mut self) -> Result<()> {
if self.offset >= self.restart_offset {
return Err(Error::from(SSTableError::OffsetExceedsRestartOffset {
offset: self.offset,
restart_offset: self.restart_offset,
}));
}
let (shared_prefix, non_shared_key, value_size, i) =
self.decode_entry_lengths(self.offset)?;
let key_end =
self.offset.checked_add(i).and_then(|sum| sum.checked_add(non_shared_key)).ok_or_else(
|| {
Error::from(SSTableError::IntegerOverflowKeyEnd {
offset: self.offset,
})
},
)?;
let value_end = key_end.checked_add(value_size).ok_or_else(|| {
Error::from(SSTableError::IntegerOverflowValueEnd {
offset: self.offset,
})
})?;
if key_end > self.restart_offset || value_end > self.restart_offset {
let err = Error::from(SSTableError::DecodedLengthsExceedBounds {
offset: self.offset,
i,
non_shared_key,
value_size,
key_end,
value_end,
restart_offset: self.restart_offset,
});
log::error!("[BLOCK] {}", err);
return Err(err);
}
self.current_key.truncate(shared_prefix);
self.current_key.extend_from_slice(&self.block[self.offset + i..key_end]);
self.offset = key_end;
self.current_value_offset_start = self.offset;
self.current_value_offset_end = self.offset + value_size;
self.offset = value_end;
Ok(())
}
pub(crate) fn reset(&mut self) {
self.offset = 0;
self.current_restart_index = 0;
self.current_key.clear();
self.current_value_offset_start = 0;
self.current_value_offset_end = 0;
}
}
impl LSMIterator for BlockIterator {
fn seek(&mut self, target: &[u8]) -> Result<bool> {
self.seek_internal(target)?;
Ok(self.is_valid())
}
fn seek_first(&mut self) -> Result<bool> {
self.seek_to_first()?;
Ok(self.is_valid())
}
fn seek_last(&mut self) -> Result<bool> {
self.seek_to_last()?;
Ok(self.is_valid())
}
fn next(&mut self) -> Result<bool> {
if !self.is_valid() {
return Ok(false);
}
self.advance()
}
fn prev(&mut self) -> Result<bool> {
if !self.is_valid() {
return Ok(false);
}
self.prev_internal()
}
fn valid(&self) -> bool {
self.is_valid()
}
fn key(&self) -> InternalKeyRef<'_> {
debug_assert!(self.valid());
InternalKeyRef::from_encoded(&self.current_key)
}
fn value_encoded(&self) -> Result<&[u8]> {
debug_assert!(self.valid());
Ok(&self.block[self.current_value_offset_start..self.current_value_offset_end])
}
}
impl BlockIterator {
pub(crate) fn is_valid(&self) -> bool {
!self.current_key.is_empty()
&& self.current_value_offset_start != 0
&& self.current_value_offset_end != 0
&& self.offset <= self.restart_offset
}
pub(crate) fn seek_to_first(&mut self) -> Result<()> {
if self.restart_points.is_empty() {
let err = Error::from(SSTableError::BlockHasNoRestartPoints);
log::error!("[BLOCK] {}", err);
return Err(err);
}
self.seek_to_restart_point(0);
if self.offset >= self.restart_offset {
self.reset();
return Ok(());
}
self.seek_next_entry()
}
pub(crate) fn seek_to_last(&mut self) -> Result<()> {
if self.restart_points.is_empty() {
self.reset();
let err = Error::from(SSTableError::BlockHasNoRestartPoints);
log::error!("[BLOCK] {}", err);
return Err(err);
}
self.seek_to_restart_point(self.restart_points.len() - 1);
let mut last_entry_start = self.offset;
while self.offset < self.restart_offset {
last_entry_start = self.offset;
self.seek_next_entry()?;
}
self.current_entry_offset = last_entry_start;
Ok(())
}
pub(crate) fn seek_internal(&mut self, target: &[u8]) -> Result<Option<()>> {
self.reset();
if self.restart_points.is_empty() {
let err = Error::from(SSTableError::EmptyCorruptBlockSeek {
block_size: self.block.len(),
restart_offset: self.restart_offset,
});
log::error!("[BLOCK] {}", err);
return Err(err);
}
let mut left = 0;
let mut right = self.restart_points.len() - 1;
while left < right {
let mid = (left + right).div_ceil(2);
self.seek_to_restart_point(mid);
let (shared_prefix, non_shared_key, _, i) = self.decode_entry_lengths(self.offset)?;
let key_start = self.offset + i;
let key_end = key_start + shared_prefix + non_shared_key;
if key_end > self.block.len() {
let err = Error::from(SSTableError::KeyExtendsBeyondBounds {
offset: self.offset,
key_end,
block_len: self.block.len(),
});
log::error!("[BLOCK] {}", err);
return Err(err);
}
let current_key = &self.block[key_start..key_end];
match self.internal_cmp.compare(current_key, target) {
Ordering::Less => left = mid,
_ => right = mid - 1,
}
}
assert_eq!(left, right);
self.seek_to_restart_point(left);
while self.advance()? {
if self.internal_cmp.compare(&self.current_key, target) != Ordering::Less {
break;
}
}
Ok(Some(()))
}
pub(crate) fn advance(&mut self) -> Result<bool> {
if self.offset >= self.restart_offset {
self.reset();
return Ok(false);
}
self.current_entry_offset = self.offset;
match self.seek_next_entry() {
Ok(()) => Ok(true),
Err(e) => {
log::error!("[BLOCK] Failed to advance: {}", e);
Err(e)
}
}
}
pub(crate) fn prev_internal(&mut self) -> Result<bool> {
let original = self.current_entry_offset;
if original == 0 {
self.reset();
return Ok(false);
}
while self.get_restart_point(self.current_restart_index) >= original {
if self.current_restart_index == 0 {
self.offset = self.restart_points[self.current_restart_index] as usize;
self.current_restart_index = self.restart_points.len();
return Ok(false);
}
self.current_restart_index -= 1
}
self.seek_to_restart_point(self.current_restart_index);
let mut prev_offset = self.offset;
loop {
match self.seek_next_entry() {
Ok(()) => {
if self.offset >= original {
self.offset = prev_offset;
self.current_entry_offset = prev_offset;
self.seek_next_entry()?;
return Ok(true);
}
prev_offset = self.offset;
}
Err(e) => {
if let Error::SSTable(SSTableError::OffsetExceedsRestartOffset {
..
}) = e
{
return Ok(false);
}
return Err(e);
}
}
}
}
#[inline]
pub(crate) fn key_bytes(&self) -> &[u8] {
&self.current_key
}
#[inline]
pub(crate) fn value_bytes(&self) -> &[u8] {
&self.block[self.current_value_offset_start..self.current_value_offset_end]
}
#[inline]
pub(crate) fn user_key(&self) -> &[u8] {
InternalKey::user_key_from_encoded(&self.current_key)
}
}