liteboxfs 0.2.0

A modern POSIX filesystem in a SQLite database
Documentation
mod common;

use std::{
    fs,
    io::{self, Seek, SeekFrom, Write},
    time::{Duration, Instant},
};

use criterion::{
    BenchmarkGroup, BenchmarkId, Criterion, Throughput, criterion_group, criterion_main,
    measurement::WallTime,
};
use liteboxfs::{Connection, CreateOptions, FileKind, Owner};
use rand::{RngCore, SeedableRng, rngs::SmallRng};

use common::TEST_INPUTS;

const TEST_SAMPLE_SIZE: usize = 20;

fn read_litebox(group: &mut BenchmarkGroup<'_, WallTime>, mut conn: Connection) {
    let mut rng = SmallRng::from_os_rng();

    for input in TEST_INPUTS {
        group.throughput(Throughput::Bytes(input.len as u64));

        group.bench_with_input(
            BenchmarkId::new("actual read throughput", input.to_string()),
            &input.len,
            |b, len| {
                b.iter_custom(|iters| {
                    let mut total = Duration::from_secs(0);

                    for _ in 0..iters {
                        let mut tx = conn.tx().unwrap();
                        let mut fs = tx.fs().unwrap();
                        let mut file = fs
                            .create("test.txt", FileKind::Regular, Owner::ROOT)
                            .unwrap();

                        let mut buffer = vec![0u8; *len];
                        rng.fill_bytes(&mut buffer);

                        io::copy(&mut buffer.as_slice(), &mut file).unwrap();
                        file.flush().unwrap();
                        file.seek(SeekFrom::Start(0)).unwrap();

                        buffer.clear();

                        let start = Instant::now();

                        io::copy(&mut file, &mut buffer).unwrap();

                        total += start.elapsed();

                        drop(file);
                        drop(fs);
                        tx.rollback().unwrap();
                    }

                    total
                });
            },
        );
    }
}

fn read_in_memory(c: &mut Criterion) {
    let mut group = c.benchmark_group("read performance (in-memory)");
    group.sample_size(TEST_SAMPLE_SIZE);

    let conn = Connection::open_in_memory(&CreateOptions::default()).unwrap();
    read_litebox(&mut group, conn);

    group.finish();
}

fn read_in_memory_chunking(c: &mut Criterion) {
    let mut group = c.benchmark_group("read performance (in-memory, chunking)");
    group.sample_size(TEST_SAMPLE_SIZE);

    let opts = CreateOptions::default().chunking(true);
    let conn = Connection::open_in_memory(&opts).unwrap();
    read_litebox(&mut group, conn);

    group.finish();
}

fn read_on_disk(c: &mut Criterion) {
    let mut group = c.benchmark_group("read performance (on-disk)");
    group.sample_size(TEST_SAMPLE_SIZE);

    let conn = Connection::create_new("bench.litebox", &CreateOptions::default()).unwrap();
    read_litebox(&mut group, conn);

    group.finish();

    fs::remove_file("bench.litebox").ok();
}

fn read_on_disk_chunking(c: &mut Criterion) {
    let mut group = c.benchmark_group("read performance (on-disk, chunking)");
    group.sample_size(TEST_SAMPLE_SIZE);

    let opts = CreateOptions::default().chunking(true);
    let conn = Connection::create_new("bench.litebox", &opts).unwrap();
    read_litebox(&mut group, conn);

    group.finish();

    fs::remove_file("bench.litebox").ok();
}

criterion_group!(
    read,
    read_in_memory,
    read_on_disk,
    read_in_memory_chunking,
    read_on_disk_chunking
);

criterion_main!(read);