use std::cmp::Ordering;
use crate::options::Options;
use crate::types::LdbIterator;
use bytes::{Bytes, BytesMut};
use integer_encoding::FixedInt;
use integer_encoding::VarInt;
pub type BlockContents = Bytes;
#[derive(Clone)]
pub struct Block {
block: BlockContents,
opt: Options,
}
impl Block {
pub fn iter(&self) -> BlockIter {
let restarts = u32::decode_fixed(&self.block[self.block.len() - 4..]);
let restart_offset = self.block.len() - 4 - 4 * restarts as usize;
BlockIter {
block: self.block.clone(),
opt: self.opt.clone(),
offset: 0,
restarts_off: restart_offset,
current_entry_offset: 0,
current_restart_ix: 0,
key: BytesMut::new(),
val_offset: 0,
}
}
pub fn contents(&self) -> BlockContents {
self.block.clone()
}
pub fn new(opt: Options, contents: BlockContents) -> Block {
assert!(contents.len() > 4);
Block {
block: contents,
opt,
}
}
}
pub struct BlockIter {
block: BlockContents,
opt: Options,
restarts_off: usize,
offset: usize,
current_entry_offset: usize,
current_restart_ix: usize,
key: BytesMut,
val_offset: usize,
}
impl BlockIter {
fn number_restarts(&self) -> usize {
u32::decode_fixed(&self.block[self.block.len() - 4..]) as usize
}
fn seek_to_restart_point(&mut self, ix: usize) -> Option<()> {
let off = self.get_restart_point(ix);
self.offset = off;
self.current_entry_offset = off;
self.current_restart_ix = ix;
let (shared, non_shared, _, head_len) = self.parse_entry_and_advance()?;
assert_eq!(shared, 0);
self.assemble_key(off + head_len, shared, non_shared);
assert!(self.valid());
Some(())
}
fn get_restart_point(&self, ix: usize) -> usize {
let restart = self.restarts_off + 4 * ix;
u32::decode_fixed(&self.block[restart..restart + 4]) as usize
}
fn parse_entry_and_advance(&mut self) -> Option<(usize, usize, usize, usize)> {
let mut i = 0;
let (shared, sharedlen) = usize::decode_var(&self.block[self.offset..])?;
i += sharedlen;
let (non_shared, non_sharedlen) = usize::decode_var(&self.block[self.offset + i..])?;
i += non_sharedlen;
let (valsize, valsizelen) = usize::decode_var(&self.block[self.offset + i..])?;
i += valsizelen;
self.val_offset = self.offset + i + non_shared;
self.offset = self.val_offset + valsize;
Some((shared, non_shared, valsize, i))
}
fn assemble_key(&mut self, off: usize, shared: usize, non_shared: usize) {
self.key.truncate(shared);
if non_shared > 0 {
let block_slice_ref: &[u8] = self.block.as_ref();
self.key
.extend_from_slice(&block_slice_ref[off..off + non_shared]);
}
}
pub fn seek_to_last(&mut self) -> Option<()> {
if self.number_restarts() > 0 {
let num_restarts = self.number_restarts();
self.seek_to_restart_point(num_restarts - 1)?;
} else {
self.reset();
}
while self.offset < self.restarts_off {
self.advance();
}
assert!(self.valid());
Some(())
}
}
impl LdbIterator for BlockIter {
fn advance(&mut self) -> bool {
if self.offset >= self.restarts_off {
self.reset();
return false;
} else {
self.current_entry_offset = self.offset;
}
let current_off = self.current_entry_offset;
if let Some((shared, non_shared, _valsize, entry_head_len)) = self.parse_entry_and_advance()
{
self.assemble_key(current_off + entry_head_len, shared, non_shared);
let num_restarts = self.number_restarts();
while self.current_restart_ix + 1 < num_restarts
&& self.get_restart_point(self.current_restart_ix + 1) < self.current_entry_offset
{
self.current_restart_ix += 1;
}
true
} else {
#[cfg(debug_assertions)]
panic!("[debug mode panic] parse_entry_and_advance(): couldn't parse entry head at/after {:?}", self.key);
#[allow(unreachable_code)]
false
}
}
fn reset(&mut self) {
self.offset = 0;
self.val_offset = 0;
self.current_restart_ix = 0;
self.key.clear();
}
fn prev(&mut self) -> bool {
let orig_offset = self.current_entry_offset;
if orig_offset == 0 {
self.reset();
return false;
}
while self.get_restart_point(self.current_restart_ix) >= orig_offset {
if self.current_restart_ix == 0 {
self.offset = self.restarts_off;
self.current_restart_ix = self.number_restarts();
break;
}
self.current_restart_ix -= 1;
}
self.offset = self.get_restart_point(self.current_restart_ix);
assert!(self.offset < orig_offset);
let mut result;
loop {
result = self.advance();
if self.offset >= orig_offset {
break;
}
}
result
}
fn seek(&mut self, to: &[u8]) {
self.reset();
let mut left = 0;
let mut right = if self.number_restarts() == 0 {
0
} else {
self.number_restarts() - 1
};
while left < right {
let middle = (left + right).div_ceil(2);
self.seek_to_restart_point(middle);
let c = self.opt.cmp.cmp(&self.key, to);
if c == Ordering::Less {
left = middle;
} else {
right = middle - 1;
}
}
assert_eq!(left, right);
self.current_restart_ix = left;
self.offset = self.get_restart_point(left);
while let Some((k, _)) = self.next() {
if self.opt.cmp.cmp(k.as_slice(), to) >= Ordering::Equal {
return;
}
}
}
fn valid(&self) -> bool {
!self.key.is_empty() && self.val_offset > 0 && self.val_offset <= self.restarts_off
}
fn current(&self) -> Option<(Bytes, Bytes)> {
if self.valid() {
Some((
self.key.clone().freeze(),
self.block.slice(self.val_offset..self.offset),
))
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::block_builder::BlockBuilder;
use crate::options;
use crate::test_util::{test_iterator_properties, LdbIteratorIter};
use crate::types::{current_key_val, LdbIterator};
fn get_data() -> Vec<(&'static [u8], &'static [u8])> {
vec![
(b"key1", b"value1"),
(b"loooooooooooooooooooooooooooooooooongerkey1", b"shrtvl1"),
("medium length key 1".as_bytes(), "some value 2".as_bytes()),
(b"prefix_key1", b"value"),
(b"prefix_key2", b"value"),
(b"prefix_key3", b"value"),
]
}
#[test]
fn test_block_iterator_properties() {
let o = options::for_test();
let mut builder = BlockBuilder::new(o.clone());
let mut data = get_data();
data.truncate(4);
for &(k, v) in data.iter() {
builder.add(k, v);
}
let block_contents = builder.finish();
let block = Block::new(o.clone(), block_contents).iter();
test_iterator_properties(block);
}
#[test]
fn test_block_empty() {
let mut o = options::for_test();
o.block_restart_interval = 16;
let builder = BlockBuilder::new(o);
let blockc = builder.finish();
assert_eq!(blockc.len(), 8);
assert_eq!(blockc, vec![0, 0, 0, 0, 1, 0, 0, 0]);
let block = Block::new(options::for_test(), blockc);
LdbIteratorIter::wrap(&mut block.iter()).for_each(|_| {
panic!("expected 0 iterations");
});
}
#[test]
fn test_block_build_iterate() {
let data = get_data();
let mut builder = BlockBuilder::new(options::for_test());
for &(k, v) in data.iter() {
builder.add(k, v);
}
let block_contents = builder.finish();
let mut block = Block::new(options::for_test(), block_contents).iter();
let mut i = 0;
assert!(!block.valid());
for (k, v) in LdbIteratorIter::wrap(&mut block) {
assert_eq!(&k[..], data[i].0);
assert_eq!(v, data[i].1);
i += 1;
}
assert_eq!(i, data.len());
}
#[test]
fn test_block_iterate_reverse() {
let mut o = options::for_test();
o.block_restart_interval = 3;
let data = get_data();
let mut builder = BlockBuilder::new(o.clone());
for &(k, v) in data.iter() {
builder.add(k, v);
}
let block_contents = builder.finish();
let mut block = Block::new(o.clone(), block_contents).iter();
assert!(!block.valid());
assert_eq!(block.next(), Some((b"key1".to_vec(), b"value1".to_vec())));
assert!(block.valid());
block.next();
assert!(block.valid());
block.prev();
assert!(block.valid());
assert_eq!(
current_key_val(&block),
Some((b"key1".to_vec(), b"value1".to_vec()))
);
block.prev();
assert!(!block.valid());
while block.next().is_some() {}
block.prev();
assert!(block.valid());
assert_eq!(
current_key_val(&block),
Some((b"prefix_key2".to_vec(), b"value".to_vec()))
);
}
#[test]
fn test_block_seek() {
let mut o = options::for_test();
o.block_restart_interval = 3;
let data = get_data();
let mut builder = BlockBuilder::new(o.clone());
for &(k, v) in data.iter() {
builder.add(k, v);
}
let block_contents = builder.finish();
let mut block = Block::new(o.clone(), block_contents).iter();
block.seek(b"prefix_key2");
assert!(block.valid());
assert_eq!(
current_key_val(&block),
Some((b"prefix_key2".to_vec(), b"value".to_vec()))
);
block.seek(b"prefix_key0");
assert!(block.valid());
assert_eq!(
current_key_val(&block),
Some((b"prefix_key1".to_vec(), b"value".to_vec()))
);
block.seek(b"key1");
assert!(block.valid());
assert_eq!(
current_key_val(&block),
Some((b"key1".to_vec(), b"value1".to_vec()))
);
block.seek(b"prefix_key3");
assert!(block.valid());
assert_eq!(
current_key_val(&block),
Some((b"prefix_key3".to_vec(), b"value".to_vec()))
);
block.seek(b"prefix_key8");
assert!(!block.valid());
assert_eq!(current_key_val(&block), None);
}
#[test]
fn test_block_seek_to_last() {
let mut o = options::for_test();
for block_restart_interval in [2, 6, 10] {
o.block_restart_interval = block_restart_interval;
let data = get_data();
let mut builder = BlockBuilder::new(o.clone());
for &(k, v) in data.iter() {
builder.add(k, v);
}
let block_contents = builder.finish();
let mut block = Block::new(o.clone(), block_contents).iter();
block.seek_to_last();
assert!(block.valid());
assert_eq!(
current_key_val(&block),
Some((b"prefix_key3".to_vec(), b"value".to_vec()))
);
}
}
}