aboutsummaryrefslogtreecommitdiffstats
path: root/log_db/benches
diff options
context:
space:
mode:
Diffstat (limited to 'log_db/benches')
-rw-r--r--log_db/benches/benchmark.rs222
-rw-r--r--log_db/benches/utils.rs46
2 files changed, 268 insertions, 0 deletions
diff --git a/log_db/benches/benchmark.rs b/log_db/benches/benchmark.rs
new file mode 100644
index 0000000..384c9b7
--- /dev/null
+++ b/log_db/benches/benchmark.rs
@@ -0,0 +1,222 @@
+mod utils;
+
+use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
+use log_db::*;
+use std::fs::OpenOptions;
+use std::path::Path;
+use tempfile;
+use utils::*;
+
+#[derive(Eq, PartialEq, Clone, Debug)]
+enum Field {
+ Id,
+ Name,
+ Data,
+}
+
+pub fn upsert_various_initial_sizes(c: &mut Criterion) {
+ let mut group = c.benchmark_group("upsert_various_initial_sizes");
+
+ for size in [100, 1000, 10000, 100_000, 1_000_000, 10_000_000] {
+ 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()
+ .data_dir(&data_dir)
+ .fields(&vec![
+ (Field::Id, RecordField::int()),
+ (Field::Name, RecordField::string()),
+ (Field::Data, RecordField::bytes()),
+ ])
+ .primary_key(Field::Id)
+ .initialize()
+ .expect("Failed to initialize DB");
+ prefill_db(&mut db, size).expect("Failed to prefill DB");
+
+ group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &_size| {
+ b.iter(|| {
+ let record = random_record(0, size as i64 + 1);
+ let _ = db.upsert(black_box(&record));
+ });
+ });
+ }
+}
+
+pub fn upsert_write_durability(c: &mut Criterion) {
+ let mut group = c.benchmark_group("upsert_write_durability");
+
+ for mode in [
+ WriteDurability::Async,
+ 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()
+ .data_dir(&data_dir)
+ .fields(&vec![
+ (Field::Id, RecordField::int()),
+ (Field::Name, RecordField::string()),
+ (Field::Data, RecordField::bytes()),
+ ])
+ .write_durability(mode.clone())
+ .primary_key(Field::Id)
+ .initialize()
+ .expect("Failed to initialize DB");
+
+ b.iter(|| {
+ let record = random_record(0, 1000);
+ let _ = db.upsert(black_box(&record));
+ });
+ });
+ }
+}
+
+pub fn get_from_disk_various_initial_sizes(c: &mut Criterion) {
+ let mut group = c.benchmark_group("get_from_disk_various_initial_sizes");
+
+ for size in [0, 10, 100, 1000, 3300, 6700, 10000, 50000, 100_000] {
+ 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()
+ .data_dir(&data_dir)
+ .memtable_capacity(0)
+ .fields(&vec![
+ (Field::Id, RecordField::int()),
+ (Field::Name, RecordField::string()),
+ (Field::Data, RecordField::bytes()),
+ ])
+ .primary_key(Field::Id)
+ .initialize()
+ .expect("Failed to initialize DB");
+ prefill_db(&mut db, size).expect("Failed to prefill DB");
+
+ group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &_size| {
+ b.iter(|| {
+ let id = random_int(0, size as i64 + 1);
+ let _ = db.get(black_box(&RecordValue::Int(id)));
+ });
+ });
+ }
+}
+
+pub fn get_various_memtable_capacities(c: &mut Criterion) {
+ let mut group = c.benchmark_group("get_various_memtable_capacities");
+
+ const PREFILL_N: usize = 10000;
+ 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");
+
+ // Create a db instance for prefilling
+ let mut db = DB::configure()
+ .data_dir(&data_dir)
+ .fields(&vec![
+ (Field::Id, RecordField::int()),
+ (Field::Name, RecordField::string()),
+ (Field::Data, RecordField::bytes()),
+ ])
+ .primary_key(Field::Id)
+ .initialize()
+ .expect("Failed to initialize DB");
+
+ prefill_db(&mut db, PREFILL_N).expect("Failed to prefill DB");
+ drop(db);
+
+ // prefill_db generates IDs between 0..1000, so having memtable_capacity = 1000
+ // effectively indexes the whole DB
+ for size in (0..).map(|x| x * 100).take_while(|&x| x <= 1000) {
+ group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &_size| {
+ let mut db = DB::configure()
+ .data_dir(&data_dir)
+ .fields(&vec![
+ (Field::Id, RecordField::int()),
+ (Field::Name, RecordField::string()),
+ (Field::Data, RecordField::bytes()),
+ ])
+ .memtable_capacity(size)
+ .primary_key(Field::Id)
+ .initialize()
+ .expect("Failed to initialize DB");
+
+ b.iter(|| {
+ let id = random_int(0, 1000 + 1);
+ let _ = db.get(black_box(&RecordValue::Int(id)));
+ });
+ });
+ }
+}
+
+fn reverse_read_file_with_various_buffer_sizes(c: &mut Criterion) {
+ let mut group = c.benchmark_group("reverse_read_file_with_various_buffer_sizes");
+ group.sample_size(50);
+
+ // odd powers of 2
+ let buffer_sizes = [128, 512, 2048, 8192, 32768, 131_072, 524_288];
+ const PREFILL_N: usize = 100_000;
+
+ 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");
+
+ // Create a db instance for prefilling
+ let mut db = DB::configure()
+ .data_dir(&data_dir)
+ .fields(&vec![
+ (Field::Id, RecordField::int()),
+ (Field::Name, RecordField::string()),
+ (Field::Data, RecordField::bytes()),
+ ])
+ .primary_key(Field::Id)
+ .initialize()
+ .expect("Failed to initialize DB");
+
+ prefill_db(&mut db, PREFILL_N).expect("Failed to prefill DB");
+ drop(db);
+
+ for size in buffer_sizes {
+ group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &_size| {
+ let mut file = OpenOptions::new()
+ .read(true)
+ .open(Path::new(data_dir).join("db"))
+ .expect("Failed to open log file");
+
+ b.iter(|| {
+ let mut rev_reader = ReverseLogReader::new_with_size(&mut file, size)
+ .expect("Failed to create ReverseLogReader");
+
+ // This is to avoid optimizing out the loop
+ let mut i = 0;
+ for _ in &mut rev_reader {
+ i += 1;
+ }
+
+ i
+ });
+ });
+ }
+}
+
+// Register the benchmark group
+criterion_group!(
+ benches,
+ upsert_various_initial_sizes,
+ upsert_write_durability,
+ get_from_disk_various_initial_sizes,
+ get_various_memtable_capacities,
+ reverse_read_file_with_various_buffer_sizes,
+);
+criterion_main!(benches);
diff --git a/log_db/benches/utils.rs b/log_db/benches/utils.rs
new file mode 100644
index 0000000..63b3d84
--- /dev/null
+++ b/log_db/benches/utils.rs
@@ -0,0 +1,46 @@
+use log_db::*;
+use rand::distributions::Alphanumeric;
+use rand::Rng;
+use std::fmt::Debug;
+use std::io;
+
+// 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 record
+pub fn random_record(from_id: i64, to_id: i64) -> Record {
+ Record {
+ values: vec![
+ RecordValue::Int(random_int(from_id, to_id)), // Random int value between 0..1000
+ RecordValue::String(random_string(5)), // Random string of length 5
+ RecordValue::Bytes(random_bytes(10)), // Random bytes of length 10
+ ],
+ }
+}
+
+pub fn prefill_db<T: Eq + Clone + Debug>(
+ db: &mut DB<T>,
+ n_records: usize,
+) -> Result<(), io::Error> {
+ for _ in 0..n_records {
+ let record = random_record(0, n_records as i64);
+ db.upsert(&record)?;
+ }
+
+ Ok(())
+}