use std::ops::Bound;
use std::sync::Arc;
use std::vec;
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use test_log::test;
use crate::sstable::block::BlockHandle;
use crate::sstable::table::{ChecksumType, Footer, IndexType, Table, TableFormat, TableWriter};
use crate::test::{collect_all, collect_iter, count_iter};
use crate::vfs::File;
use crate::{
user_range_to_internal_range,
InternalKey,
InternalKeyKind,
LSMIterator,
Options,
Result,
INTERNAL_KEY_SEQ_NUM_MAX,
};
fn default_opts() -> Arc<Options> {
let mut opts = Options::new();
opts.block_restart_interval = 3;
opts.index_partition_size = 100; Arc::new(opts)
}
fn default_opts_mut() -> Options {
let mut opts = Options::new();
opts.block_restart_interval = 3;
opts.index_partition_size = 100; opts
}
#[test]
fn test_footer() {
let f = Footer::new(BlockHandle::new(44, 4), BlockHandle::new(55, 5));
let mut buf = [0; 50]; f.encode(&mut buf[..]);
let f2 = Footer::decode(&buf).unwrap();
assert_eq!(f2.meta_index.offset(), 44);
assert_eq!(f2.meta_index.size(), 4);
assert_eq!(f2.index.offset(), 55);
assert_eq!(f2.index.size(), 5);
assert_eq!(f2.format, TableFormat::LSMV1);
assert_eq!(f2.checksum, ChecksumType::CRC32c);
}
#[test]
fn test_table_builder() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut b = TableWriter::new(d, 0, opts, 0);
let data = [("abc", "def"), ("abe", "dee"), ("bcd", "asa"), ("dcc", "a00")];
let data2 = [("abd", "def"), ("abf", "dee"), ("ccd", "asa"), ("dcd", "a00")];
for i in 0..data.len() {
b.add(
InternalKey::new(Vec::from(data[i].0.as_bytes()), 1, InternalKeyKind::Set, 0),
data[i].1.as_bytes(),
)
.unwrap();
b.add(
InternalKey::new(Vec::from(data2[i].0.as_bytes()), 1, InternalKeyKind::Set, 0),
data2[i].1.as_bytes(),
)
.unwrap();
}
let actual = b.finish().unwrap();
assert_eq!(724, actual);
}
#[test]
#[should_panic]
fn test_bad_input() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut b = TableWriter::new(d, 0, opts, 0);
let data = [("abc", "def"), ("abc", "dee"), ("bcd", "asa"), ("bsr", "a00")];
for &(k, v) in data.iter() {
b.add(InternalKey::new(Vec::from(k.as_bytes()), 1, InternalKeyKind::Set, 0), v.as_bytes())
.unwrap();
}
b.finish().unwrap();
}
fn build_data() -> Vec<(&'static str, &'static str)> {
vec![
("abc", "def"),
("abd", "dee"),
("bcd", "asa"),
("bsr", "a00"),
("xyz", "xxx"),
("xzz", "yyy"),
("zzz", "111"),
]
}
fn build_table(data: Vec<(&str, &str)>) -> (Vec<u8>, usize) {
let mut d = Vec::with_capacity(512);
let mut opts = default_opts_mut();
opts.block_restart_interval = 3;
opts.block_size = 32;
let opt = Arc::new(opts);
{
let mut b = TableWriter::new(&mut d, 0, opt, 0);
for &(k, v) in data.iter() {
b.add(
InternalKey::new(Vec::from(k.as_bytes()), 1, InternalKeyKind::Set, 0),
v.as_bytes(),
)
.unwrap();
}
b.finish().unwrap();
}
let size = d.len();
(d, size)
}
fn build_table_with_seq_num(data: Vec<(&str, &str, u64)>) -> (Vec<u8>, usize) {
let mut d = Vec::with_capacity(512);
let mut opts = default_opts_mut();
opts.block_restart_interval = 3;
opts.block_size = 32;
let opt = Arc::new(opts);
{
let mut b = TableWriter::new(&mut d, 0, opt, 0);
for &(k, v, seq) in data.iter() {
b.add(
InternalKey::new(Vec::from(k.as_bytes()), seq, InternalKeyKind::Set, 0),
v.as_bytes(),
)
.unwrap();
}
b.finish().unwrap();
}
let size = d.len();
(d, size)
}
fn wrap_buffer(src: Vec<u8>) -> Arc<dyn File> {
Arc::new(src)
}
#[test]
fn test_table_seek() {
let (src, size) = build_table(build_data());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let key = InternalKey::new(Vec::from(b"bcd"), 2, InternalKeyKind::Set, 0);
iter.seek(&key.encode()).unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"bcd"[..], &b"asa"[..]));
let key = InternalKey::new(Vec::from(b"abc"), 2, InternalKeyKind::Set, 0);
iter.seek(&key.encode()).unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"abc"[..], &b"def"[..]));
let key = InternalKey::new(Vec::from(b"{{{"), 2, InternalKeyKind::Set, 0);
iter.seek(&key.encode()).unwrap();
assert!(!iter.valid());
let key = InternalKey::new(Vec::from(b"bbb"), 2, InternalKeyKind::Set, 0);
iter.seek(&key.encode()).unwrap();
assert!(iter.valid());
}
#[test]
fn test_table_iter() {
let (src, size) = build_table(build_data());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.next().unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"abc"[..], &b"def"[..]));
iter.next().unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"abd"[..], &b"dee"[..]));
iter.next().unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"bcd"[..], &b"asa"[..]));
iter.next().unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"bsr"[..], &b"a00"[..]));
iter.next().unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"xyz"[..], &b"xxx"[..]));
iter.next().unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"xzz"[..], &b"yyy"[..]));
iter.next().unwrap();
assert!(iter.valid());
assert_eq!((iter.key().user_key(), iter.value_encoded().unwrap()), (&b"zzz"[..], &b"111"[..]));
}
#[test]
fn test_many_items() {
let opts = Options::new();
let opts = Arc::new(opts);
let mut buffer = Vec::with_capacity(10240);
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let num_items = 10001;
let mut items = Vec::with_capacity(num_items as usize);
for i in 0..num_items {
let key = format!("key_{i:05}");
let value = format!("value_{i:05}");
items.push((key.clone(), value.clone()));
let internal_key = InternalKey::new(
Vec::from(key.as_bytes()),
i + 2, InternalKeyKind::Set,
0,
);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
assert!(size > 0, "Table should have non-zero size");
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(
table.meta.properties.num_entries, num_items,
"Table should contain num_items entries"
);
for (key, value) in &items {
let internal_key =
InternalKey::new(Vec::from(key.as_bytes()), num_items + 1, InternalKeyKind::Set, 0);
let result = table.get(&internal_key).unwrap();
assert!(result.is_some(), "Key '{key}' not found in table");
if let Some((found_key, found_value)) = result {
assert_eq!(
std::str::from_utf8(&found_key.user_key).unwrap(),
key,
"Key mismatch for '{key}'"
);
assert_eq!(
std::str::from_utf8(found_value.as_ref()).unwrap(),
value,
"Value mismatch for key '{key}'"
);
}
}
}
#[test]
fn test_iter_items() {
let opts = Options::new();
let opts = Arc::new(opts);
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let num_items = 10001;
let mut items = Vec::with_capacity(num_items as usize);
for i in 0..num_items {
let key = format!("key_{i:05}");
let value = format!("value_{i:05}");
items.push((key.clone(), value.clone()));
let internal_key =
InternalKey::new(Vec::from(key.as_bytes()), i + 1, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
assert!(size > 0, "Table should have non-zero size");
let table = Arc::new(Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap());
assert_eq!(
table.meta.properties.num_entries, num_items,
"Table should contain num_items entries"
);
let mut iter = table.iter(None).unwrap();
iter.seek_to_first().unwrap();
let mut item = 0;
while iter.valid() {
let key = iter.key().to_owned();
let value = iter.value_encoded().unwrap();
let expected_key = format!("key_{item:05}");
let expected_value = format!("value_{item:05}");
assert_eq!(std::str::from_utf8(&key.user_key).unwrap(), expected_key);
assert_eq!(value, expected_value.as_bytes());
iter.next().unwrap();
item += 1;
}
}
fn add_key(writer: &mut TableWriter<Vec<u8>>, key: &[u8], seq: u64, value: &[u8]) -> Result<()> {
writer.add(InternalKey::new(Vec::from(key), seq, InternalKeyKind::Set, 0), value)
}
#[test]
fn test_writer_key_range_empty() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let writer = TableWriter::new(d, 1, opts, 0);
assert!(writer.meta.smallest_point.is_none());
assert!(writer.meta.largest_point.is_none());
}
#[test]
fn test_writer_key_range_single_entry() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
add_key(&mut writer, b"singleton", 1, b"value").unwrap();
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"singleton");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], b"singleton");
}
}
#[test]
fn test_writer_key_range_ascending_keys() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let keys = ["aaa", "bbb", "ccc", "ddd", "eee"];
for (i, key) in keys.iter().enumerate() {
add_key(&mut writer, key.as_bytes(), i as u64 + 1, b"value").unwrap();
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"aaa");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], key.as_bytes());
}
}
}
#[test]
fn test_writer_key_range_interleaved_pattern() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let keys = ["a10", "a20", "a15", "a30", "a25"];
let mut sorted_keys = keys;
sorted_keys.sort();
for (i, key) in sorted_keys.iter().enumerate() {
add_key(&mut writer, key.as_bytes(), i as u64 + 1, b"value").unwrap();
}
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"a10");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], b"a30");
}
}
#[test]
fn test_writer_key_range_sparse_pattern() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let keys = ["aaaaa", "nnnnn", "zzzzz"];
for (i, key) in keys.iter().enumerate() {
add_key(&mut writer, key.as_bytes(), i as u64 + 1, b"value").unwrap();
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"aaaaa");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], key.as_bytes());
}
}
}
#[test]
fn test_writer_key_range_clustered_pattern() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let prefixes = ["aaa", "aab", "aac"];
for (i, prefix) in prefixes.iter().enumerate() {
for j in 1..=5 {
let key = format!("{prefix}{j}");
add_key(&mut writer, key.as_bytes(), (i * 5 + j) as u64, b"value").unwrap();
}
}
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"aaa1");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], b"aac5");
}
}
#[test]
fn test_writer_key_range_binary_keys() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let keys = [vec![0x00, 0x01, 0x02], vec![0x10, 0x11, 0x12], vec![0xF0, 0xF1, 0xF2]];
for (i, key) in keys.iter().enumerate() {
add_key(&mut writer, key, i as u64 + 1, b"value").unwrap();
}
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], &[0x00, 0x01, 0x02]);
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], &[0xF0, 0xF1, 0xF2]);
}
}
#[test]
fn test_writer_key_range_identical_keys_different_seqnums() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
add_key(&mut writer, b"same_key", 30, b"value3").unwrap();
add_key(&mut writer, b"same_key", 20, b"value2").unwrap();
add_key(&mut writer, b"same_key", 10, b"value1").unwrap();
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"same_key");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], b"same_key");
}
}
#[test]
fn test_writer_key_range_unicode_keys() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let keys = ["α", "β", "γ", "δ", "ε"];
for (i, key) in keys.iter().enumerate() {
add_key(&mut writer, key.as_bytes(), i as u64 + 1, b"value").unwrap();
}
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], "α".as_bytes());
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], "ε".as_bytes());
}
}
#[test]
fn test_writer_key_range_with_special_chars() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let keys = [
"\0key", "key\n", "key\tvalue", "key\\value", "\"quoted\"", ];
let mut sorted_keys = keys.to_vec();
sorted_keys.sort();
for (i, key) in sorted_keys.iter().enumerate() {
add_key(&mut writer, key.as_bytes(), i as u64 + 1, b"value").unwrap();
}
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], sorted_keys.first().unwrap().as_bytes());
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], sorted_keys.last().unwrap().as_bytes());
}
}
#[test]
fn test_writer_key_range_with_mixed_case() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let keys = ["AAA", "BBB", "aaa", "bbb"];
let mut sorted_keys = keys.to_vec();
sorted_keys.sort();
for (i, key) in sorted_keys.iter().enumerate() {
add_key(&mut writer, key.as_bytes(), i as u64 + 1, b"value").unwrap();
}
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"AAA");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], b"bbb");
}
}
#[test]
fn test_writer_key_range_with_pseudo_random_keys() {
let d = Vec::with_capacity(2048);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let mut rng = StdRng::seed_from_u64(100);
let mut keys = Vec::new();
for _ in 0..100 {
let len = rng.random_range(3..10);
let mut key = Vec::with_capacity(len);
for _ in 0..len {
key.push(rng.random_range(b'a'..=b'z'));
}
keys.push(key);
}
keys.sort();
for (i, key) in keys.iter().enumerate() {
add_key(&mut writer, key, i as u64 + 1, b"value").unwrap();
}
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], &keys.first().unwrap()[..]);
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], &keys.last().unwrap()[..]);
}
}
#[test]
fn test_writer_key_range_with_prefix_pattern() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
add_key(&mut writer, b"prefix:aaa", 1, b"value").unwrap();
add_key(&mut writer, b"prefix:bbb", 2, b"value").unwrap();
add_key(&mut writer, b"prefix:ccc", 3, b"value").unwrap();
add_key(&mut writer, b"zzzzzz", 4, b"value").unwrap();
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"prefix:aaa");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], b"zzzzzz");
}
}
#[test]
fn test_writer_key_range_boundary_keys() {
let d = Vec::with_capacity(512);
let opts = default_opts();
let mut writer = TableWriter::new(d, 1, opts, 0);
let long = "z".repeat(1000);
let long = &long.as_str();
let keys = [
"", "a", long, ];
for (i, key) in keys.iter().enumerate() {
add_key(&mut writer, key.as_bytes(), i as u64 + 1, b"value").unwrap();
}
assert!(writer.meta.smallest_point.is_some());
assert!(writer.meta.largest_point.is_some());
if let Some(smallest) = &writer.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"");
}
if let Some(largest) = &writer.meta.largest_point {
assert_eq!(&largest.user_key[..], "z".repeat(1000).as_bytes());
}
}
#[test]
fn test_table_key_range_persistence() {
let data = build_data();
let (src, size) = build_table(data.clone());
let opts = default_opts();
let expected_low = data.first().unwrap().0.as_bytes();
let expected_high = data.last().unwrap().0.as_bytes();
let table = Table::new(1, opts, wrap_buffer(src), size as u64).unwrap();
assert!(table.meta.smallest_point.is_some());
assert!(table.meta.largest_point.is_some());
if let Some(smallest) = &table.meta.smallest_point {
assert_eq!(&smallest.user_key[..], expected_low);
}
if let Some(largest) = &table.meta.largest_point {
assert_eq!(&largest.user_key[..], expected_high);
}
assert!(table.is_key_in_key_range(&InternalKey::new(
Vec::from(expected_low),
1,
InternalKeyKind::Set,
0
)));
assert!(table.is_key_in_key_range(&InternalKey::new(
Vec::from(expected_high),
1,
InternalKeyKind::Set,
0
)));
let before_range = "aaa".as_bytes();
assert!(!table.is_key_in_key_range(&InternalKey::new(
Vec::from(before_range),
1,
InternalKeyKind::Set,
0
)));
let after_range = "zzzz".as_bytes();
assert!(!table.is_key_in_key_range(&InternalKey::new(
Vec::from(after_range),
1,
InternalKeyKind::Set,
0
)));
let middle_key = "bsr".as_bytes(); assert!(table.is_key_in_key_range(&InternalKey::new(
Vec::from(middle_key),
1,
InternalKeyKind::Set,
0
)));
}
#[test]
fn test_table_disjoint_key_range_persistence() {
let disjoint_data = vec![
("aaa", "val1"),
("bbb", "val2"),
("ppp", "val3"), ("qqq", "val4"),
("zzz", "val5"), ];
let (src, size) = build_table(disjoint_data.clone());
let opts = default_opts();
let expected_low = disjoint_data.first().unwrap().0.as_bytes();
let expected_high = disjoint_data.last().unwrap().0.as_bytes();
let table = Table::new(1, opts, wrap_buffer(src), size as u64).unwrap();
assert!(table.meta.smallest_point.is_some());
assert!(table.meta.largest_point.is_some());
if let Some(smallest) = &table.meta.smallest_point {
assert_eq!(&smallest.user_key[..], expected_low);
}
if let Some(largest) = &table.meta.largest_point {
assert_eq!(&largest.user_key[..], expected_high);
}
let in_first_gap = "ccc".as_bytes(); assert!(table.is_key_in_key_range(&InternalKey::new(
Vec::from(in_first_gap),
1,
InternalKeyKind::Set,
0
)));
let in_second_gap = "xxx".as_bytes(); assert!(table.is_key_in_key_range(&InternalKey::new(
Vec::from(in_second_gap),
1,
InternalKeyKind::Set,
0
)));
}
#[test]
fn test_table_key_range_with_many_blocks() {
let mut data: Vec<(String, String)> = Vec::new();
for i in 0..50 {
let key = format!("key_{i:03}");
let value = format!("value_{i}");
data.push((key, value));
}
let data: Vec<(&str, &str)> = data.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
let (src, size) = build_table(data);
let opts = default_opts();
let expected_low = "key_000".as_bytes();
let expected_high = "key_049".as_bytes();
let table = Table::new(1, opts, wrap_buffer(src), size as u64).unwrap();
assert!(table.meta.smallest_point.is_some());
assert!(table.meta.largest_point.is_some());
if let Some(smallest) = &table.meta.smallest_point {
assert_eq!(&smallest.user_key[..], expected_low);
}
if let Some(largest) = &table.meta.largest_point {
assert_eq!(&largest.user_key[..], expected_high);
}
assert!(table.meta.properties.num_data_blocks > 1);
for idx in [0, 10, 25, 49] {
let key = format!("key_{idx:03}");
assert!(table.is_key_in_key_range(&InternalKey::new(
Vec::from(key.as_bytes()),
1,
InternalKeyKind::Set,
0
)));
}
}
#[test]
fn test_table_key_range_with_tombstones() {
let data = vec![
("aaa", "val1"),
("bbb", "val2"),
("ccc", ""), ("ddd", "val4"),
("eee", ""), ];
let (src, size) = build_table_with_tombstones(data.clone());
let opts = default_opts();
let table = Table::new(1, opts, wrap_buffer(src), size as u64).unwrap();
assert!(table.meta.smallest_point.is_some());
assert!(table.meta.largest_point.is_some());
if let Some(smallest) = &table.meta.smallest_point {
assert_eq!(&smallest.user_key[..], b"aaa");
}
if let Some(largest) = &table.meta.largest_point {
assert_eq!(&largest.user_key[..], b"eee");
}
assert_eq!(table.meta.properties.tombstone_count, 2);
}
fn build_table_with_tombstones(data: Vec<(&'static str, &'static str)>) -> (Vec<u8>, usize) {
let mut d = Vec::with_capacity(512);
let mut opts = default_opts_mut();
opts.block_restart_interval = 3;
opts.block_size = 32;
let opt = Arc::new(opts);
{
let mut b = TableWriter::new(&mut d, 0, opt, 0);
for &(k, v) in data.iter() {
let kind = if v.is_empty() {
InternalKeyKind::Delete
} else {
InternalKeyKind::Set
};
b.add(InternalKey::new(Vec::from(k.as_bytes()), 1, kind, 0), v.as_bytes()).unwrap();
}
b.finish().unwrap();
}
let size = d.len();
(d, size)
}
#[test]
fn test_table_iterator_no_items_lost() {
let data = vec![
("key_000", "value_000"),
("key_001", "value_001"),
("key_002", "value_002"),
("key_003", "value_003"),
("key_004", "value_004"),
];
let (src, size) = build_table(data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.seek_to_first().unwrap();
let mut collected_items = Vec::new();
while iter.valid() {
let key = iter.key().to_owned();
let value = iter.value_encoded().unwrap();
let key_str = std::str::from_utf8(&key.user_key).unwrap();
let value_str = std::str::from_utf8(value).unwrap();
collected_items.push((key_str.to_string(), value_str.to_string()));
iter.next().unwrap();
}
assert_eq!(
collected_items.len(),
data.len(),
"Iterator should return exactly {} items, got {}",
data.len(),
collected_items.len()
);
for (i, (expected_key, expected_value)) in data.iter().enumerate() {
assert!(
i < collected_items.len(),
"Missing item at index {i}: expected ({expected_key}, {expected_value})"
);
let (actual_key, actual_value) = &collected_items[i];
assert_eq!(
actual_key, expected_key,
"Key mismatch at index {i}: expected '{expected_key}', got '{actual_key}'"
);
assert_eq!(
actual_value, expected_value,
"Value mismatch at index {i}: expected '{expected_value}', got '{actual_value}'"
);
}
assert_eq!(collected_items[0].0, data[0].0, "First item key was lost!");
assert_eq!(collected_items[0].1, data[0].1, "First item value was lost!");
}
#[test]
fn test_table_iterator_does_not_restart_after_exhaustion() {
let data = vec![("a", "val_a"), ("b", "val_b"), ("c", "val_c")];
let (src, size) = build_table(data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.seek_to_first().unwrap();
let mut seen_keys = Vec::new();
let mut iteration_count = 0;
loop {
iteration_count += 1;
if iteration_count > 10 {
panic!(
"Iterator appears to be stuck in a loop! This suggests the iterator is restarting instead of staying exhausted."
);
}
if !iter.valid() {
break;
}
let key = iter.key().to_owned();
let value = iter.value_encoded().unwrap();
let key_str = std::str::from_utf8(&key.user_key).unwrap();
let value_str = std::str::from_utf8(value).unwrap();
seen_keys.push((key_str.to_string(), value_str.to_string()));
let key_count = seen_keys.iter().filter(|(k, _)| k == key_str).count();
if key_count > 1 {
panic!("Iterator restarted! Saw key '{key_str}' {key_count} times");
}
iter.next().unwrap();
}
assert_eq!(
seen_keys.len(),
data.len(),
"Expected {} items, got {}",
data.len(),
seen_keys.len()
);
for i in 0..3 {
let result = iter.next().unwrap();
if result {
panic!(
"Iterator should remain exhausted, but returned true on additional call #{}",
i + 1
);
}
}
}
#[test]
fn test_table_iterator_advance_method_correctness() {
let data = vec![("item1", "data1"), ("item2", "data2"), ("item3", "data3")];
let (src, size) = build_table(data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
for expected_index in 0..data.len() {
let advance_result = iter.next().unwrap();
assert!(
advance_result,
"next() should return true when moving to item {} (of {})",
expected_index,
data.len()
);
assert!(iter.valid(), "Iterator should be valid after advancing to item {expected_index}");
let current_key = iter.key();
let key_str = std::str::from_utf8(current_key.user_key()).unwrap();
let expected_key = data[expected_index].0;
assert_eq!(
key_str, expected_key,
"After advancing to position {expected_index}, expected key '{expected_key}', got '{key_str}'"
);
}
let final_advance = iter.next().unwrap();
assert!(!final_advance, "next() should return false when trying to advance past the last item");
assert!(!iter.valid(), "Iterator should be invalid after advancing past the last item");
for i in 0..3 {
let advance_result = iter.next().unwrap();
assert!(
!advance_result,
"next() should continue returning false after exhaustion (call #{})",
i + 1
);
assert!(!iter.valid(), "Iterator should remain invalid after additional next() calls");
}
}
#[test]
fn test_table_iterator_edge_cases() {
{
let single_data = vec![("only_key", "only_value")];
let (src, size) = build_table(single_data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let collected = collect_all(&mut iter).unwrap();
assert_eq!(collected.len(), 1, "Single item table should return exactly 1 item");
let key_str = std::str::from_utf8(&collected[0].0.user_key).unwrap();
let value_str = std::str::from_utf8(collected[0].1.as_ref()).unwrap();
assert_eq!(key_str, "only_key");
assert_eq!(value_str, "only_value");
}
{
let two_data = vec![("first", "1st"), ("second", "2nd")];
let (src, size) = build_table(two_data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let collected = collect_all(&mut iter).unwrap();
assert_eq!(collected.len(), 2, "Two item table should return exactly 2 items");
let keys: Vec<String> = collected
.iter()
.map(|(k, _)| std::str::from_utf8(&k.user_key).unwrap().to_string())
.collect();
assert_eq!(keys, vec!["first", "second"], "Items should be in correct order");
}
{
let large_data: Vec<_> =
(0..100).map(|i| (format!("key_{i:03}"), format!("value_{i:03}"))).collect();
let large_data_refs: Vec<(&str, &str)> =
large_data.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
let (src, size) = build_table(large_data_refs);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let collected = collect_all(&mut iter).unwrap();
assert_eq!(collected.len(), 100, "Large table should return exactly 100 items");
let mut seen_keys = std::collections::HashSet::new();
for (key, _) in &collected {
let key_str = std::str::from_utf8(&key.user_key).unwrap();
assert!(
seen_keys.insert(key_str),
"Duplicate key found: '{key_str}' - iterator may have restarted"
);
}
let first_key = std::str::from_utf8(&collected[0].0.user_key).unwrap();
let last_key = std::str::from_utf8(&collected[99].0.user_key).unwrap();
assert_eq!(first_key, "key_000", "First key should be key_000");
assert_eq!(last_key, "key_099", "Last key should be key_099");
}
}
#[test]
fn test_table_iterator_seek_then_iterate() {
let data = vec![
("item_01", "val_01"),
("item_02", "val_02"),
("item_03", "val_03"),
("item_04", "val_04"),
("item_05", "val_05"),
];
let (src, size) = build_table(data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let test_cases = vec![("item_01", 0), ("item_03", 2), ("item_05", 4)];
for (seek_key, expected_start_index) in test_cases {
let mut iter = table.iter(None).unwrap();
let internal_key =
InternalKey::new(Vec::from(seek_key.as_bytes()), 1, InternalKeyKind::Set, 0);
iter.seek(&internal_key.encode()).unwrap();
assert!(iter.valid(), "Iterator should be valid after seeking to '{seek_key}'");
let mut remaining_items = Vec::new();
while iter.valid() {
let current_key = iter.key();
let current_value = iter.value_encoded().unwrap();
let key_str = std::str::from_utf8(current_key.user_key()).unwrap();
let value_str = std::str::from_utf8(current_value).unwrap();
remaining_items.push((key_str.to_string(), value_str.to_string()));
if !iter.next().unwrap() {
break;
}
}
let expected_remaining = &data[expected_start_index..];
assert_eq!(
remaining_items.len(),
expected_remaining.len(),
"After seeking to '{}', expected {} remaining items, got {}",
seek_key,
expected_remaining.len(),
remaining_items.len()
);
for (i, (expected_key, expected_value)) in expected_remaining.iter().enumerate() {
assert_eq!(
remaining_items[i].0, *expected_key,
"After seeking to '{}', item {} key mismatch: expected '{}', got '{}'",
seek_key, i, expected_key, remaining_items[i].0
);
assert_eq!(
remaining_items[i].1, *expected_value,
"After seeking to '{}', item {} value mismatch: expected '{}', got '{}'",
seek_key, i, expected_value, remaining_items[i].1
);
}
}
}
#[test]
fn test_table_iterator_seek_behavior() {
let data = vec![
("key_001", "val_001"),
("key_002", "val_002"),
("key_005", "val_005"),
("key_007", "val_007"),
("key_010", "val_010"),
];
let (src, size) = build_table(data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
{
let mut iter = table.iter(None).unwrap();
let seek_key = InternalKey::new(Vec::from(b"key_005"), 1, InternalKeyKind::Set, 0);
iter.seek(&seek_key.encode()).unwrap();
assert!(iter.valid(), "Iterator should be valid after seeking to existing key");
let current_key = iter.key();
let found_key = std::str::from_utf8(current_key.user_key()).unwrap();
assert_eq!(found_key, "key_005", "Should find the exact key we sought");
let remaining_collected = collect_iter(&mut iter);
let remaining: Vec<_> = remaining_collected
.iter()
.map(|(k, v)| {
(
std::str::from_utf8(&k.user_key).unwrap().to_string(),
std::str::from_utf8(v.as_ref()).unwrap().to_string(),
)
})
.collect();
let expected = [
("key_005".to_string(), "val_005".to_string()),
("key_007".to_string(), "val_007".to_string()),
("key_010".to_string(), "val_010".to_string()),
];
assert_eq!(remaining.len(), expected.len(), "Should get remaining items after seek");
for (i, (actual, expected)) in remaining.iter().zip(expected.iter()).enumerate() {
assert_eq!(actual, expected, "Mismatch at position {i} after seek");
}
}
{
let mut iter = table.iter(None).unwrap();
let seek_key = InternalKey::new(Vec::from(b"key_003"), 1, InternalKeyKind::Set, 0);
iter.seek(&seek_key.encode()).unwrap();
assert!(iter.valid(), "Iterator should be valid after seeking to non-existing key");
let current_key = iter.key();
let found_key = std::str::from_utf8(current_key.user_key()).unwrap();
assert_eq!(found_key, "key_005", "Should find next key when seeking non-existing");
}
{
let mut iter = table.iter(None).unwrap();
let seek_key = InternalKey::new(Vec::from(b"key_999"), 1, InternalKeyKind::Set, 0);
iter.seek(&seek_key.encode()).unwrap();
assert!(!iter.valid(), "Iterator should be invalid after seeking past end");
}
}
#[test]
fn test_table_iterator_performance_regression() {
let mut large_data = Vec::new();
for i in 0..1000 {
large_data.push((format!("key_{i:06}"), format!("value_{i:06}")));
}
let large_data_refs: Vec<(&str, &str)> =
large_data.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
let (src, size) = build_table(large_data_refs);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
use std::time::Instant;
let start = Instant::now();
let mut iter = table.iter(None).unwrap();
let count = count_iter(&mut iter).unwrap();
let duration = start.elapsed();
assert_eq!(count, 1000, "Should iterate through all 1000 items");
assert!(duration.as_millis() < 1000, "Iteration took too long: {duration:?}");
let start = Instant::now();
for i in (0..1000).step_by(100) {
let mut iter = table.iter(None).unwrap();
let seek_key =
InternalKey::new(format!("key_{i:06}").into_bytes(), 1, InternalKeyKind::Set, 0);
iter.seek(&seek_key.encode()).unwrap();
assert!(iter.valid(), "Seek to key_{i:06} should succeed");
}
let seek_duration = start.elapsed();
assert!(seek_duration.as_millis() < 100, "Seek operations took too long: {seek_duration:?}");
}
#[test]
fn test_table_iterator_state_invariants() {
let data = vec![("a", "1"), ("b", "2"), ("c", "3"), ("d", "4")];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.seek_to_first().unwrap();
while iter.valid() {
let _key = iter.key();
let _value = iter.value_encoded();
if !iter.next().unwrap() {
break;
}
}
assert!(!iter.valid(), "Iterator should be invalid after exhaustion");
for _ in 0..5 {
assert!(!iter.next().unwrap(), "next() should continue returning false after exhaustion");
assert!(!iter.valid(), "Iterator should remain invalid");
let next_result = iter.next();
assert!(
next_result.is_ok() && !next_result.unwrap(),
"next() should continue returning Ok(false) after exhaustion"
);
}
}
#[test]
fn test_table_iterator_multiple_iterations() {
let data = vec![("alpha", "a"), ("beta", "b"), ("gamma", "g")];
let (src, size) = build_table(data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
for iteration in 0..3 {
let mut iter = table.iter(None).unwrap();
let collected = collect_all(&mut iter).unwrap();
assert_eq!(
collected.len(),
data.len(),
"Iteration #{} should return {} items, got {}",
iteration,
data.len(),
collected.len()
);
for (i, (expected_key, expected_value)) in data.iter().enumerate() {
let (actual_key, actual_value) = &collected[i];
let actual_key_str = std::str::from_utf8(&actual_key.user_key).unwrap();
let actual_value_str = std::str::from_utf8(actual_value.as_ref()).unwrap();
assert_eq!(
actual_key_str, *expected_key,
"Iteration #{iteration}, item {i}: expected key '{expected_key}', got '{actual_key_str}'"
);
assert_eq!(
actual_value_str, *expected_value,
"Iteration #{iteration}, item {i}: expected value '{expected_value}', got '{actual_value_str}'"
);
}
}
}
#[test]
fn test_table_iterator_positioning_edge_cases() {
{
let empty_data: Vec<(&str, &str)> = vec![];
let (src, size) = build_table(empty_data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let result = iter.next();
assert!(result.is_err(), "next() on empty table should return error (no valid blocks)");
assert!(!iter.valid(), "Iterator should not be valid on empty table");
}
{
let single_data = vec![("single", "item")];
let (src, size) = build_table(single_data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
assert!(iter.next().unwrap(), "First advance should succeed on single-item table");
assert!(iter.valid(), "Iterator should be valid after first advance");
assert!(!iter.next().unwrap(), "Second advance should fail on single-item table");
assert!(!iter.valid(), "Iterator should be invalid after second advance");
}
{
let data = vec![("a", "1"), ("b", "2")];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
while iter.next().unwrap() {
}
assert!(!iter.valid(), "Iterator should be invalid after exhaustion");
assert!(!iter.next().unwrap(), "next() after exhaustion should return false");
assert!(!iter.valid(), "Iterator should remain invalid");
let next_result = iter.next();
assert!(
next_result.is_ok() && !next_result.unwrap(),
"next() after exhaustion should return Ok(false)"
);
}
}
#[test]
fn test_table_iterator_next_vs_advance_consistency() {
let data = vec![("x", "1"), ("y", "2"), ("z", "3")];
let (src, size) = build_table(data.clone());
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter1 = table.iter(None).unwrap();
iter1.seek_to_first().unwrap();
let mut collected_via_advance = Vec::new();
while iter1.valid() {
collected_via_advance
.push((iter1.key().to_owned(), iter1.value_encoded().unwrap().to_vec()));
if !iter1.next().unwrap() {
break;
}
}
let mut iter2 = table.iter(None).unwrap();
iter2.seek_to_first().unwrap();
let mut collected_via_next = Vec::new();
while iter2.valid() {
collected_via_next.push((iter2.key().to_owned(), iter2.value_encoded().unwrap().to_vec()));
if !iter2.next().unwrap() {
break;
}
}
assert_eq!(
collected_via_next.len(),
collected_via_advance.len(),
"next() and next() should yield same number of items"
);
for (i, ((next_key, next_val), (adv_key, adv_val))) in
collected_via_next.iter().zip(collected_via_advance.iter()).enumerate()
{
assert_eq!(
next_key.user_key, adv_key.user_key,
"Key mismatch at position {i} between next() and next()"
);
assert_eq!(
next_val.as_slice(),
*adv_val,
"Value mismatch at position {i} between next() and next()"
);
}
}
#[test]
fn test_table_iterator_basic_correctness() {
let mut large_data = Vec::new();
for i in 0..50 {
large_data.push((format!("key_{i:03}"), format!("value_{i:03}")));
}
let large_data_refs: Vec<(&str, &str)> =
large_data.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
let (src, size) = build_table(large_data_refs);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let collected = collect_all(&mut iter).unwrap();
assert_eq!(collected.len(), 50, "Should collect exactly 50 items");
for (i, (actual_key, actual_value)) in collected.iter().enumerate() {
let key_str = std::str::from_utf8(&actual_key.user_key).unwrap();
let value_str = std::str::from_utf8(actual_value.as_ref()).unwrap();
let expected_key = format!("key_{i:03}");
let expected_value = format!("value_{i:03}");
assert_eq!(key_str, expected_key, "Key mismatch at position {i}");
assert_eq!(value_str, expected_value, "Value mismatch at position {i}");
}
}
#[test]
fn test_table_with_partitioned_index() {
let mut opts = default_opts_mut();
opts.index_partition_size = 100; opts.block_size = 64; let opts = Arc::new(opts);
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for i in 0..100 {
let key = format!("key_{i:03}");
let value = format!("value_{i:03}");
let internal_key =
InternalKey::new(Vec::from(key.as_bytes()), i + 1, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
assert!(size > 0, "Table should have non-zero size");
let table = Arc::new(Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap());
match &table.index_block {
&IndexType::Partitioned(_) => {
}
}
for i in 0..100 {
let key = format!("key_{i:03}");
let expected_value = format!("value_{i:03}");
let internal_key = InternalKey::new(
Vec::from(key.as_bytes()),
i + 2, InternalKeyKind::Set,
0,
);
let result = table.get(&internal_key).unwrap();
assert!(result.is_some(), "Key '{key}' not found in table");
if let Some((found_key, found_value)) = result {
assert_eq!(std::str::from_utf8(&found_key.user_key).unwrap(), key, "Key mismatch");
assert_eq!(
std::str::from_utf8(found_value.as_ref()).unwrap(),
expected_value,
"Value mismatch"
);
}
}
let mut iter = table.iter(None).unwrap();
let collected = collect_all(&mut iter).unwrap();
assert_eq!(collected.len(), 100, "Should iterate through all entries");
for (i, (key, value)) in collected.iter().enumerate() {
let expected_key = format!("key_{i:03}");
let expected_value = format!("value_{i:03}");
assert_eq!(
std::str::from_utf8(&key.user_key).unwrap(),
expected_key,
"Iterator key mismatch at position {i}"
);
assert_eq!(
std::str::from_utf8(value.as_ref()).unwrap(),
expected_value,
"Iterator value mismatch at position {i}"
);
}
}
#[test]
fn test_get_nonexistent_key_returns_none() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key = b"key_bbb";
let value = b"value_bbb";
let internal_key = InternalKey::new(Vec::from(key), 1, InternalKeyKind::Set, 0);
writer.add(internal_key, value).unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(
Vec::from(b"key_aaa"),
2, InternalKeyKind::Set,
0,
);
let result = table.get(&lookup_key).unwrap();
assert!(
result.is_none(),
"get() should return None for non-existent key, but got {:?}",
result.map(|(k, v)| (
String::from_utf8_lossy(&k.user_key).to_string(),
String::from_utf8_lossy(&v).to_string()
))
);
}
#[test]
fn test_get_same_key_different_sequence_numbers() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let user_key = b"my_key";
let key1 = InternalKey::new(Vec::from(user_key), 100, InternalKeyKind::Set, 0);
writer.add(key1, b"value_100").unwrap();
let key2 = InternalKey::new(Vec::from(user_key), 50, InternalKeyKind::Set, 0);
writer.add(key2, b"value_50").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key_higher = InternalKey::new(Vec::from(user_key), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key_higher).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), user_key);
assert_eq!(&found_value, b"value_100");
let lookup_key_between = InternalKey::new(Vec::from(user_key), 75, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key_between).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), user_key);
assert_eq!(&found_value, b"value_50");
let lookup_key_exact = InternalKey::new(Vec::from(user_key), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key_exact).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), user_key);
assert_eq!(&found_value, b"value_100");
let different_user_key = b"other_key";
let lookup_key_different =
InternalKey::new(Vec::from(different_user_key), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key_different).unwrap();
assert!(
result.is_none(),
"Should return None for different user_key, got: {:?}",
result.map(|(k, v)| (
String::from_utf8_lossy(&k.user_key).to_string(),
String::from_utf8_lossy(&v).to_string()
))
);
}
#[test]
fn test_get_with_lower_sequence_number() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_aaa = InternalKey::new(Vec::from(b"aaa_key"), 100, InternalKeyKind::Set, 0);
writer.add(key_aaa, b"value_aaa").unwrap();
let key_bbb = InternalKey::new(Vec::from(b"bbb_key"), 75, InternalKeyKind::Set, 0);
writer.add(key_bbb, b"value_bbb").unwrap();
let user_key = b"my_key";
let key = InternalKey::new(Vec::from(user_key), 50, InternalKeyKind::Set, 0);
writer.add(key, b"value_50").unwrap();
let key_zzz = InternalKey::new(Vec::from(b"zzz_key"), 100, InternalKeyKind::Set, 0);
writer.add(key_zzz, b"value_zzz").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(user_key), 25, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
if result.is_some() {
let (found_key, found_value) = result.unwrap();
panic!(
"BUG: Expected None, got key={}, seq_num={}, value={:?}",
String::from_utf8_lossy(&found_key.user_key),
found_key.seq_num(),
String::from_utf8_lossy(&found_value)
);
}
assert!(result.is_none());
}
#[test]
fn test_get_empty_table() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"any_key"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key);
assert!(result.is_err());
}
#[test]
fn test_get_multiple_keys_with_sequence_variations() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_a = InternalKey::new(Vec::from(b"key_a"), 100, InternalKeyKind::Set, 0);
writer.add(key_a, b"value_a_100").unwrap();
let key_b = InternalKey::new(Vec::from(b"key_b"), 50, InternalKeyKind::Set, 0);
writer.add(key_b, b"value_b_50").unwrap();
let key_c = InternalKey::new(Vec::from(b"key_c"), 75, InternalKeyKind::Set, 0);
writer.add(key_c, b"value_c_75").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_b_low = InternalKey::new(Vec::from(b"key_b"), 25, InternalKeyKind::Set, 0);
let result = table.get(&lookup_b_low).unwrap();
assert!(result.is_none());
let lookup_a_high = InternalKey::new(Vec::from(b"key_a"), 150, InternalKeyKind::Set, 0);
let result = table.get(&lookup_a_high).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), b"key_a");
assert_eq!(&found_value, b"value_a_100");
let lookup_c_exact = InternalKey::new(Vec::from(b"key_c"), 75, InternalKeyKind::Set, 0);
let result = table.get(&lookup_c_exact).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), b"key_c");
assert_eq!(&found_value, b"value_c_75");
let lookup_key_b5 = InternalKey::new(Vec::from(b"key_b5"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key_b5).unwrap();
assert!(result.is_none());
}
#[test]
fn test_get_boundary_conditions() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_aaa = InternalKey::new(Vec::from(b"aaa_key"), 100, InternalKeyKind::Set, 0);
writer.add(key_aaa, b"value_aaa").unwrap();
let user_key = b"boundary_key";
let key = InternalKey::new(Vec::from(user_key), 100, InternalKeyKind::Set, 0);
writer.add(key, b"value_100").unwrap();
let key_zzz = InternalKey::new(Vec::from(b"zzz_key"), 100, InternalKeyKind::Set, 0);
writer.add(key_zzz, b"value_zzz").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_min = InternalKey::new(Vec::from(user_key), 0, InternalKeyKind::Set, 0);
let result = table.get(&lookup_min).unwrap();
assert!(result.is_none());
let lookup_max =
InternalKey::new(Vec::from(user_key), INTERNAL_KEY_SEQ_NUM_MAX, InternalKeyKind::Set, 0);
let result = table.get(&lookup_max).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), user_key);
assert_eq!(&found_value, b"value_100");
let lookup_one = InternalKey::new(Vec::from(user_key), 1, InternalKeyKind::Set, 0);
let result = table.get(&lookup_one).unwrap();
assert!(result.is_none());
}
#[test]
fn test_get_lookup_higher_than_stored() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_aaa = InternalKey::new(Vec::from(b"aaa_key"), 100, InternalKeyKind::Set, 0);
writer.add(key_aaa, b"value_aaa").unwrap();
let key_bbb = InternalKey::new(Vec::from(b"bbb_key"), 80, InternalKeyKind::Set, 0);
writer.add(key_bbb, b"value_bbb").unwrap();
let user_key = b"mykey";
let key = InternalKey::new(Vec::from(user_key), 25, InternalKeyKind::Set, 0);
writer.add(key, b"value_25").unwrap();
let key_zzz = InternalKey::new(Vec::from(b"zzz_key"), 100, InternalKeyKind::Set, 0);
writer.add(key_zzz, b"value_zzz").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(user_key), 50, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), user_key);
assert_eq!(found_key.seq_num(), 25);
assert_eq!(&found_value, b"value_25");
}
#[test]
fn test_get_partition_index_sequence_numbers() {
let opts = Arc::new(Options::new().with_filter_policy(None).with_block_size(512));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
for i in 0..20 {
let key = format!("aaa_key_{:03}", i);
let value = format!("value_{}", i);
let internal_key =
InternalKey::new(Vec::from(key.as_bytes()), 1000, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let target_key = b"target_key";
let key_500 = InternalKey::new(Vec::from(target_key), 500, InternalKeyKind::Set, 0);
writer.add(key_500, b"value_500").unwrap();
for i in 0..40 {
let key = format!("zzz_key_{:03}", i);
let value = format!("value_{}", i);
let internal_key =
InternalKey::new(Vec::from(key.as_bytes()), 1000, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
assert!(table.meta.properties.block_count > 1);
let lookup_high = InternalKey::new(Vec::from(target_key), 1000, InternalKeyKind::Set, 0);
let result = table.get(&lookup_high).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), target_key);
assert_eq!(found_key.seq_num(), 500);
assert_eq!(&found_value, b"value_500");
let lookup_exact = InternalKey::new(Vec::from(target_key), 500, InternalKeyKind::Set, 0);
let result = table.get(&lookup_exact).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), target_key);
assert_eq!(found_key.seq_num(), 500);
assert_eq!(&found_value, b"value_500");
let lookup_low = InternalKey::new(Vec::from(target_key), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_low).unwrap();
assert!(result.is_none());
let filler_key = b"zzz_key_010";
let lookup_filler = InternalKey::new(Vec::from(filler_key), 1000, InternalKeyKind::Set, 0);
let result = table.get(&lookup_filler).unwrap();
assert!(result.is_some());
let (found_key, _) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), filler_key);
}
#[test]
fn test_get_nonexistent_key_greater_than_all() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_aaa = InternalKey::new(Vec::from(b"key_aaa"), 100, InternalKeyKind::Set, 0);
writer.add(key_aaa, b"value_aaa").unwrap();
let key_bbb = InternalKey::new(Vec::from(b"key_bbb"), 100, InternalKeyKind::Set, 0);
writer.add(key_bbb, b"value_bbb").unwrap();
let key_ccc = InternalKey::new(Vec::from(b"key_ccc"), 100, InternalKeyKind::Set, 0);
writer.add(key_ccc, b"value_ccc").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"key_zzz"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_none());
}
#[test]
fn test_get_nonexistent_key_between_existing() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_aaa = InternalKey::new(Vec::from(b"key_aaa"), 100, InternalKeyKind::Set, 0);
writer.add(key_aaa, b"value_aaa").unwrap();
let key_ccc = InternalKey::new(Vec::from(b"key_ccc"), 100, InternalKeyKind::Set, 0);
writer.add(key_ccc, b"value_ccc").unwrap();
let key_eee = InternalKey::new(Vec::from(b"key_eee"), 100, InternalKeyKind::Set, 0);
writer.add(key_eee, b"value_eee").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"key_bbb"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_none());
}
#[test]
fn test_get_with_tombstone() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_other = InternalKey::new(Vec::from(b"key_other"), 100, InternalKeyKind::Set, 0);
writer.add(key_other, b"value_other").unwrap();
let key_target = InternalKey::new(Vec::from(b"key_target"), 100, InternalKeyKind::Delete, 0);
writer.add(key_target, b"").unwrap();
let key_zzz = InternalKey::new(Vec::from(b"key_zzz"), 100, InternalKeyKind::Set, 0);
writer.add(key_zzz, b"value_zzz").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"key_target"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_some());
let (found_key, _) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), b"key_target");
assert!(found_key.is_tombstone());
}
#[test]
fn test_get_nonexistent_with_similar_prefix() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key1 = InternalKey::new(Vec::from(b"user_data"), 100, InternalKeyKind::Set, 0);
writer.add(key1, b"value1").unwrap();
let key2 = InternalKey::new(Vec::from(b"user_profile"), 100, InternalKeyKind::Set, 0);
writer.add(key2, b"value2").unwrap();
let key3 = InternalKey::new(Vec::from(b"username"), 100, InternalKeyKind::Set, 0);
writer.add(key3, b"value3").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"user"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_none());
}
#[test]
fn test_get_nonexistent_empty_key() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_aaa = InternalKey::new(Vec::from(b"key_aaa"), 100, InternalKeyKind::Set, 0);
writer.add(key_aaa, b"value_aaa").unwrap();
let key_bbb = InternalKey::new(Vec::from(b"key_bbb"), 100, InternalKeyKind::Set, 0);
writer.add(key_bbb, b"value_bbb").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(b""), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_none());
}
#[test]
fn test_get_nonexistent_with_special_chars() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key1 = InternalKey::new(Vec::from(b"key\x00"), 100, InternalKeyKind::Set, 0);
writer.add(key1, b"value0").unwrap();
let key2 = InternalKey::new(Vec::from(b"key\x01"), 100, InternalKeyKind::Set, 0);
writer.add(key2, b"value1").unwrap();
let key3 = InternalKey::new(Vec::from(b"key\xFF"), 100, InternalKeyKind::Set, 0);
writer.add(key3, b"value_ff").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"key\x02"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_none());
}
#[test]
fn test_get_nonexistent_in_large_table() {
let opts = Arc::new(Options::new().with_filter_policy(None).with_block_size(512));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
for i in 0..100 {
if i == 50 {
continue;
}
let key = format!("key_{:03}", i);
let value = format!("value_{}", i);
let internal_key =
InternalKey::new(Vec::from(key.as_bytes()), 100, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
assert!(table.meta.properties.block_count > 1);
let lookup_key = InternalKey::new(Vec::from(b"key_050"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_none());
}
#[test]
fn test_get_all_keys_same_prefix_different_suffix() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key_a = InternalKey::new(Vec::from(b"prefix_a"), 100, InternalKeyKind::Set, 0);
writer.add(key_a, b"value_a").unwrap();
let key_b = InternalKey::new(Vec::from(b"prefix_b"), 100, InternalKeyKind::Set, 0);
writer.add(key_b, b"value_b").unwrap();
let key_c = InternalKey::new(Vec::from(b"prefix_c"), 100, InternalKeyKind::Set, 0);
writer.add(key_c, b"value_c").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"prefix_d"), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(result.is_none());
}
#[test]
fn test_table_iterator_seek_nonexistent_key() {
let opts = Arc::new(Options::default());
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key = b"key_bbb";
let value = b"value_bbb";
let internal_key = InternalKey::new(Vec::from(key), 1, InternalKeyKind::Set, 0);
writer.add(internal_key, value).unwrap();
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let lookup_key = InternalKey::new(
Vec::from(b"key_aaa"),
2, InternalKeyKind::Set,
0,
);
iter.seek(&lookup_key.encode()).unwrap();
assert!(iter.valid(), "Iterator should be valid (positioned at next key)");
let current_key = iter.key();
assert_eq!(
current_key.user_key(),
b"key_bbb",
"Iterator should be positioned at the next greater key"
);
let is_exact_match = current_key.user_key() == b"key_aaa";
assert!(!is_exact_match, "Caller should check for exact match if needed");
}
#[test]
fn test_table_iterator_seek_nonexistent_past_end() {
let opts = Arc::new(Options::default());
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key = b"key_bbb";
let value = b"value_bbb";
let internal_key = InternalKey::new(Vec::from(key), 1, InternalKeyKind::Set, 0);
writer.add(internal_key, value).unwrap();
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"key_zzz"), 2, InternalKeyKind::Set, 0);
iter.seek(&lookup_key.encode()).unwrap();
assert!(!iter.valid(), "Iterator should be invalid when seeking past all keys");
}
#[test]
fn test_table_iterator_seek_exact_match() {
let opts = Arc::new(Options::default());
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key = b"key_bbb";
let value = b"value_bbb";
let internal_key = InternalKey::new(Vec::from(key), 1, InternalKeyKind::Set, 0);
writer.add(internal_key, value).unwrap();
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let lookup_key = InternalKey::new(Vec::from(b"key_bbb"), 2, InternalKeyKind::Set, 0);
iter.seek(&lookup_key.encode()).unwrap();
assert!(iter.valid(), "Iterator should be valid");
let current_key = iter.key();
assert_eq!(
current_key.user_key(),
b"key_bbb",
"Iterator should be positioned at the exact key"
);
}
#[test]
fn test_table_iter_upper_bound_included() {
let data = vec![
("key_000", "value"),
("key_001", "value"),
("key_002", "value"),
("key_003", "value"),
("key_004", "value"),
("key_005", "value"),
("key_006", "value"),
("key_007", "value"),
("key_008", "value"),
("key_009", "value"),
];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Unbounded,
Bound::Included(b"key_005".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_first().unwrap();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.next().unwrap() {
break;
}
}
assert_eq!(results.len(), 6, "Should return exactly 6 items");
assert_eq!(results[0], "key_000");
assert_eq!(results[1], "key_001");
assert_eq!(results[2], "key_002");
assert_eq!(results[3], "key_003");
assert_eq!(results[4], "key_004");
assert_eq!(results[5], "key_005");
assert_eq!(results.last().unwrap(), "key_005");
}
#[test]
fn test_table_iter_upper_bound_excluded() {
let data = vec![
("key_000", "value"),
("key_001", "value"),
("key_002", "value"),
("key_003", "value"),
("key_004", "value"),
("key_005", "value"),
("key_006", "value"),
("key_007", "value"),
("key_008", "value"),
("key_009", "value"),
];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Unbounded,
Bound::Excluded(b"key_005".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_first().unwrap();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.next().unwrap() {
break;
}
}
assert_eq!(results.len(), 5, "Should return exactly 5 items");
assert_eq!(results[0], "key_000");
assert_eq!(results[1], "key_001");
assert_eq!(results[2], "key_002");
assert_eq!(results[3], "key_003");
assert_eq!(results[4], "key_004");
assert_eq!(results.last().unwrap(), "key_004");
}
#[test]
fn test_table_iter_unbounded_reverse() {
let data = vec![
("key_000", "value"),
("key_001", "value"),
("key_002", "value"),
("key_003", "value"),
("key_004", "value"),
("key_005", "value"),
("key_006", "value"),
("key_007", "value"),
("key_008", "value"),
("key_009", "value"),
];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter_temp = table.iter(None).unwrap();
let collected = collect_all(&mut iter_temp).unwrap();
assert_eq!(collected.len(), 10, "Forward iteration should return 10 items");
let forward_keys: Vec<String> = collected
.iter()
.map(|(k, _)| std::str::from_utf8(&k.user_key).unwrap().to_string())
.collect();
assert_eq!(
forward_keys,
vec![
"key_000", "key_001", "key_002", "key_003", "key_004", "key_005", "key_006", "key_007",
"key_008", "key_009"
]
);
let mut iter = table.iter(None).unwrap();
iter.seek_to_last().unwrap();
let mut results = Vec::new();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(results.len(), 10, "Should return exactly 10 items");
assert_eq!(results[0], "key_009");
assert_eq!(results[9], "key_000");
}
#[test]
fn test_table_iter_lower_bound_included_reverse() {
let data = vec![
("key_000", "value"),
("key_001", "value"),
("key_002", "value"),
("key_003", "value"),
("key_004", "value"),
("key_005", "value"),
("key_006", "value"),
("key_007", "value"),
("key_008", "value"),
("key_009", "value"),
];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Included(b"key_003".as_slice()),
Bound::Unbounded,
)))
.unwrap();
let mut results = Vec::new();
iter.seek_to_last().unwrap();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(results.len(), 7, "Should return exactly 7 items");
assert_eq!(results[0], "key_009");
assert_eq!(results[1], "key_008");
assert_eq!(results[2], "key_007");
assert_eq!(results[3], "key_006");
assert_eq!(results[4], "key_005");
assert_eq!(results[5], "key_004");
assert_eq!(results[6], "key_003");
assert_eq!(results.last().unwrap(), "key_003");
}
#[test]
fn test_table_iter_both_bounds() {
let data = vec![
("key_000", "value"),
("key_001", "value"),
("key_002", "value"),
("key_003", "value"),
("key_004", "value"),
("key_005", "value"),
("key_006", "value"),
("key_007", "value"),
("key_008", "value"),
("key_009", "value"),
];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Included(b"key_002".as_slice()),
Bound::Excluded(b"key_007".as_slice()),
)))
.unwrap();
iter.seek_first().unwrap();
let mut results = Vec::new();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.next().unwrap() {
break;
}
}
assert_eq!(results.len(), 5, "Should return exactly 5 items");
assert_eq!(results[0], "key_002");
assert_eq!(results[1], "key_003");
assert_eq!(results[2], "key_004");
assert_eq!(results[3], "key_005");
assert_eq!(results[4], "key_006");
}
#[test]
fn test_table_iter_unbounded() {
let data = vec![
("key_000", "value"),
("key_001", "value"),
("key_002", "value"),
("key_003", "value"),
("key_004", "value"),
("key_005", "value"),
("key_006", "value"),
("key_007", "value"),
("key_008", "value"),
("key_009", "value"),
];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter =
table.iter(Some(user_range_to_internal_range(Bound::Unbounded, Bound::Unbounded))).unwrap();
let mut results = Vec::new();
iter.seek_first().unwrap();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.next().unwrap() {
break;
}
}
assert_eq!(results.len(), 10, "Should return exactly 10 items");
assert_eq!(results[0], "key_000");
assert_eq!(results[9], "key_009");
}
#[test]
fn test_table_iter_forward_and_backward() {
let data = vec![
("key_000", "value"),
("key_001", "value"),
("key_002", "value"),
("key_003", "value"),
("key_004", "value"),
("key_005", "value"),
("key_006", "value"),
("key_007", "value"),
("key_008", "value"),
("key_009", "value"),
("key_010", "value"),
("key_011", "value"),
("key_012", "value"),
("key_013", "value"),
("key_014", "value"),
("key_015", "value"),
("key_016", "value"),
("key_017", "value"),
("key_018", "value"),
("key_019", "value"),
("key_020", "value"),
("key_021", "value"),
("key_022", "value"),
("key_023", "value"),
("key_024", "value"),
("key_025", "value"),
("key_026", "value"),
("key_027", "value"),
("key_028", "value"),
("key_029", "value"),
];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut forward_iter = table.iter(None).unwrap();
forward_iter.seek_to_first().unwrap();
let mut forward_keys = Vec::new();
while forward_iter.valid() {
let key = forward_iter.key();
forward_keys.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !forward_iter.next().unwrap() {
break;
}
}
assert_eq!(forward_keys.len(), 30);
assert_eq!(forward_keys[0], "key_000");
assert_eq!(forward_keys[29], "key_029");
let mut backward_iter = table.iter(None).unwrap();
backward_iter.seek_to_last().unwrap();
let mut backward_keys = Vec::new();
while backward_iter.valid() {
let key = backward_iter.key();
backward_keys.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !backward_iter.prev().unwrap() {
break;
}
}
assert_eq!(backward_keys.len(), 30);
assert_eq!(backward_keys[0], "key_029");
assert_eq!(backward_keys[29], "key_000");
let mut seek_iter = table.iter(None).unwrap();
seek_iter.seek_to_last().unwrap();
let mut seek_backward = Vec::new();
while seek_iter.valid() {
let key = seek_iter.key();
seek_backward.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !seek_iter.prev().unwrap() {
break;
}
}
assert_eq!(seek_backward.len(), 30);
assert_eq!(seek_backward[0], "key_029");
assert_eq!(seek_backward[29], "key_000");
let expected_forward: Vec<String> = (0..30).map(|i| format!("key_{:03}", i)).collect();
assert_eq!(forward_keys, expected_forward);
let expected_backward: Vec<String> = (0..30).rev().map(|i| format!("key_{:03}", i)).collect();
assert_eq!(backward_keys, expected_backward);
assert_eq!(seek_backward, backward_keys);
}
#[test]
fn test_table_iter_upper_bound_excluded_reverse() {
let data = vec![
("key_000", "value", 1),
("key_001", "value", 1),
("key_002", "value", 1),
("key_003", "value", 1),
("key_004", "value", 1),
("key_005", "value3", 3), ("key_005", "value2", 2), ("key_005", "value", 1), ("key_006", "value", 1),
("key_007", "value", 1),
("key_008", "value", 1),
("key_009", "value", 1),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Unbounded,
Bound::Excluded(b"key_005".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_last().unwrap();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(results.len(), 5, "Should return exactly 5 items");
assert_eq!(results[0], "key_004"); assert_eq!(results[4], "key_000");
assert!(!results.iter().any(|k| k == "key_005"), "key_005 should not appear in results");
}
#[test]
fn test_table_iter_upper_bound_included_reverse_nonexistent_key() {
let data = vec![
("key_000", "value"),
("key_001", "value"),
("key_002", "value"),
("key_003", "value"),
("key_004", "value"),
("key_006", "value"),
("key_007", "value"),
("key_008", "value"),
("key_009", "value"),
];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Unbounded,
Bound::Included(b"key_005".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_last().unwrap();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(results.len(), 5, "Should return exactly 5 items");
assert_eq!(results[0], "key_004"); assert_eq!(results[4], "key_000");
assert!(!results.iter().any(|k| k == "key_006"), "key_006 should not appear");
}
#[test]
fn test_table_iter_lower_bound_excluded_forward_with_multiple_versions() {
let data = vec![
("key_000", "v1", 1),
("key_001", "v1", 1),
("key_002", "v1", 1),
("key_003", "v1", 3),
("key_003", "v2", 2), ("key_003", "v3", 1),
("key_004", "v1", 2),
("key_004", "v1", 1),
("key_005", "v1", 1),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Excluded(b"key_003".as_slice()),
Bound::Unbounded,
)))
.unwrap();
let mut results = Vec::new();
iter.seek_first().unwrap();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.next().unwrap() {
break;
}
}
assert!(results[0] == "key_004", "First result should be key_004, got {}", results[0]);
assert!(!results.iter().any(|k| k == "key_003"), "key_003 should not appear in results");
}
#[test]
fn test_table_iter_excluded_bound_across_multiple_blocks() {
let mut data = vec![];
for seq in (1..=100).rev() {
data.push(("key_003", "value", seq));
}
data.push(("key_004", "value", 1));
data.push(("key_005", "value", 1));
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Excluded(b"key_003".as_slice()),
Bound::Unbounded,
)))
.unwrap();
iter.seek_first().unwrap();
let mut results = Vec::new();
while iter.valid() {
let key = iter.key();
let user_key = String::from_utf8(key.user_key().to_vec()).unwrap();
results.push(user_key);
if !iter.next().unwrap() {
break;
}
}
assert!(
!results.iter().any(|k| k == "key_003"),
"key_003 should be completely excluded, but found in results"
);
assert_eq!(
results.first().unwrap(),
"key_004",
"First key should be key_004, got {}",
results.first().unwrap()
);
assert_eq!(results.len(), 2, "Should return exactly 2 keys, got {}", results.len());
}
#[test]
fn test_table_iter_excluded_bound_across_partitions_reverse() {
let mut data = vec![];
data.push(("key_001", "value", 1));
data.push(("key_002", "value", 1));
for seq in (1..=100).rev() {
data.push(("key_003", "value", seq));
}
data.push(("key_004", "value", 1));
data.push(("key_005", "value", 1));
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Unbounded,
Bound::Excluded(b"key_003".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_last().unwrap();
while iter.valid() {
let key = iter.key();
let user_key = String::from_utf8(key.user_key().to_vec()).unwrap();
results.push(user_key);
if !iter.prev().unwrap() {
break;
}
}
assert!(
!results.iter().any(|k| k == "key_003"),
"key_003 should be completely excluded, but found in results"
);
assert_eq!(
results.first().unwrap(),
"key_002",
"First key in reverse should be key_002, got {}",
results.first().unwrap()
);
assert_eq!(results.len(), 2, "Should return exactly 2 keys");
assert_eq!(results[0], "key_002");
assert_eq!(results[1], "key_001");
}
#[test]
fn test_table_iter_both_bounds_excluded_same_key() {
let data = vec![
("key_001", "value", 1),
("key_002", "value", 1),
("key_003", "value", 100),
("key_003", "value", 50),
("key_003", "value", 1),
("key_004", "value", 1),
("key_005", "value", 1),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Excluded(b"key_003".as_slice()),
Bound::Excluded(b"key_003".as_slice()),
)))
.unwrap();
iter.seek_first().unwrap();
let results = collect_all(&mut iter).unwrap();
assert_eq!(
results.len(),
0,
"Range (Excluded(X), Excluded(X)) should be empty, got {} items",
results.len()
);
}
#[test]
fn test_table_iter_both_bounds_excluded_same_key_reverse() {
let data = vec![
("key_001", "value", 1),
("key_002", "value", 1),
("key_003", "value", 100),
("key_003", "value", 50),
("key_003", "value", 1),
("key_004", "value", 1),
("key_005", "value", 1),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Excluded(b"key_003".as_slice()),
Bound::Excluded(b"key_003".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_last().unwrap();
while iter.valid() {
results.push((iter.key().to_owned(), iter.value_encoded().unwrap().to_vec()));
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(
results.len(),
0,
"Range (Excluded(X), Excluded(X)) in reverse should be empty, got {} items",
results.len()
);
}
#[test]
fn test_table_iter_excluded_bounds_adjacent_keys() {
let data = vec![
("key_001", "value", 1),
("key_002", "value", 100),
("key_002", "value", 50),
("key_003", "value", 80),
("key_003", "value", 40),
("key_003", "value", 10),
("key_004", "value", 100),
("key_004", "value", 50),
("key_005", "value", 1),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Excluded(b"key_002".as_slice()),
Bound::Excluded(b"key_004".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_first().unwrap();
while iter.valid() {
let key = iter.key();
let user_key = String::from_utf8(key.user_key().to_vec()).unwrap();
results.push((user_key, key.seq_num()));
if !iter.next().unwrap() {
break;
}
}
assert_eq!(results.len(), 3, "Should return 3 versions of key_003");
assert!(results.iter().all(|(k, _)| k == "key_003"), "All results should be key_003");
assert!(
!results.iter().any(|(k, _)| k == "key_002" || k == "key_004"),
"Should not contain key_002 or key_004"
);
assert_eq!(results[0].1, 80);
assert_eq!(results[1].1, 40);
assert_eq!(results[2].1, 10);
}
#[test]
fn test_table_iter_multiple_versions_at_both_bounds() {
let data = vec![
("key_002", "value", 100),
("key_002", "value", 90),
("key_002", "value", 80),
("key_003", "value", 50),
("key_004", "value", 50),
("key_005", "value", 100),
("key_005", "value", 90),
("key_005", "value", 80),
("key_006", "value", 1),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Excluded(b"key_002".as_slice()),
Bound::Excluded(b"key_005".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_first().unwrap();
while iter.valid() {
let key = iter.key();
let user_key = String::from_utf8(key.user_key().to_vec()).unwrap();
results.push(user_key);
if !iter.next().unwrap() {
break;
}
}
assert_eq!(results.len(), 2, "Should return exactly 2 items");
assert_eq!(results[0], "key_003");
assert_eq!(results[1], "key_004");
assert!(
!results.iter().any(|k| k == "key_002" || k == "key_005"),
"Should not contain any version of excluded bounds"
);
}
#[test]
fn test_get_block_boundary_same_user_key_bug() {
let opts = Arc::new(
Options::new()
.with_filter_policy(None) .with_block_size(32), );
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let user_key = b"test";
let key1 = InternalKey::new(Vec::from(user_key), 300, InternalKeyKind::Set, 0);
writer.add(key1, b"v").unwrap();
let key2 = InternalKey::new(Vec::from(user_key), 200, InternalKeyKind::Set, 0);
writer.add(key2, b"v").unwrap();
let key3 = InternalKey::new(Vec::from(user_key), 100, InternalKeyKind::Set, 0);
writer.add(key3, b"v").unwrap();
let key4 = InternalKey::new(Vec::from(user_key), 50, InternalKeyKind::Set, 0);
writer.add(key4, b"v").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
assert!(
table.meta.properties.num_data_blocks >= 2,
"Test requires at least 2 data blocks to trigger the bug, got {}. \
Adjust block_size or add more entries.",
table.meta.properties.num_data_blocks
);
let lookup_boundary_key = InternalKey::new(Vec::from(user_key), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup_boundary_key).unwrap();
assert!(
result.is_some(),
"BUG: get() returned None for key at block boundary. \
The key ('test', seq=200) exists as the last key of block 1, \
but the index comparison uses < instead of <=, causing it to fail \
when lookup key equals the separator key."
);
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key.as_slice(), user_key);
assert_eq!(found_key.seq_num(), 200);
assert_eq!(found_value.as_slice(), b"v");
let lookup_key1 = InternalKey::new(Vec::from(user_key), 300, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key1).unwrap();
assert!(result.is_some(), "seq=300 should be found");
let lookup_key3 = InternalKey::new(Vec::from(user_key), 100, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key3).unwrap();
assert!(result.is_some(), "seq=100 should be found");
let lookup_key4 = InternalKey::new(Vec::from(user_key), 50, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key4).unwrap();
assert!(result.is_some(), "seq=50 should be found");
}
#[test]
fn test_iterator_trait_prev_multi_partition_bug() {
let opts = Arc::new(
Options::new()
.with_filter_policy(None)
.with_block_size(50) .with_index_partition_size(50), );
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let num_keys = 100;
for i in 0..num_keys {
let key = InternalKey::new(
format!("key_{:05}", i).into_bytes(),
1000 - i as u64, InternalKeyKind::Set,
0,
);
writer.add(key, format!("value_{}", i).as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table_arc = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let IndexType::Partitioned(ref partitioned_index) = table_arc.index_block;
let num_partitions = partitioned_index.blocks.len();
assert!(
num_partitions >= 2,
"Test requires at least 2 index partitions to trigger the bug, got {}. \
Adjust index_partition_size or add more keys.",
num_partitions
);
println!("Created table with {} index partitions", num_partitions);
let mut iter = table_arc.iter(None).unwrap();
iter.seek_to_last().unwrap();
assert!(iter.valid(), "Iterator should be valid after seek_to_last");
let mut correct_results = Vec::new();
correct_results.push(iter.key().user_key().to_vec());
while iter.prev().unwrap() {
correct_results.push(iter.key().user_key().to_vec());
}
let correct_count = correct_results.len();
println!("Correct backward iteration found {} keys", correct_count);
assert_eq!(correct_count, num_keys as usize, "Should find all keys");
let mut iter2 = table_arc.iter(None).unwrap();
iter2.seek_to_last().unwrap();
assert!(iter2.valid(), "Iterator should be valid after seek_to_last");
let mut buggy_results = Vec::new();
buggy_results.push(iter2.key().user_key().to_vec());
while iter2.prev().unwrap() {
buggy_results.push(iter2.key().user_key().to_vec());
}
let buggy_count = buggy_results.len();
println!("Buggy trait prev() found {} keys", buggy_count);
assert_eq!(
buggy_count, correct_count,
"BUG DETECTED: Iterator::prev() trait method only found {} keys, \
but should have found {} keys. The trait method uses self.index_block \
which is only the first partition's iterator and doesn't handle \
crossing partition boundaries.",
buggy_count, correct_count
);
}
#[test]
fn test_partitioned_index_same_user_key_spanning_partitions_bug() {
let opts = Arc::new(
Options::new()
.with_filter_policy(None)
.with_block_size(50) .with_index_partition_size(50), );
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let user_key = b"foo";
let num_versions = 100;
for seq in (1..=num_versions).rev() {
let key = InternalKey::new(user_key.to_vec(), seq as u64, InternalKeyKind::Set, 0);
writer.add(key, format!("value_at_seq_{}", seq).as_bytes()).unwrap();
}
let key = InternalKey::new(b"goo".to_vec(), 1, InternalKeyKind::Set, 0);
writer.add(key, b"value_goo").unwrap();
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let IndexType::Partitioned(ref partitioned_index) = table.index_block;
let num_partitions = partitioned_index.blocks.len();
println!("Created table with {} index partitions", num_partitions);
for (i, block) in partitioned_index.blocks.iter().enumerate() {
let sep_key = InternalKey::decode(&block.separator_key);
println!(
" Partition {}: user_key = {:?}, seq = {}",
i,
String::from_utf8_lossy(&sep_key.user_key),
sep_key.seq_num()
);
}
assert!(
num_partitions >= 2,
"Test requires at least 2 index partitions to trigger the bug, got {}. \
Adjust index_partition_size or add more versions.",
num_partitions
);
let foo_partitions: Vec<_> = partitioned_index
.blocks
.iter()
.enumerate()
.filter(|(_, b)| InternalKey::decode(&b.separator_key).user_key == b"foo")
.collect();
println!(
"Partitions with user_key 'foo': {:?}",
foo_partitions.iter().map(|(i, _)| i).collect::<Vec<_>>()
);
let query_seq = 30u64;
let lookup_key = InternalKey::new(user_key.to_vec(), query_seq, InternalKeyKind::Set, 0);
let result = table.get(&lookup_key).unwrap();
assert!(
result.is_some(),
"BUG DETECTED: Table::get returned None for (foo, seq={}), but version exists!\n\
The bug is in TopLevelIndex::find_block_handle_by_key which uses user_key-only lookup.\n\
When the same user_key spans multiple partitions, it only searches the first partition\n\
(which contains high seq_nums) and misses entries in later partitions (low seq_nums).",
query_seq
);
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key, user_key.to_vec());
println!(
"Found key with seq_num={}, value={:?}",
found_key.seq_num(),
String::from_utf8_lossy(&found_value)
);
assert!(
found_key.seq_num() <= query_seq,
"Found version seq_num {} should be <= query seq_num {}",
found_key.seq_num(),
query_seq
);
for query_seq in [10, 25, 50, 75, 99] {
let lookup = InternalKey::new(user_key.to_vec(), query_seq, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(
result.is_some(),
"BUG: Table::get returned None for (foo, seq={}), but version should exist!",
query_seq
);
let (found_key, _) = result.unwrap();
assert!(
found_key.seq_num() <= query_seq,
"For query seq={}, found seq={} which is greater (should be <=)",
query_seq,
found_key.seq_num()
);
}
}
#[test]
fn test_table_get_mvcc_correct_version() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let user_key = b"my_key";
for seq in [100u64, 75, 50, 25] {
let key = InternalKey::new(user_key.to_vec(), seq, InternalKeyKind::Set, 0);
let value = format!("value_at_seq_{}", seq);
writer.add(key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup = InternalKey::new(user_key.to_vec(), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_some());
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.seq_num(), 100);
assert_eq!(&found_value, b"value_at_seq_100");
let lookup = InternalKey::new(user_key.to_vec(), 80, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_some());
let (found_key, _) = result.unwrap();
assert_eq!(found_key.seq_num(), 75);
let lookup = InternalKey::new(user_key.to_vec(), 50, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_some());
let (found_key, _) = result.unwrap();
assert_eq!(found_key.seq_num(), 50);
let lookup = InternalKey::new(user_key.to_vec(), 10, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_none(), "No version should be visible at seq=10");
}
#[test]
fn test_table_get_returns_none_for_future_version() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key = InternalKey::new(b"future_key".to_vec(), 100, InternalKeyKind::Set, 0);
writer.add(key, b"future_value").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup = InternalKey::new(b"future_key".to_vec(), 50, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_none(), "Should not see future version at seq=100 when querying at seq=50");
}
#[test]
fn test_table_get_different_user_keys() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let keys = ["apple", "banana", "cherry", "date"];
for key in &keys {
let ikey = InternalKey::new(key.as_bytes().to_vec(), 100, InternalKeyKind::Set, 0);
let value = format!("value_for_{}", key);
writer.add(ikey, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
for key in &keys {
let lookup = InternalKey::new(key.as_bytes().to_vec(), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_some(), "Should find key {}", key);
let (found_key, found_value) = result.unwrap();
assert_eq!(found_key.user_key, key.as_bytes().to_vec());
assert_eq!(String::from_utf8_lossy(&found_value), format!("value_for_{}", key));
}
let lookup = InternalKey::new(b"nonexistent".to_vec(), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_none());
}
#[test]
fn test_table_get_at_block_boundaries() {
let opts = Arc::new(
Options::new().with_filter_policy(None).with_block_size(64),
);
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
for i in 0..20 {
let key = format!("key_{:04}", i);
let value = format!("value_{:04}", i);
let ikey = InternalKey::new(key.as_bytes().to_vec(), 100, InternalKeyKind::Set, 0);
writer.add(ikey, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
assert!(
table.meta.properties.num_data_blocks > 1,
"Test requires multiple blocks, got {}",
table.meta.properties.num_data_blocks
);
for i in 0..20 {
let key = format!("key_{:04}", i);
let lookup = InternalKey::new(key.as_bytes().to_vec(), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_some(), "Should find key {}", key);
let (found_key, _) = result.unwrap();
assert_eq!(found_key.user_key, key.as_bytes().to_vec());
}
}
#[test]
fn test_table_get_tombstone_handling() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let set_key = InternalKey::new(b"my_key".to_vec(), 100, InternalKeyKind::Set, 0);
writer.add(set_key, b"original_value").unwrap();
let delete_key = InternalKey::new(b"my_key".to_vec(), 50, InternalKeyKind::Delete, 0);
writer.add(delete_key, b"").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup = InternalKey::new(b"my_key".to_vec(), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_some());
let (found_key, _) = result.unwrap();
assert_eq!(found_key.seq_num(), 100);
assert!(!found_key.is_tombstone());
let lookup = InternalKey::new(b"my_key".to_vec(), 75, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_some());
let (found_key, _) = result.unwrap();
assert_eq!(found_key.seq_num(), 50);
assert!(found_key.is_tombstone(), "Should return the tombstone marker");
}
#[test]
fn test_table_get_user_key_mismatch() {
let opts = Arc::new(Options::new().with_filter_policy(None));
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let key1 = InternalKey::new(b"apple".to_vec(), 100, InternalKeyKind::Set, 0);
writer.add(key1, b"apple_value").unwrap();
let key2 = InternalKey::new(b"cherry".to_vec(), 100, InternalKeyKind::Set, 0);
writer.add(key2, b"cherry_value").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap();
let lookup = InternalKey::new(b"banana".to_vec(), 200, InternalKeyKind::Set, 0);
let result = table.get(&lookup).unwrap();
assert!(result.is_none(), "Should return None when user_key doesn't match");
}
#[test]
fn test_reverse_iteration_unbounded_consistency() {
let data = vec![("key_000", "value"), ("key_001", "value"), ("key_002", "value")];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.seek_to_last().unwrap();
let mut results = Vec::new();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(results.len(), 3);
assert_eq!(results[0], "key_002"); assert_eq!(results[1], "key_001");
assert_eq!(results[2], "key_000"); }
#[test]
fn test_prev_iteration_across_partitions() {
let mut opts = Options::new();
opts.block_size = 32; opts.index_partition_size = 64; let opts = Arc::new(opts);
let data: Vec<(&str, &str)> = (0..20)
.map(|i| {
let key: &'static str = Box::leak(format!("key_{:03}", i).into_boxed_str());
let val: &'static str = Box::leak(format!("val_{:03}", i).into_boxed_str());
(key, val)
})
.collect();
let (src, size) = build_table(data.clone());
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let IndexType::Partitioned(ref index) = table.index_block;
assert!(index.blocks.len() > 1, "Test requires multiple partitions");
let mut iter = table.iter(None).unwrap();
iter.seek_to_last().unwrap();
let mut results = Vec::new();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(results.len(), 20);
assert_eq!(results[0], "key_019");
assert_eq!(results[19], "key_000");
}
#[test]
fn test_seek_to_last_valid_block() {
let data = vec![("aaa", "value1"), ("bbb", "value2"), ("ccc", "value3")];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.seek_to_last().unwrap();
assert!(iter.valid());
let key = iter.key();
assert_eq!(key.user_key(), b"ccc");
}
#[test]
fn test_range_at_exact_block_boundary() {
let mut opts = Options::new();
opts.block_size = 50; let opts = Arc::new(opts);
let data: Vec<(&str, &str)> = (0..10)
.map(|i| {
let key: &'static str = Box::leak(format!("key_{:03}", i).into_boxed_str());
let val: &'static str = Box::leak(format!("val_{:03}", i).into_boxed_str());
(key, val)
})
.collect();
let (src, size) = build_table(data);
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Included(b"key_003".as_slice()),
Bound::Included(b"key_006".as_slice()),
)))
.unwrap();
let collected = collect_all(&mut iter).unwrap();
let results: Vec<String> =
collected.iter().map(|(k, _)| String::from_utf8(k.user_key.clone()).unwrap()).collect();
assert_eq!(results.len(), 4);
assert_eq!(results[0], "key_003");
assert_eq!(results[3], "key_006");
}
#[test]
fn test_range_with_multiple_versions_at_boundary() {
let data = vec![
("key_001", "v1", 10),
("key_002", "v1", 100),
("key_002", "v2", 50),
("key_002", "v3", 10), ("key_003", "v1", 10),
("key_004", "v1", 10),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Included(b"key_002".as_slice()),
Bound::Included(b"key_003".as_slice()),
)))
.unwrap();
let collected = collect_all(&mut iter).unwrap();
let results: Vec<(String, u64)> = collected
.iter()
.map(|(k, _)| (String::from_utf8(k.user_key.clone()).unwrap(), k.seq_num()))
.collect();
assert_eq!(results.len(), 4, "Expected 4 items, got {:?}", results);
assert_eq!(results[0].0, "key_002");
assert_eq!(results[0].1, 100);
assert_eq!(results[1].0, "key_002");
assert_eq!(results[1].1, 50);
assert_eq!(results[2].0, "key_002");
assert_eq!(results[2].1, 10);
assert_eq!(results[3].0, "key_003");
}
#[test]
fn test_excluded_bound_skips_all_versions() {
let data = vec![
("key_001", "v1", 10),
("key_002", "v1", 100),
("key_002", "v2", 50),
("key_002", "v3", 10),
("key_003", "v1", 10),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Excluded(b"key_002".as_slice()),
Bound::Unbounded,
)))
.unwrap();
let collected = collect_all(&mut iter).unwrap();
let results: Vec<String> =
collected.iter().map(|(k, _)| String::from_utf8(k.user_key.clone()).unwrap()).collect();
assert_eq!(results.len(), 1, "Expected 1 item, got {:?}", results);
assert_eq!(results[0], "key_003");
assert!(!results.iter().any(|k| k == "key_002"), "key_002 should not appear in results");
}
#[test]
fn test_reverse_iteration_with_excluded_upper_bound() {
let data = vec![
("key_001", "v1", 10),
("key_002", "v1", 100),
("key_002", "v2", 50),
("key_003", "v1", 10),
("key_004", "v1", 10),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Unbounded,
Bound::Excluded(b"key_003".as_slice()),
)))
.unwrap();
let mut results = Vec::new();
iter.seek_last().unwrap();
while iter.valid() {
let key = iter.key();
results.push(String::from_utf8(key.user_key().to_vec()).unwrap());
if !iter.prev().unwrap() {
break;
}
}
assert!(!results.iter().any(|k| k == "key_003"), "key_003 should not appear");
assert!(!results.iter().any(|k| k == "key_004"), "key_004 should not appear");
assert_eq!(results[0], "key_002");
}
#[test]
fn test_empty_range_returns_nothing() {
let data = vec![("aaa", "value"), ("bbb", "value"), ("ddd", "value"), ("eee", "value")];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Included(b"ccc".as_slice()),
Bound::Included(b"ccc".as_slice()),
)))
.unwrap();
let results = collect_all(&mut iter).unwrap();
assert_eq!(results.len(), 0, "Range for non-existent key should be empty");
}
#[test]
fn test_range_completely_before_table() {
let data = vec![("mmm", "value"), ("nnn", "value"), ("ooo", "value")];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Included(b"aaa".as_slice()),
Bound::Included(b"bbb".as_slice()),
)))
.unwrap();
let results = collect_all(&mut iter).unwrap();
assert_eq!(results.len(), 0, "Range before all keys should be empty");
}
#[test]
fn test_range_completely_after_table() {
let data = vec![("aaa", "value"), ("bbb", "value"), ("ccc", "value")];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Included(b"xxx".as_slice()),
Bound::Included(b"zzz".as_slice()),
)))
.unwrap();
let results = collect_all(&mut iter).unwrap();
assert_eq!(results.len(), 0, "Range after all keys should be empty");
}
#[test]
fn test_reverse_iteration_empty_range() {
let data = vec![("aaa", "value"), ("bbb", "value"), ("ddd", "value")];
let (src, size) = build_table(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Included(b"ccc".as_slice()),
Bound::Included(b"ccc".as_slice()),
)))
.unwrap();
let result = iter.seek_last();
assert!(result.is_err() || !iter.valid(), "Empty range should be invalid on seek_last()");
}
#[test]
fn test_table_properties_persistence() {
let mut buffer = Vec::new();
let table_id = 42;
let opts = default_opts();
let mut writer = TableWriter::new(&mut buffer, table_id, Arc::clone(&opts), 0);
let mut entries = Vec::new();
let mut expected_deletions = 0u64;
let mut expected_tombstones = 0u64;
for i in 0..50 {
let key = format!("key_{:03}", i).into_bytes();
let value = format!("value_{:03}", i).into_bytes();
let seq = 1000 + i;
let kind = match i % 10 {
0..=6 => InternalKeyKind::Set,
7..=8 => {
expected_deletions += 1;
expected_tombstones += 1;
InternalKeyKind::Delete
}
9 => {
expected_deletions += 1;
expected_tombstones += 1; InternalKeyKind::RangeDelete
}
_ => unreachable!(),
};
let internal_key = InternalKey::new(key.clone(), seq, kind, 0);
let entry_value = match kind {
InternalKeyKind::Delete | InternalKeyKind::RangeDelete => vec![],
_ => value.clone(),
};
writer.add(internal_key, &entry_value).unwrap();
entries.push((key, value, seq, kind));
}
let size = writer.finish().unwrap();
let table = Table::new(table_id, opts, wrap_buffer(buffer), size as u64).unwrap();
let meta = &table.meta;
let props = &meta.properties;
assert_eq!(props.id, table_id, "Table ID should match");
assert_eq!(props.table_format, TableFormat::LSMV1, "Table format should be LSMV1");
assert_eq!(props.num_entries, 50, "Number of entries should be 50");
assert_eq!(props.item_count, 50, "Item count should be 50");
assert_eq!(props.key_count, 50, "Key count should be 50");
assert_eq!(props.num_deletions, expected_deletions, "Number of deletions should match");
assert_eq!(props.tombstone_count, expected_tombstones, "Tombstone count should match");
assert!(props.num_data_blocks > 0, "Should have at least one data block");
assert!(props.data_size > 0, "Data size should be greater than 0");
assert!(props.index_size > 0, "Index size should be tracked");
assert!(props.index_partitions > 0, "Should have at least one index partition");
assert!(props.top_level_index_size > 0, "Top-level index size should be tracked");
assert!(props.filter_size > 0, "Filter size should be tracked");
assert!(props.raw_key_size > 0, "Raw key size should be tracked");
assert!(props.raw_value_size > 0, "Raw value size should be tracked");
assert_eq!(
props.raw_key_size + props.raw_value_size,
props.data_size,
"Raw sizes should sum to data_size"
);
assert_eq!(props.seqnos.0, 1000, "Smallest sequence number should be 1000");
assert_eq!(props.seqnos.1, 1049, "Largest sequence number should be 1049");
assert_eq!(meta.smallest_seq_num, Some(1000), "Metadata smallest seq num should match");
assert_eq!(meta.largest_seq_num, Some(1049), "Metadata largest seq num should match");
assert_eq!(props.compression, crate::CompressionType::None, "Compression should be None");
assert!(props.block_size > 0, "Block size should be tracked");
assert!(props.block_count > 0, "Block count should be tracked");
assert_eq!(props.oldest_key_time, Some(0), "Oldest key time should be 0");
assert_eq!(props.newest_key_time, Some(0), "Newest key time should be 0");
assert_eq!(props.num_range_deletions, 5, "Should have 5 range deletions");
assert!(props.created_at > 0, "Created at timestamp should be set");
assert!(meta.smallest_point.is_some(), "Should have smallest point key");
assert!(meta.largest_point.is_some(), "Should have largest point key");
if let Some(smallest) = &meta.smallest_point {
assert_eq!(&smallest.user_key, b"key_000", "Smallest key should be key_000");
assert_eq!(smallest.seq_num(), 1000, "Smallest seq num should be 1000");
}
if let Some(largest) = &meta.largest_point {
assert_eq!(&largest.user_key, b"key_049", "Largest key should be key_049");
assert_eq!(largest.seq_num(), 1049, "Largest seq num should be 1049");
}
assert_eq!(meta.has_point_keys, Some(true), "Should have point keys");
}
#[test]
fn test_table_get_all_keys() {
let mut opts = default_opts_mut();
opts.block_size = 64; opts.index_partition_size = 200;
let opts = Arc::new(opts);
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
for i in 0..100 {
let key = format!("key_{i:03}");
let value = format!("value_{i:03}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
for i in 0..100 {
let key = format!("key_{i:03}");
let expected_value = format!("value_{i:03}");
let seek_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
let result = table.get(&seek_key).unwrap();
assert!(result.is_some(), "Key '{key}' not found");
if let Some((found_key, found_value)) = result {
assert_eq!(
std::str::from_utf8(&found_key.user_key).unwrap(),
key,
"Key mismatch for {key}"
);
assert_eq!(
std::str::from_utf8(found_value.as_ref()).unwrap(),
expected_value,
"Value mismatch for {key}"
);
}
}
}
#[test]
fn test_table_get_nonexistent_keys() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
for i in 0..10 {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let nonexistent_keys = vec!["key_10", "key_99", "aaa", "zzz"];
for key_str in &nonexistent_keys {
let seek_key = InternalKey::new(key_str.as_bytes().to_vec(), 100, InternalKeyKind::Set, 0);
let result = table.get(&seek_key).unwrap();
if result.is_some() {
let (found_key, _) = result.unwrap();
let found_str = std::str::from_utf8(&found_key.user_key).unwrap();
assert!(found_str.starts_with("key_"), "Found key {found_str} should be valid");
}
}
}
#[test]
fn test_table_get_with_compression() {
let compression_types =
vec![crate::CompressionType::None, crate::CompressionType::SnappyCompression];
for compression in compression_types {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
for i in 0..20 {
let key = format!("key_{i:02}");
let value = format!("value_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
for i in 0..20 {
let key = format!("key_{i:02}");
let expected_value = format!("value_{i:02}");
let seek_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
let result = table.get(&seek_key).unwrap();
assert!(result.is_some(), "Should find key {key} with compression {compression:?}");
if let Some((found_key, found_value)) = result {
assert_eq!(
std::str::from_utf8(&found_key.user_key).unwrap(),
key,
"Key mismatch with compression {compression:?}"
);
assert_eq!(
std::str::from_utf8(found_value.as_ref()).unwrap(),
expected_value,
"Value mismatch with compression {compression:?}"
);
}
}
}
}
#[test]
fn test_table_iterator_full_scan() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let test_data: Vec<(String, String)> =
(0..50).map(|i| (format!("key_{i:03}"), format!("value_{i:03}"))).collect();
for (i, (key, value)) in test_data.iter().enumerate() {
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.seek_to_first().unwrap();
let mut collected = Vec::new();
while iter.valid() {
let key = iter.key();
let value = iter.value_encoded().unwrap();
collected.push((
std::str::from_utf8(key.user_key()).unwrap().to_string(),
std::str::from_utf8(value).unwrap().to_string(),
));
match iter.next() {
Ok(false) => break,
Ok(true) => {}
Err(e) => panic!("Iterator error: {e}"),
}
}
assert_eq!(collected.len(), 50, "Should collect all 50 entries");
for (i, (key, value)) in collected.iter().enumerate() {
assert_eq!(*key, format!("key_{i:03}"), "Key order mismatch");
assert_eq!(*value, format!("value_{i:03}"), "Value mismatch");
}
}
#[test]
fn test_table_iterator_reverse_scan() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let test_data: Vec<(String, String)> =
(0..50).map(|i| (format!("key_{i:03}"), format!("value_{i:03}"))).collect();
for (i, (key, value)) in test_data.iter().enumerate() {
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.seek_to_last().unwrap();
let mut collected = Vec::new();
while iter.valid() {
let key = iter.key();
let value = iter.value_encoded().unwrap();
collected.push((
std::str::from_utf8(key.user_key()).unwrap().to_string(),
std::str::from_utf8(value).unwrap().to_string(),
));
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(collected.len(), 50, "Should collect all 50 entries");
for (i, (key, value)) in collected.iter().enumerate() {
let expected_idx = 49 - i;
assert_eq!(*key, format!("key_{expected_idx:03}"), "Reverse key order mismatch");
assert_eq!(*value, format!("value_{expected_idx:03}"), "Reverse value mismatch");
}
}
#[test]
fn test_table_iterator_seek_and_scan() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
for i in 0..30 {
let key = format!("key_{i:03}");
let value = format!("value_{i:03}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
let seek_points = vec!["key_005", "key_010", "key_015", "key_020", "key_025"];
for seek_key_str in &seek_points {
let seek_key =
InternalKey::new(seek_key_str.as_bytes().to_vec(), 100, InternalKeyKind::Set, 0);
iter.seek(&seek_key.encode()).unwrap();
if iter.valid() {
let found_key_bytes: &[u8] = iter.key().user_key();
let seek_key_bytes = seek_key_str.as_bytes();
assert!(
found_key_bytes >= seek_key_bytes,
"Found key should be >= seek key {seek_key_str}"
);
}
let mut count = 0;
while iter.valid() && count < 5 {
count += 1;
match iter.next() {
Ok(false) => break,
Ok(true) => {}
Err(e) => panic!("Iterator error: {e}"),
}
}
}
iter.seek_to_last().unwrap();
let last_key_bytes = iter.key().user_key();
assert_eq!(std::str::from_utf8(last_key_bytes).unwrap(), "key_029", "Should find last key");
for _ in 0..5 {
if !iter.prev().unwrap() {
break;
}
}
}
#[test]
fn test_table_iterator_across_partitions() {
let mut opts = default_opts_mut();
opts.index_partition_size = 150; opts.block_size = 500;
let opts = Arc::new(opts);
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
for i in 0..100 {
let key = format!("key_{i:03}");
let value = format!("value_{i:03}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, value.as_bytes()).unwrap();
}
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let crate::sstable::table::IndexType::Partitioned(ref partitioned_index) = table.index_block;
assert!(partitioned_index.blocks.len() >= 2, "Should have multiple partitions");
let mut iter = table.iter(None).unwrap();
iter.seek_to_first().unwrap();
let mut count = 0;
while iter.valid() {
count += 1;
match iter.next() {
Ok(false) => break,
Ok(true) => {}
Err(e) => panic!("Iterator error: {e}"),
}
}
assert_eq!(count, 100, "Should iterate all 100 keys across partitions");
iter.seek_to_last().unwrap();
let mut count_backward = 0;
while iter.valid() {
count_backward += 1;
if !iter.prev().unwrap() {
break;
}
}
assert_eq!(count_backward, 100, "Should iterate all 100 keys backwards across partitions");
}
#[test]
fn test_empty_table_operations() {
let opts = default_opts();
let mut buffer = Vec::new();
let writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let seek_key = InternalKey::new(b"any_key".to_vec(), 1, InternalKeyKind::Set, 0);
let result = table.get(&seek_key);
assert!(result.is_err(), "Get on empty table should return error");
let mut iter = table.iter(None).unwrap();
let result = iter.seek_to_first();
assert!(result.is_err(), "Get on empty table should return error");
}
#[test]
fn test_single_entry_table() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let internal_key = InternalKey::new(b"single_key".to_vec(), 1, InternalKeyKind::Set, 0);
writer.add(internal_key, b"single_value").unwrap();
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
let seek_key = InternalKey::new(b"single_key".to_vec(), 1, InternalKeyKind::Set, 0);
let result = table.get(&seek_key).unwrap();
assert!(result.is_some(), "Should find the single key");
if let Some((found_key, found_value)) = result {
assert_eq!(found_key.user_key, b"single_key");
let value_bytes: &[u8] = found_value.as_ref();
assert_eq!(value_bytes, b"single_value");
}
let mut iter = table.iter(None).unwrap();
iter.seek_to_first().unwrap();
assert!(iter.valid(), "Iterator should be valid");
assert_eq!(iter.key().user_key(), b"single_key");
let iter_value = iter.value_encoded().unwrap();
let iter_value_bytes: &[u8] = iter_value;
assert_eq!(iter_value_bytes, b"single_value");
match iter.next() {
Ok(false) => {}
Ok(true) => {}
Err(e) => panic!("Iterator error: {e}"),
}
assert!(!iter.valid(), "Iterator should be invalid after next()");
}
#[test]
fn test_large_values() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 0, Arc::clone(&opts), 0);
let large_value = vec![b'x'; 10000]; for i in 0..10 {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, &large_value).unwrap();
}
let size = writer.finish().unwrap();
let table = Arc::new(Table::new(0, opts, wrap_buffer(buffer), size as u64).unwrap());
for i in 0..10 {
let key = format!("key_{i:02}");
let seek_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
let result = table.get(&seek_key).unwrap();
assert!(result.is_some(), "Should find key {key}");
if let Some((found_key, found_value)) = result {
assert_eq!(found_key.user_key, key.as_bytes());
let found_bytes: &[u8] = found_value.as_ref();
assert_eq!(found_bytes, &large_value[..], "Large value should match");
assert_eq!(found_bytes.len(), 10000, "Value size should be 10000");
}
}
}
#[test]
fn test_backward_iter_multiple_versions_same_user_key() {
let data = vec![
("key_000", "value_v2", 200),
("key_000", "value_v1", 100),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table.iter(None).unwrap();
iter.seek_to_last().unwrap();
let mut results: Vec<(String, u64)> = Vec::new();
while iter.valid() {
let key = iter.key();
let user_key = String::from_utf8(key.user_key().to_vec()).unwrap();
results.push((user_key, key.seq_num()));
iter.prev().unwrap();
}
assert_eq!(
results.len(),
2,
"Backward iteration should return both MVCC versions. Got: {:?}",
results
);
assert_eq!(results[0].1, 100, "First backward result should be seq=100");
assert_eq!(results[1].1, 200, "Second backward result should be seq=200");
}
#[test]
fn test_backward_iter_inclusive_upper_bound_mvcc() {
let data = vec![
("key_001", "v1", 300),
("key_001", "v2", 200),
("key_001", "v3", 100),
("key_002", "v1", 50),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Unbounded,
Bound::Included(b"key_001".as_slice()),
)))
.unwrap();
iter.seek_to_last().unwrap();
let mut results: Vec<(String, u64)> = Vec::new();
while iter.valid() {
let key = iter.key();
let user_key = String::from_utf8(key.user_key().to_vec()).unwrap();
results.push((user_key, key.seq_num()));
iter.prev().unwrap();
}
assert_eq!(results.len(), 3, "Should return all 3 versions of key_001. Got: {:?}", results);
for (user_key, _) in &results {
assert_eq!(user_key, "key_001");
}
}
#[test]
fn test_backward_iter_exclusive_upper_bound_mvcc() {
let data = vec![
("key_001", "v1", 300),
("key_001", "v2", 200),
("key_002", "v1", 150),
("key_002", "v2", 100),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter = table
.iter(Some(user_range_to_internal_range(
Bound::Unbounded,
Bound::Excluded(b"key_002".as_slice()),
)))
.unwrap();
iter.seek_to_last().unwrap();
let mut results: Vec<(String, u64)> = Vec::new();
while iter.valid() {
let key = iter.key();
let user_key = String::from_utf8(key.user_key().to_vec()).unwrap();
results.push((user_key, key.seq_num()));
iter.prev().unwrap();
}
assert_eq!(results.len(), 2, "Should return only key_001 versions. Got: {:?}", results);
for (user_key, _) in &results {
assert_eq!(user_key, "key_001", "Should not contain key_002");
}
}
#[test]
fn test_forward_backward_consistency_mvcc() {
let data = vec![
("key_001", "v1", 300),
("key_001", "v2", 200),
("key_002", "v1", 150),
("key_003", "v1", 100),
];
let (src, size) = build_table_with_seq_num(data);
let opts = default_opts();
let table = Arc::new(Table::new(1, opts, wrap_buffer(src), size as u64).unwrap());
let mut iter_fwd = table.iter(None).unwrap();
iter_fwd.seek_to_first().unwrap();
let mut forward_results: Vec<(Vec<u8>, u64)> = vec![];
while iter_fwd.valid() {
let key = iter_fwd.key();
forward_results.push((key.user_key().to_vec(), key.seq_num()));
iter_fwd.next().unwrap();
}
let mut iter_bwd = table.iter(None).unwrap();
iter_bwd.seek_to_last().unwrap();
let mut backward_results: Vec<(Vec<u8>, u64)> = Vec::new();
while iter_bwd.valid() {
let key = iter_bwd.key();
backward_results.push((key.user_key().to_vec(), key.seq_num()));
iter_bwd.prev().unwrap();
}
backward_results.reverse();
assert_eq!(
forward_results.len(),
backward_results.len(),
"Forward and backward should return same count"
);
assert_eq!(forward_results, backward_results, "Forward and reversed backward should match");
}
#[test]
fn test_seq_num_tracking_with_zero_first() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
let entries = vec![
("aaa", 0u64), ("bbb", 100u64), ("ccc", 50u64), ];
for (key, seq) in &entries {
let internal_key = InternalKey::new(key.as_bytes().to_vec(), *seq, InternalKeyKind::Set, 0);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(
table.meta.smallest_seq_num,
Some(0),
"smallest_seq_num should be 0 (first entry's seq_num)"
);
assert_eq!(table.meta.largest_seq_num, Some(100), "largest_seq_num should be 100");
assert_eq!(table.meta.properties.seqnos, (0, 100), "seqnos tuple should match");
}
#[test]
fn test_seq_num_tracking_various_orders() {
{
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for (i, seq) in [1u64, 2, 3].iter().enumerate() {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), *seq, InternalKeyKind::Set, 0);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.smallest_seq_num, Some(1), "Ascending: smallest=1");
assert_eq!(table.meta.largest_seq_num, Some(3), "Ascending: largest=3");
}
{
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for (i, seq) in [3u64, 2, 1].iter().enumerate() {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), *seq, InternalKeyKind::Set, 0);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.smallest_seq_num, Some(1), "Descending: smallest=1");
assert_eq!(table.meta.largest_seq_num, Some(3), "Descending: largest=3");
}
{
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for (i, seq) in [5u64, 1, 10, 3].iter().enumerate() {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), *seq, InternalKeyKind::Set, 0);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.smallest_seq_num, Some(1), "Random: smallest=1");
assert_eq!(table.meta.largest_seq_num, Some(10), "Random: largest=10");
}
}
#[test]
fn test_timestamp_tracking_with_zero_first() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
let entries = vec![
("aaa", 0u64), ("bbb", 1000u64), ("ccc", 500u64), ];
for (key, ts) in &entries {
let internal_key = InternalKey::new(key.as_bytes().to_vec(), 1, InternalKeyKind::Set, *ts);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(
table.meta.properties.oldest_key_time,
Some(0),
"oldest_key_time should be 0 (first entry's timestamp)"
);
assert_eq!(table.meta.properties.newest_key_time, Some(1000), "newest_key_time should be 1000");
}
#[test]
fn test_timestamp_tracking_various_orders() {
{
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for (i, ts) in [100u64, 200, 300].iter().enumerate() {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), 1, InternalKeyKind::Set, *ts);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.properties.oldest_key_time, Some(100));
assert_eq!(table.meta.properties.newest_key_time, Some(300));
}
{
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for (i, ts) in [300u64, 200, 100].iter().enumerate() {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), 1, InternalKeyKind::Set, *ts);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.properties.oldest_key_time, Some(100));
assert_eq!(table.meta.properties.newest_key_time, Some(300));
}
{
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for (i, ts) in [500u64, 0, 1000, 250].iter().enumerate() {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), 1, InternalKeyKind::Set, *ts);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.properties.oldest_key_time, Some(0));
assert_eq!(table.meta.properties.newest_key_time, Some(1000));
}
}
#[test]
fn test_single_entry_metadata() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
let internal_key = InternalKey::new(b"only_key".to_vec(), 42, InternalKeyKind::Set, 12345);
writer.add(internal_key, b"only_value").unwrap();
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.smallest_seq_num, Some(42));
assert_eq!(table.meta.largest_seq_num, Some(42));
assert_eq!(table.meta.properties.seqnos, (42, 42));
assert_eq!(table.meta.properties.oldest_key_time, Some(12345));
assert_eq!(table.meta.properties.newest_key_time, Some(12345));
}
#[test]
fn test_metadata_roundtrip_with_edge_values() {
use crate::sstable::meta::TableMetadata;
{
let mut meta = TableMetadata::new();
meta.update_seq_num(0);
meta.update_seq_num(100);
let encoded = meta.encode();
let decoded = TableMetadata::decode(&encoded).unwrap();
assert_eq!(decoded.smallest_seq_num, Some(0), "Roundtrip should preserve seq_num=0");
assert_eq!(decoded.largest_seq_num, Some(100));
}
{
let mut meta = TableMetadata::new();
meta.update_seq_num(1);
meta.update_seq_num(u64::MAX - 1);
let encoded = meta.encode();
let decoded = TableMetadata::decode(&encoded).unwrap();
assert_eq!(decoded.smallest_seq_num, Some(1));
assert_eq!(decoded.largest_seq_num, Some(u64::MAX - 1));
}
}
#[test]
fn test_all_zero_seq_nums() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for i in 0..5 {
let key = format!("key_{i:02}");
let internal_key = InternalKey::new(key.as_bytes().to_vec(), 0, InternalKeyKind::Set, 0);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.smallest_seq_num, Some(0));
assert_eq!(table.meta.largest_seq_num, Some(0));
assert_eq!(table.meta.properties.seqnos, (0, 0));
}
#[test]
fn test_all_zero_timestamps() {
let opts = default_opts();
let mut buffer = Vec::new();
let mut writer = TableWriter::new(&mut buffer, 1, Arc::clone(&opts), 0);
for i in 0..5 {
let key = format!("key_{i:02}");
let internal_key =
InternalKey::new(key.as_bytes().to_vec(), (i + 1) as u64, InternalKeyKind::Set, 0);
writer.add(internal_key, b"value").unwrap();
}
let size = writer.finish().unwrap();
let table = Table::new(1, opts, wrap_buffer(buffer), size as u64).unwrap();
assert_eq!(table.meta.properties.oldest_key_time, Some(0));
assert_eq!(table.meta.properties.newest_key_time, Some(0));
}