Skip to content

Commit

Permalink
commitlog: Provide segment_len method for segments (#2042)
Browse files Browse the repository at this point in the history
  • Loading branch information
kim authored Dec 10, 2024
1 parent b9b36d5 commit 3169861
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 6 deletions.
17 changes: 15 additions & 2 deletions crates/commitlog/src/repo/fs.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::fs::{self, File};
use std::io;
use std::io::{self, Seek};

use log::{debug, warn};
use spacetimedb_paths::server::{CommitLogDir, SegmentFile};

use super::{Repo, TxOffset, TxOffsetIndex, TxOffsetIndexMut};
use super::{Repo, Segment, TxOffset, TxOffsetIndex, TxOffsetIndexMut};

const SEGMENT_FILE_EXT: &str = ".stdb.log";

Expand Down Expand Up @@ -57,6 +57,19 @@ impl Fs {
}
}

impl Segment for File {
fn segment_len(&mut self) -> io::Result<u64> {
let old_pos = self.stream_position()?;
let len = self.seek(io::SeekFrom::End(0))?;
// If we're already at the end of the file, avoid seeking.
if old_pos != len {
self.seek(io::SeekFrom::Start(old_pos))?;
}

Ok(len)
}
}

impl Repo for Fs {
type Segment = File;

Expand Down
13 changes: 11 additions & 2 deletions crates/commitlog/src/repo/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ impl Segment {
pub fn len(&self) -> usize {
self.buf.read().unwrap().len()
}

pub fn is_empty(&self) -> bool {
self.len() == 0
}
Expand All @@ -39,6 +40,12 @@ impl From<SharedBytes> for Segment {
}
}

impl super::Segment for Segment {
fn segment_len(&mut self) -> io::Result<u64> {
Ok(Segment::len(self) as u64)
}
}

impl FileLike for Segment {
fn fsync(&mut self) -> io::Result<()> {
Ok(())
Expand Down Expand Up @@ -118,8 +125,10 @@ impl Repo for Memory {
let mut inner = self.0.write().unwrap();
match inner.entry(offset) {
btree_map::Entry::Occupied(entry) => {
if entry.get().read().unwrap().len() == 0 {
Ok(Segment::from(Arc::clone(entry.get())))
let entry = entry.get();
let read_guard = entry.read().unwrap();
if read_guard.len() == 0 {
Ok(Segment::from(Arc::clone(entry)))
} else {
Err(io::Error::new(
io::ErrorKind::AlreadyExists,
Expand Down
17 changes: 16 additions & 1 deletion crates/commitlog/src/repo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,28 @@ pub type TxOffset = u64;
pub type TxOffsetIndexMut = IndexFileMut<TxOffset>;
pub type TxOffsetIndex = IndexFile<TxOffset>;

pub trait Segment: FileLike + io::Read + io::Write + io::Seek + Send + Sync {
/// Determine the length in bytes of the segment.
///
/// This method does not rely on metadata `fsync`, and may use up to three
/// `seek` operations.
///
/// If the method returns successfully, the seek position before the call is
/// restored. However, if it returns an error, the seek position is
/// unspecified.
//
// TODO: Replace with `Seek::stream_len` if / when stabilized:
// https://github.com/rust-lang/rust/issues/59359
fn segment_len(&mut self) -> io::Result<u64>;
}

/// A repository of log segments.
///
/// This is mainly an internal trait to allow testing against an in-memory
/// representation.
pub trait Repo: Clone {
/// The type of log segments managed by this repo, which must behave like a file.
type Segment: io::Read + io::Write + FileLike + io::Seek + Send + Sync + 'static;
type Segment: Segment + 'static;

/// Create a new segment with the minimum transaction offset `offset`.
///
Expand Down
8 changes: 7 additions & 1 deletion crates/commitlog/src/tests/partial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use log::debug;

use crate::{
commitlog, error, payload,
repo::{self, Repo},
repo::{self, Repo, Segment},
segment::FileLike,
tests::helpers::enable_logging,
Commit, Encode, Options, DEFAULT_LOG_FORMAT_VERSION,
Expand Down Expand Up @@ -160,6 +160,12 @@ struct ShortSegment {
max_len: u64,
}

impl Segment for ShortSegment {
fn segment_len(&mut self) -> io::Result<u64> {
self.inner.segment_len()
}
}

impl FileLike for ShortSegment {
fn fsync(&mut self) -> std::io::Result<()> {
self.inner.fsync()
Expand Down

2 comments on commit 3169861

@github-actions
Copy link

@github-actions github-actions bot commented on 3169861 Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarking failed. Please check the workflow run for details.

@github-actions
Copy link

@github-actions github-actions bot commented on 3169861 Dec 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callgrind benchmark results

Callgrind Benchmark Report

These benchmarks were run using callgrind,
an instruction-level profiler. They allow comparisons between sqlite (sqlite), SpacetimeDB running through a module (stdb_module), and the underlying SpacetimeDB data storage engine (stdb_raw). Callgrind emulates a CPU to collect the below estimates.

Measurement changes larger than five percent are in bold.

In-memory benchmarks

callgrind: empty transaction

db total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw 6455 6455 0.00% 6559 6559 0.00%
sqlite 5609 5609 0.00% 6061 6061 0.00%

callgrind: filter

db schema indices count preload _column data_type total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str no_index 64 128 1 u64 75267 75267 0.00% 75763 75755 0.01%
stdb_raw u32_u64_str no_index 64 128 2 string 117551 117551 0.00% 118327 118323 0.00%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 25072 25072 0.00% 25648 25648 0.00%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 24039 24039 0.00% 24475 24467 0.03%
sqlite u32_u64_str no_index 64 128 2 string 144351 144351 0.00% 145821 145825 -0.00%
sqlite u32_u64_str no_index 64 128 1 u64 123742 123742 0.00% 125052 125048 0.00%
sqlite u32_u64_str btree_each_column 64 128 1 u64 131059 131059 0.00% 132473 132473 0.00%
sqlite u32_u64_str btree_each_column 64 128 2 string 134158 134158 0.00% 135752 135748 0.00%

callgrind: insert bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 64 128 814337 790526 3.01% 862377 807706 6.77%
stdb_raw u32_u64_str btree_each_column 64 128 1040919 1042219 -0.12% 1072649 1073571 -0.09%
sqlite u32_u64_str unique_0 64 128 399360 399360 0.00% 414108 414104 0.00%
sqlite u32_u64_str btree_each_column 64 128 984611 984611 0.00% 1018945 1018953 -0.00%

callgrind: iterate

db schema indices count total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 138448 138448 0.00% 138534 138534 0.00%
stdb_raw u32_u64_str unique_0 64 15873 15873 0.00% 15951 15943 0.05%
sqlite u32_u64_str unique_0 1024 1042718 1042718 0.00% 1046082 1046082 0.00%
sqlite u32_u64_str unique_0 64 74722 74704 0.02% 75912 75878 0.04%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47528 47528 0.00% 50180 50180 0.00%
64 bsatn 25509 25509 0.00% 27753 27753 0.00%
16 bsatn 8200 8200 0.00% 9594 9594 0.00%
16 json 12188 12188 0.00% 14092 14092 0.00%

callgrind: update bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 1024 19052516 19249447 -1.02% 19567092 19753965 -0.95%
stdb_raw u32_u64_str unique_0 64 128 1237102 1251660 -1.16% 1274198 1289562 -1.19%
sqlite u32_u64_str unique_0 1024 1024 1802137 1802137 0.00% 1811105 1811109 -0.00%
sqlite u32_u64_str unique_0 64 128 128540 128540 0.00% 131336 131360 -0.02%
On-disk benchmarks

callgrind: empty transaction

db total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw 6460 6460 0.00% 6564 6560 0.06%
sqlite 5651 5651 0.00% 6141 6141 0.00%

callgrind: filter

db schema indices count preload _column data_type total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str no_index 64 128 1 u64 75272 75272 0.00% 75732 75732 0.00%
stdb_raw u32_u64_str no_index 64 128 2 string 117556 117556 0.00% 118276 118256 0.02%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 25076 25076 0.00% 25688 25624 0.25%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 24044 24044 0.00% 24456 24456 0.00%
sqlite u32_u64_str no_index 64 128 1 u64 125663 125663 0.00% 127241 127237 0.00%
sqlite u32_u64_str no_index 64 128 2 string 146272 146272 0.00% 148002 148006 -0.00%
sqlite u32_u64_str btree_each_column 64 128 2 string 136344 136344 0.00% 138354 138334 0.01%
sqlite u32_u64_str btree_each_column 64 128 1 u64 133155 133155 0.00% 134985 134969 0.01%

callgrind: insert bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 64 128 762654 763405 -0.10% 809938 810647 -0.09%
stdb_raw u32_u64_str btree_each_column 64 128 987474 991904 -0.45% 1049952 1054348 -0.42%
sqlite u32_u64_str unique_0 64 128 416908 416908 0.00% 431052 431060 -0.00%
sqlite u32_u64_str btree_each_column 64 128 1023158 1023158 0.00% 1057352 1057372 -0.00%

callgrind: iterate

db schema indices count total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 138453 138453 0.00% 138515 138515 0.00%
stdb_raw u32_u64_str unique_0 64 15878 15878 0.00% 15940 15940 0.00%
sqlite u32_u64_str unique_0 1024 1045786 1045786 0.00% 1049620 1049620 0.00%
sqlite u32_u64_str unique_0 64 76476 76476 0.00% 77818 77818 0.00%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47528 47528 0.00% 50180 50180 0.00%
64 bsatn 25509 25509 0.00% 27753 27753 0.00%
16 bsatn 8200 8200 0.00% 9594 9594 0.00%
16 json 12188 12188 0.00% 14092 14092 0.00%

callgrind: update bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 1024 17967555 17968107 -0.00% 18562363 18566031 -0.02%
stdb_raw u32_u64_str unique_0 64 128 1190928 1189447 0.12% 1259674 1257537 0.17%
sqlite u32_u64_str unique_0 1024 1024 1809785 1809785 0.00% 1818569 1818569 0.00%
sqlite u32_u64_str unique_0 64 128 132687 132687 0.00% 135591 135591 0.00%

Please sign in to comment.