diff options
Diffstat (limited to 'autere_db/benches')
| -rw-r--r-- | autere_db/benches/benchmark.rs | 181 | ||||
| -rw-r--r-- | autere_db/benches/utils.rs | 122 |
2 files changed, 303 insertions, 0 deletions
diff --git a/autere_db/benches/benchmark.rs b/autere_db/benches/benchmark.rs new file mode 100644 index 0000000..648c9f6 --- /dev/null +++ b/autere_db/benches/benchmark.rs @@ -0,0 +1,181 @@ +mod utils; + +use std::collections::HashSet; + +use autere_db::*; +use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; +use tempfile; +use utils::*; + +pub fn upsert_compacted(c: &mut Criterion) { + let mut group = c.benchmark_group("upsert_compacted"); + let data_dir_obj = tempfile::tempdir().expect("Failed to get tmpdir"); + let data_dir = data_dir_obj + .path() + .to_str() + .expect("Failed to convert tmpdir path to str"); + let mut db = DB::configure() + .fields(Inst::fields()) + .primary_key(Inst::primary_key()) + .secondary_keys(Inst::secondary_keys()) + .data_dir(data_dir) + .initialize() + .expect("Failed to initialize DB"); + + let mut insts = Vec::new(); + for size in [100_000, 1_000_000, 10_000_000] { + println!("Prefilling DB to {} entries", size); + prefill_db(&mut db, &mut insts, size, true).expect("Failed to prefill DB"); + + group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &_size| { + b.iter(|| { + let inst = random_inst(0, size as i64 + 1); + let result = db.upsert(black_box(inst)).unwrap(); + assert!(result == ()); + }); + }); + } +} + +pub fn delete_existing_compacted(c: &mut Criterion) { + let mut group = c.benchmark_group("delete_existing_compacted"); + let data_dir_obj = tempfile::tempdir().expect("Failed to get tmpdir"); + let data_dir = data_dir_obj + .path() + .to_str() + .expect("Failed to convert tmpdir path to str"); + let mut db = DB::configure() + .fields(Inst::fields()) + .primary_key(Inst::primary_key()) + .secondary_keys(Inst::secondary_keys()) + .data_dir(data_dir) + .initialize() + .expect("Failed to initialize DB"); + + let mut insts = Vec::new(); + for size in [100_000, 1_000_000, 10_000_000] { + println!("Prefilling DB to {} entries", size); + prefill_db(&mut db, &mut insts, size, true).expect("Failed to prefill DB"); + + let pk_set: HashSet<i64> = insts.iter().map(|inst| inst.id).collect(); + let mut pk_set_it = pk_set.into_iter(); + + group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &_size| { + b.iter(|| { + let result = db + .delete(black_box(&Value::Int(pk_set_it.next().unwrap()))) + .unwrap(); + assert!(result.is_some()); + }); + }); + } +} + +pub fn upsert_write_durability(c: &mut Criterion) { + let mut group = c.benchmark_group("upsert_write_durability"); + + for mode in [WriteDurability::Flush, WriteDurability::FlushSync] { + group.bench_with_input(BenchmarkId::from_parameter(&mode), &mode, |b, _mode| { + let data_dir_obj = tempfile::tempdir().expect("Failed to get tmpdir"); + let data_dir = data_dir_obj + .path() + .to_str() + .expect("Failed to convert tmpdir path to str"); + let mut db = DB::configure() + .fields(Inst::fields()) + .primary_key(Inst::primary_key()) + .secondary_keys(Inst::secondary_keys()) + .data_dir(data_dir) + .write_durability(mode.clone()) + .initialize() + .expect("Failed to initialize DB"); + + b.iter(|| { + let inst = random_inst(0, 1000); + let result = db.upsert(black_box(inst)).unwrap(); + assert!(result == ()); + }); + }); + } +} + +pub fn get_existing_compacted(c: &mut Criterion) { + let mut group = c.benchmark_group("get_existing_compacted"); + + let data_dir_obj = tempfile::tempdir().expect("Failed to get tmpdir"); + let data_dir = data_dir_obj + .path() + .to_str() + .expect("Failed to convert tmpdir path to str"); + let mut db = DB::configure() + .fields(Inst::fields()) + .primary_key(Inst::primary_key()) + .secondary_keys(Inst::secondary_keys()) + .data_dir(data_dir) + .initialize() + .expect("Failed to initialize DB"); + + let mut insts = Vec::new(); + let mut inst_index = 0; + for size in [100_000, 1_000_000, 10_000_000] { + println!("Prefilling DB to {} entries", size); + prefill_db(&mut db, &mut insts, size, true).expect("Failed to prefill DB"); + + group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &_size| { + b.iter(|| { + let id = insts[inst_index].id; + let result = db.get(black_box(&Value::Int(id))).unwrap(); + assert!(result.is_some()); + inst_index = (inst_index + 1) % insts.len(); + }); + }); + } +} + +pub fn find_by_existing_compacted(c: &mut Criterion) { + let mut group = c.benchmark_group("find_by_existing_compacted"); + + let data_dir_path = tempfile::tempdir() + .expect("Failed to get tmpdir") + .into_path(); + let data_dir = data_dir_path + .to_str() + .expect("Failed to convert tmpdir path to str"); + let mut db = DB::configure() + .fields(Inst::fields()) + .primary_key(Inst::primary_key()) + .secondary_keys(Inst::secondary_keys()) + .data_dir(data_dir) + .initialize() + .expect("Failed to initialize DB"); + + let mut insts = Vec::new(); + let mut inst_index = 0; + for size in [100_000, 1_000_000, 10_000_000] { + println!("Prefilling DB to {} entries", size); + prefill_db(&mut db, &mut insts, size, true).expect("Failed to prefill DB"); + println!("DB prefilling done, insts.len = {}", insts.len()); + + group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &_size| { + b.iter(|| { + let name = insts[inst_index].name.clone(); + let result = db + .find_by(black_box(&Field::Name), black_box(&Value::String(name))) + .unwrap(); + assert!(result.len() > 0); + inst_index = (inst_index + 1) % insts.len(); + }); + }); + } +} + +// Register the benchmark group +criterion_group!( + benches, + upsert_compacted, + delete_existing_compacted, + upsert_write_durability, + get_existing_compacted, + find_by_existing_compacted, +); +criterion_main!(benches); diff --git a/autere_db/benches/utils.rs b/autere_db/benches/utils.rs new file mode 100644 index 0000000..9b0a0ea --- /dev/null +++ b/autere_db/benches/utils.rs @@ -0,0 +1,122 @@ +use autere_db::*; +use rand::distributions::Alphanumeric; +use rand::Rng; +use std::fmt::Debug; + +#[derive(Eq, PartialEq, Clone, Debug)] +pub enum Field { + Id, + Name, + Data, +} + +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct Inst { + pub id: i64, + pub name: String, + pub data: Vec<u8>, +} + +impl AsRef<str> for Field { + fn as_ref(&self) -> &str { + match self { + Field::Id => "id", + Field::Name => "name", + Field::Data => "data", + } + } +} + +impl Into<String> for Field { + fn into(self) -> String { + self.as_ref().to_string() + } +} + +impl From<Inst> for Record { + fn from(inst: Inst) -> Self { + vec![ + Value::Int(inst.id), + Value::String(inst.name), + Value::Bytes(inst.data), + ] + .into() + } +} + +impl From<Record> for Inst { + fn from(record: Record) -> Self { + let mut it = record.into_iter(); + Inst { + id: match it.next().unwrap() { + Value::Int(id) => id, + _ => panic!("Expected Int"), + }, + name: match it.next().unwrap() { + Value::String(name) => name, + _ => panic!("Expected String"), + }, + data: match it.next().unwrap() { + Value::Bytes(data) => data, + _ => panic!("Expected Bytes"), + }, + } + } +} + +impl Inst { + pub fn fields() -> Vec<Field> { + vec![Field::Id, Field::Name, Field::Data] + } + pub fn primary_key() -> Field { + Field::Id + } + pub fn secondary_keys() -> Vec<Field> { + vec![Field::Name] + } +} + +// Function to generate a random integer +pub fn random_int(from: i64, to: i64) -> i64 { + let mut rng = rand::thread_rng(); + rng.gen_range(from..to) +} + +// Function to generate a random string +pub fn random_string(len: usize) -> String { + let mut rng = rand::thread_rng(); + (0..len).map(|_| rng.sample(Alphanumeric) as char).collect() +} + +// Function to generate random bytes +pub fn random_bytes(len: usize) -> Vec<u8> { + let mut rng = rand::thread_rng(); + (0..len).map(|_| rng.gen()).collect() +} + +// Function to generate a random Inst +pub fn random_inst(from_id: i64, to_id: i64) -> Inst { + Inst { + id: random_int(from_id, to_id), // Random int value between 0..1000 + name: random_string(5), // Random string of length 5 + data: random_bytes(10), // Random bytes of length 10 + } +} + +pub fn prefill_db( + db: &mut DB, + insts: &mut Vec<Inst>, + n_records: usize, + compact: bool, +) -> DBResult<()> { + for i in 0..(n_records - insts.len()) { + let inst = random_inst(0, n_records as i64); + insts.push(inst.clone()); + db.upsert(inst)?; + if i % 1000 == 0 && compact { + db.do_maintenance_tasks()?; + } + } + + Ok(()) +} |
