aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2024-10-05 18:18:55 +0200
committerJan Tuomi <jan@jantuomi.fi>2024-10-05 18:18:55 +0200
commitf69622209297111bedb6633af3d973164a4f6d93 (patch)
tree85f6831d6a7b263206c903549802df59f26003be
parentbe2827ffd3f4b73d20da791c9798d83daf0f44f5 (diff)
Improve benchmarks, apply measurements to code
-rw-r--r--benches/benchmark.rs55
-rw-r--r--src/reverse_log_reader.rs12
2 files changed, 64 insertions, 3 deletions
diff --git a/benches/benchmark.rs b/benches/benchmark.rs
index c999811..43d53f7 100644
--- a/benches/benchmark.rs
+++ b/benches/benchmark.rs
@@ -2,6 +2,8 @@ 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::*;
@@ -156,6 +158,58 @@ pub fn get_various_memtable_capacities(c: &mut Criterion) {
}
}
+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, RecordFieldType::Int),
+ (Field::Name, RecordFieldType::String),
+ (Field::Data, RecordFieldType::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,
@@ -163,5 +217,6 @@ criterion_group!(
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/src/reverse_log_reader.rs b/src/reverse_log_reader.rs
index 8a2126f..5d80dba 100644
--- a/src/reverse_log_reader.rs
+++ b/src/reverse_log_reader.rs
@@ -3,6 +3,7 @@ use std::fs::{self};
use std::io::{self, Read, Seek, SeekFrom};
pub struct ReverseLogReader<'a> {
+ /// The file to read from end to beginning.
file: &'a mut fs::File,
/// The internal buffer used to read from the file.
/// It is populated with the last INTERNAL_BUF_SIZE bytes read from the file
@@ -13,16 +14,21 @@ pub struct ReverseLogReader<'a> {
/// is populated with the next (= closer to the start of the file) INTERNAL_BUF_SIZE bytes from the file.
/// Note: This is the index of the next byte to be read from the internal buffer + 1
internal_pos: usize,
+ /// A flag indicating whether the record separator at the cursor position has been consumed.
+ /// Useful to avoid consuming the separator once when reading until an escape character, and
+ /// a second time when reading a new record and validating it ends in a separator.
consumed_record_sep: bool,
}
-const INTERNAL_BUF_SIZE: usize = 4096;
+// This value is based on the reverse_read_file_with_various_buffer_sizes benchmark.
+// Greater values yield little to no performance improvement.
+const DEFAULT_INTERNAL_BUF_SIZE: usize = 32768;
impl<'a> ReverseLogReader<'a> {
pub fn new(file: &mut fs::File) -> Result<ReverseLogReader, io::Error> {
file.seek(SeekFrom::End(0))?;
Ok(ReverseLogReader {
file,
- internal_buf: vec![0; INTERNAL_BUF_SIZE],
+ internal_buf: vec![0; DEFAULT_INTERNAL_BUF_SIZE],
internal_pos: 0,
consumed_record_sep: false,
})
@@ -61,7 +67,7 @@ impl<'a> ReverseLogReader<'a> {
self.consumed_record_sep = false;
let mut result_buf: Vec<u8> = vec![];
- let mut read_buf = Vec::with_capacity(INTERNAL_BUF_SIZE);
+ let mut read_buf = Vec::with_capacity(self.internal_buf.len());
loop {
read_buf.clear();
let read = self.read_until(ESCAPE_CHARACTER, &mut read_buf)?;