use std::path::Path;
use std::sync::Arc;
use bytes::Bytes;
use crate::fs::{FaultFs, Fs};
use crate::{batch, key, log, manifest, sst};
fn pieces(mut data: &[u8]) -> Vec<&[u8]> {
let mut out = Vec::new();
while let Some((&len, rest)) = data.split_first() {
let len = (len as usize).min(rest.len());
out.push(&rest[..len]);
data = &rest[len..];
}
out
}
pub fn log_records(data: &[u8]) {
let Some((no, body)) = data.split_first_chunk::<4>() else {
return;
};
let log = log::read_records(body, u32::from_le_bytes(*no));
assert!(log.discarded <= body.len());
for record in log.records {
assert!(record.len() <= body.len());
}
}
pub fn write_batch(data: &[u8]) {
if let Ok(batch) = batch::decode(data) {
let mem = crate::memtable::Memtable::new(1);
for (seq, op) in (batch.first_seq..).zip(&batch.ops) {
match *op {
batch::BatchOp::Put { cf, key, value } => {
mem.insert_entry(cf, key, seq, key::Kind::Put, value)
}
batch::BatchOp::Delete { cf, key } => {
mem.insert_entry(cf, key, seq, key::Kind::Delete, b"")
}
batch::BatchOp::DeleteRange { cf, start, end } => {
mem.insert_range_tombstone(cf, start, end, seq)
}
}
}
let _ = mem.get(0, b"k", u64::MAX);
}
}
pub fn version_edits(data: &[u8]) {
let snapshot = manifest::encode_edits(&manifest::ManifestState::new_database().snapshot());
let records = std::iter::once(&snapshot[..]).chain(pieces(data));
if let Ok(state) = manifest::replay(records) {
let _ = state.snapshot();
}
}
pub fn block(data: &[u8]) {
let Some((target_len, rest)) = data.split_first() else {
return;
};
let (target, body) = rest.split_at((*target_len as usize).min(rest.len()));
let Ok(block) = sst::block::Block::new(Bytes::copy_from_slice(body)) else {
return;
};
let mut it = block.iter();
it.seek_to_first();
let mut n = 0;
while it.valid() && n < 10_000 {
let _ = (it.key(), it.value());
it.next();
n += 1;
}
it.seek_to_last();
let mut n = 0;
while it.valid() && n < 10_000 {
it.prev();
n += 1;
}
it.seek(target);
it.seek_for_prev(target);
let _ = it.status();
let mut fresh = block.iter();
fresh.seek(target);
let mut key = Vec::new();
match block.seek_entry(target, &mut key) {
Ok(Some(entry)) => {
assert!(
fresh.valid(),
"seek_entry found an entry the iterator did not"
);
assert_eq!(key, fresh.key());
let (start, end) = entry.value;
assert_eq!(&block.bytes()[start..end], &fresh.value()[..]);
}
Ok(None) => assert!(!fresh.valid() && fresh.status().is_ok()),
Err(_) => assert!(fresh.status().is_err()),
}
}
pub fn bloom(data: &[u8]) {
let Some((hash, filter)) = data.split_first_chunk::<8>() else {
return;
};
let _ = sst::bloom::may_contain(filter, u64::from_le_bytes(*hash));
let _ = sst::bloom::may_contain(filter, sst::bloom::hash(filter));
}
pub fn table(data: &[u8]) {
let fs = FaultFs::new();
let path = Path::new("/t/000001.sst");
let file = fs.create(path).expect("in memory");
file.append(data).expect("in memory");
let Ok(reader) = sst::TableReader::open(fs.open_random(path).expect("in memory")) else {
return;
};
let reader = Arc::new(reader);
use crate::iter::InternalIterator;
let mut it = sst::TableIter::new(reader.clone());
it.seek_to_last();
let mut n = 0;
while it.valid() && n < 10_000 {
it.prev();
n += 1;
}
it.seek_ge(&key::first_of(0, b""));
let mut n = 0;
while it.valid() && n < 10_000 {
if let Some(p) = key::parse(it.key()) {
let _ = reader.get(p.cf, p.user_key, p.seq);
}
it.next();
n += 1;
}
let _ = it.status();
let _ = reader.get(0, b"k", u64::MAX);
let _ = reader.approximate_offset_of(&key::first_of(1, b"k"));
}
pub fn open(data: &[u8]) {
let fs = Arc::new(FaultFs::new());
let dir = Path::new("/db");
fs.create_dir_all(dir).expect("in memory");
let (manifest_no, wal_no) = (1u64, 2u64);
let mut edits = manifest::ManifestState::new_database().snapshot();
edits.push(manifest::Edit::LogNumber(wal_no));
let mut manifest_log = Vec::new();
log::encode_record(&mut manifest_log, 1, &manifest::encode_edits(&edits));
let mut wal_log = Vec::new();
log::encode_header(&mut wal_log, 2, 0);
for piece in pieces(data) {
match piece.split_first() {
Some((tag, payload)) if tag & 1 == 0 => {
log::encode_record(&mut manifest_log, 1, payload)
}
Some((_, payload)) => log::encode_record(&mut wal_log, 2, payload),
None => {}
}
}
let write = |name: String, bytes: &[u8]| {
let file = fs.create(&dir.join(name)).expect("in memory");
file.append(bytes).expect("in memory");
};
write(manifest::manifest_name(manifest_no), &manifest_log);
write(crate::db::wal_name(wal_no), &wal_log);
write(
"CURRENT".into(),
format!("{}\n", manifest::manifest_name(manifest_no)).as_bytes(),
);
let opts = crate::Options {
fs: fs.clone(),
create_if_missing: false,
..crate::Options::default()
};
let Ok(db) = crate::Db::open(dir, opts) else {
return;
};
let cf = db.default_cf();
if let Ok(it) = db.iterator(&cf, crate::IteratorMode::Start) {
for item in it.take(10_000) {
if item.is_err() {
break;
}
}
}
let _ = db.get(&cf, b"k");
let mut batch = crate::WriteBatch::new();
batch.put(&cf, b"k", b"v");
let _ = db.write(batch);
let _ = db.flush();
}