Skip to content

Commit

Permalink
core: Provide read access to commit/message log and odb (#265)
Browse files Browse the repository at this point in the history
* core: Provide read access to commit/message log and odb

This is a first approximation to provide data access for Kafka-style
replication. It punts on notifications of segment rotation (which
could also be solved via filesystem events).

ObjectDB access is fairly crude, and will likely require it's own
replication subsystem.

* fixup! Merge remote-tracking branch 'origin/master' into kim/log-access

* Add some tests

Also make max segment size configurable, so tests don't have to write
>= 1GiB worth of data.

* Abide to the Rust naming conventions

* Add test for commit iter

* Remove `MessageLogIter`, use `commit_log::Iter` instead (#272)
  • Loading branch information
kim authored Oct 3, 2023
1 parent 3f5f97f commit e8aed85
Show file tree
Hide file tree
Showing 3 changed files with 583 additions and 122 deletions.
275 changes: 260 additions & 15 deletions crates/core/src/db/commit_log.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{
datastore::traits::{MutTxDatastore, TxData},
message_log::MessageLog,
message_log::{self, MessageLog},
messages::commit::Commit,
ostorage::ObjectDB,
};
Expand All @@ -14,7 +14,13 @@ use crate::{
},
error::DBError,
};
use spacetimedb_lib::hash::hash_bytes;

use spacetimedb_lib::{
hash::{hash_bytes, Hash},
DataKey,
};

use std::io;
use std::sync::Arc;
use std::sync::Mutex;

Expand Down Expand Up @@ -50,24 +56,30 @@ impl CommitLog {
D: MutTxDatastore<RowId = RowId>,
{
if let Some(bytes) = self.generate_commit(tx_data, datastore) {
if let Some(mlog) = &self.mlog {
let mut mlog = mlog.lock().unwrap();
mlog.append(&bytes)?;
if self.fsync {
mlog.sync_all()?;
let mut odb = self.odb.lock().unwrap();
odb.sync_all()?;
log::trace!("DATABASE: FSYNC");
} else {
mlog.flush()?;
}
}
Ok(Some(bytes.len()))
self.append_commit_bytes(&bytes).map(Some)
} else {
Ok(None)
}
}

// For testing -- doesn't require a `MutTxDatastore`, which is currently
// unused anyway.
fn append_commit_bytes(&self, commit: &[u8]) -> Result<usize, DBError> {
if let Some(mlog) = &self.mlog {
let mut mlog = mlog.lock().unwrap();
mlog.append(commit)?;
if self.fsync {
mlog.sync_all()?;
let mut odb = self.odb.lock().unwrap();
odb.sync_all()?;
log::trace!("DATABASE: FSYNC");
} else {
mlog.flush()?;
}
}
Ok(commit.len())
}

fn generate_commit<D: MutTxDatastore<RowId = RowId>>(&self, tx_data: &TxData, _datastore: &D) -> Option<Vec<u8>> {
// We are not creating a commit for empty transactions.
// The reason for this is that empty transactions get encoded as 0 bytes,
Expand Down Expand Up @@ -121,3 +133,236 @@ impl CommitLog {
}
}
}

/// A read-only view of a [`CommitLog`].
pub struct CommitLogView {
mlog: Option<Arc<Mutex<MessageLog>>>,
odb: Arc<Mutex<Box<dyn ObjectDB + Send>>>,
}

impl CommitLogView {
/// Obtain an iterator over a snapshot of the raw message log segments.
///
/// See also: [`MessageLog::segments`]
pub fn message_log_segments(&self) -> message_log::Segments {
self.message_log_segments_from(0)
}

/// Obtain an iterator over a snapshot of the raw message log segments
/// containing messages equal to or newer than `offset`.
///
/// See [`MessageLog::segments_from`] for more information.
pub fn message_log_segments_from(&self, offset: u64) -> message_log::Segments {
if let Some(mlog) = &self.mlog {
let mlog = mlog.lock().unwrap();
mlog.segments_from(offset)
} else {
message_log::Segments::empty()
}
}

/// Obtain an iterator over the [`Commit`]s in the log.
///
/// The iterator represents a snapshot of the log.
pub fn iter(&self) -> Iter {
self.iter_from(0)
}

/// Obtain an iterator over the [`Commit`]s in the log, starting at `offset`.
///
/// The iterator represents a snapshot of the log.
///
/// Note that [`Commit`]s with an offset _smaller_ than `offset` may be
/// yielded if the offset doesn't fall on a segment boundary, due to the
/// lack of slicing support.
///
/// See [`MessageLog::segments_from`] for more information.
pub fn iter_from(&self, offset: u64) -> Iter {
self.message_log_segments_from(offset).into()
}

/// Obtain an iterator over the large objects in [`Commit`], if any.
///
/// Large objects are stored in the [`ObjectDB`], and are referenced from
/// the transactions in a [`Commit`].
///
/// The iterator attempts to read each large object in turn, yielding an
/// [`io::Error`] with kind [`io::ErrorKind::NotFound`] if the object was
/// not found.
//
// TODO(kim): We probably want a more efficient way to stream the contents
// of the ODB over the network for replication purposes.
pub fn commit_objects<'a>(&self, commit: &'a Commit) -> impl Iterator<Item = io::Result<bytes::Bytes>> + 'a {
fn hashes(tx: &Arc<Transaction>) -> impl Iterator<Item = Hash> + '_ {
tx.writes.iter().filter_map(|write| {
if let DataKey::Hash(h) = write.data_key {
Some(h)
} else {
None
}
})
}

let odb = self.odb.clone();
commit.transactions.iter().flat_map(hashes).map(move |hash| {
let odb = odb.lock().unwrap();
odb.get(hash)
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, format!("Missing object: {hash}")))
})
}
}

impl From<&CommitLog> for CommitLogView {
fn from(log: &CommitLog) -> Self {
Self {
mlog: log.mlog.clone(),
odb: log.odb.clone(),
}
}
}

#[must_use = "iterators are lazy and do nothing unless consumed"]
struct IterSegment {
inner: message_log::IterSegment,
}

impl Iterator for IterSegment {
type Item = io::Result<Commit>;

fn next(&mut self) -> Option<Self::Item> {
let next = self.inner.next()?;
Some(next.map(|bytes| {
// It seems very improbable that `decode` is infallible...
let (commit, _) = Commit::decode(bytes);
commit
}))
}
}

/// Iterator over a [`CommitLogView`], yielding [`Commit`]s.
///
/// Created by [`CommitLogView::iter`] and [`CommitLogView::iter_from`]
/// respectively.
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct Iter {
commits: Option<IterSegment>,
segments: message_log::Segments,
}

impl Iterator for Iter {
type Item = io::Result<Commit>;

fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(mut commits) = self.commits.take() {
if let Some(commit) = commits.next() {
self.commits = Some(commits);
return Some(commit);
}
}

let segment = self.segments.next()?;
match segment.try_into_iter() {
Err(e) => return Some(Err(e)),
Ok(inner) => {
self.commits = Some(IterSegment { inner });
}
}
}
}
}

impl From<message_log::Segments> for Iter {
fn from(segments: message_log::Segments) -> Self {
Self {
commits: None,
segments,
}
}
}

#[cfg(test)]
mod tests {
use super::*;

use spacetimedb_lib::data_key::InlineData;
use tempdir::TempDir;

use crate::db::ostorage::memory_object_db::MemoryObjectDB;

#[test]
fn test_iter_commits() {
let tmp = TempDir::new("commit_log_test").unwrap();

let data_key = DataKey::Data(InlineData::from_bytes(b"asdf").unwrap());
let tx = Transaction {
writes: vec![
Write {
operation: Operation::Insert,
set_id: 42,
data_key,
},
Write {
operation: Operation::Delete,
set_id: 42,
data_key,
},
],
};

// The iterator doesn't verify integrity of commits, so we can just
// write the same one repeatedly.
let commit = Commit {
parent_commit_hash: None,
commit_offset: 0,
min_tx_offset: 0,
transactions: vec![Arc::new(tx)],
};
let mut commit_bytes = Vec::new();
commit.encode(&mut commit_bytes);

const COMMITS_PER_SEGMENT: usize = 10_000;
const TOTAL_MESSAGES: usize = (COMMITS_PER_SEGMENT * 3) - 1;
let segment_size: usize = COMMITS_PER_SEGMENT * (commit_bytes.len() + 4);

let mlog = message_log::MessageLog::options()
.max_segment_size(segment_size as u64)
.open(tmp.path())
.unwrap();
let odb = MemoryObjectDB::default();

let log = CommitLog::new(
Some(Arc::new(Mutex::new(mlog))),
Arc::new(Mutex::new(Box::new(odb))),
Commit {
parent_commit_hash: None,
commit_offset: 0,
min_tx_offset: 0,
transactions: Vec::new(),
},
true, // fsync
);

for _ in 0..TOTAL_MESSAGES {
log.append_commit_bytes(&commit_bytes).unwrap();
}

let view = CommitLogView::from(&log);
let commits = view.iter().map(Result::unwrap).count();
assert_eq!(TOTAL_MESSAGES, commits);

let commits = view.iter_from(1_000_000).map(Result::unwrap).count();
assert_eq!(0, commits);

// No slicing yet, so offsets on segment boundaries yield an additional
// COMMITS_PER_SEGMENT.
let commits = view.iter_from(20_001).map(Result::unwrap).count();
assert_eq!(9999, commits);

let commits = view.iter_from(10_001).map(Result::unwrap).count();
assert_eq!(19_999, commits);

let commits = view.iter_from(10_000).map(Result::unwrap).count();
assert_eq!(29_999, commits);
}
}
Loading

1 comment on commit e8aed85

@github-actions
Copy link

Choose a reason for hiding this comment

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

Benchmark for e8aed85

Click to view benchmark
Test Base PR %
serialize/location/bsatn/count=100 2.6±0.03µs 37.3 MElem/sec N/A N/A
serialize/location/json/count=100 3.7±0.02µs 25.5 MElem/sec N/A N/A
serialize/location/product_value/count=100 2.6±0.05µs 36.8 MElem/sec N/A N/A
serialize/person/bsatn/count=100 3.2±0.05µs 29.9 MElem/sec N/A N/A
serialize/person/json/count=100 5.3±0.09µs 17.9 MElem/sec N/A N/A
serialize/person/product_value/count=100 1784.8±6.28ns 53.4 MElem/sec N/A N/A
sqlite/disk/empty 438.4±5.27ns 425.6±2.73ns -2.92%
sqlite/disk/filter/string/indexed/load=1000/count=10 5.6±0.02µs 175.6 KElem/sec N/A N/A
sqlite/disk/filter/string/non_indexed/load=1000/count=10 53.2±0.50µs 18.3 KElem/sec N/A N/A
sqlite/disk/filter/u64/indexed/load=1000/count=10 5.4±0.10µs 181.6 KElem/sec N/A N/A
sqlite/disk/filter/u64/non_indexed/load=1000/count=10 39.4±0.05µs 24.8 KElem/sec N/A N/A
sqlite/disk/find_unique/u32/load=1000 2.2±0.02µs 436.5 KElem/sec N/A N/A
sqlite/disk/insert_1/location/multi_index/load=0 14.6±0.16µs 67.1 KElem/sec N/A N/A
sqlite/disk/insert_1/location/multi_index/load=1000 19.8±0.85µs 49.3 KElem/sec N/A N/A
sqlite/disk/insert_1/location/non_unique/load=0 7.2±0.10µs 135.0 KElem/sec N/A N/A
sqlite/disk/insert_1/location/non_unique/load=1000 7.6±0.12µs 128.0 KElem/sec N/A N/A
sqlite/disk/insert_1/location/unique/load=0 7.2±0.11µs 135.6 KElem/sec N/A N/A
sqlite/disk/insert_1/location/unique/load=1000 7.7±0.12µs 127.5 KElem/sec N/A N/A
sqlite/disk/insert_1/person/multi_index/load=0 14.5±0.20µs 67.5 KElem/sec N/A N/A
sqlite/disk/insert_1/person/multi_index/load=1000 20.7±0.72µs 47.2 KElem/sec N/A N/A
sqlite/disk/insert_1/person/non_unique/load=0 7.2±0.07µs 134.9 KElem/sec N/A N/A
sqlite/disk/insert_1/person/non_unique/load=1000 8.0±0.17µs 122.7 KElem/sec N/A N/A
sqlite/disk/insert_1/person/unique/load=0 7.2±0.09µs 134.8 KElem/sec N/A N/A
sqlite/disk/insert_1/person/unique/load=1000 8.0±0.18µs 122.2 KElem/sec N/A N/A
sqlite/disk/insert_bulk/location/multi_index/load=0/count=100 128.4±0.41µs 122.3±0.61µs -4.75%
sqlite/disk/insert_bulk/location/multi_index/load=1000/count=100 215.7±2.47µs 208.8±2.32µs -3.20%
sqlite/disk/insert_bulk/location/non_unique/load=0/count=100 41.6±0.39µs 23.5 KElem/sec N/A N/A
sqlite/disk/insert_bulk/location/non_unique/load=1000/count=100 45.8±0.16µs 21.3 KElem/sec N/A N/A
sqlite/disk/insert_bulk/location/unique/load=0/count=100 44.5±0.15µs 21.9 KElem/sec N/A N/A
sqlite/disk/insert_bulk/location/unique/load=1000/count=100 50.5±0.21µs 19.3 KElem/sec N/A N/A
sqlite/disk/insert_bulk/person/multi_index/load=0/count=100 113.9±1.44µs 117.7±1.24µs +3.34%
sqlite/disk/insert_bulk/person/multi_index/load=1000/count=100 251.0±1.76µs 248.3±3.90µs -1.08%
sqlite/disk/insert_bulk/person/non_unique/load=0/count=100 41.7±0.19µs 23.4 KElem/sec N/A N/A
sqlite/disk/insert_bulk/person/non_unique/load=1000/count=100 58.3±0.79µs 16.8 KElem/sec N/A N/A
sqlite/disk/insert_bulk/person/unique/load=0/count=100 45.3±0.31µs 21.5 KElem/sec N/A N/A
sqlite/disk/insert_bulk/person/unique/load=1000/count=100 51.4±0.71µs 19.0 KElem/sec N/A N/A
sqlite/disk/iterate/location/unique/count=100 8.1±0.01µs 120.5 KElem/sec N/A N/A
sqlite/disk/iterate/person/unique/count=100 8.8±0.11µs 110.7 KElem/sec N/A N/A
sqlite/mem/empty 426.6±3.03ns 422.5±4.49ns -0.96%
sqlite/mem/filter/string/indexed/load=1000/count=10 4.1±0.02µs 236.3 KElem/sec N/A N/A
sqlite/mem/filter/string/non_indexed/load=1000/count=10 55.3±0.51µs 17.7 KElem/sec N/A N/A
sqlite/mem/filter/u64/indexed/load=1000/count=10 3.9±0.05µs 248.8 KElem/sec N/A N/A
sqlite/mem/filter/u64/non_indexed/load=1000/count=10 38.2±0.11µs 25.6 KElem/sec N/A N/A
sqlite/mem/find_unique/u32/load=1000 1060.2±20.74ns 921.1 KElem/sec N/A N/A
sqlite/mem/insert_1/location/multi_index/load=0 4.3±0.07µs 227.2 KElem/sec N/A N/A
sqlite/mem/insert_1/location/multi_index/load=1000 5.5±0.14µs 177.7 KElem/sec N/A N/A
sqlite/mem/insert_1/location/non_unique/load=0 1732.1±18.50ns 563.8 KElem/sec N/A N/A
sqlite/mem/insert_1/location/non_unique/load=1000 1833.4±24.27ns 532.7 KElem/sec N/A N/A
sqlite/mem/insert_1/location/unique/load=0 1707.8±11.72ns 571.8 KElem/sec N/A N/A
sqlite/mem/insert_1/location/unique/load=1000 1885.3±63.23ns 518.0 KElem/sec N/A N/A
sqlite/mem/insert_1/person/multi_index/load=0 4.1±0.04µs 235.4 KElem/sec N/A N/A
sqlite/mem/insert_1/person/multi_index/load=1000 6.3±0.11µs 154.0 KElem/sec N/A N/A
sqlite/mem/insert_1/person/non_unique/load=0 1781.2±28.46ns 548.2 KElem/sec N/A N/A
sqlite/mem/insert_1/person/non_unique/load=1000 1950.4±36.44ns 500.7 KElem/sec N/A N/A
sqlite/mem/insert_1/person/unique/load=0 1790.6±6.73ns 545.4 KElem/sec N/A N/A
sqlite/mem/insert_1/person/unique/load=1000 2.0±0.05µs 487.1 KElem/sec N/A N/A
sqlite/mem/insert_bulk/location/multi_index/load=0/count=100 112.8±0.16µs 110.8±0.77µs -1.77%
sqlite/mem/insert_bulk/location/multi_index/load=1000/count=100 167.7±0.64µs 166.3±1.23µs -0.83%
sqlite/mem/insert_bulk/location/non_unique/load=0/count=100 37.5±8.28µs 26.1 KElem/sec N/A N/A
sqlite/mem/insert_bulk/location/non_unique/load=1000/count=100 38.2±0.31µs 25.5 KElem/sec N/A N/A
sqlite/mem/insert_bulk/location/unique/load=0/count=100 38.3±0.27µs 25.5 KElem/sec N/A N/A
sqlite/mem/insert_bulk/location/unique/load=1000/count=100 42.3±0.30µs 23.1 KElem/sec N/A N/A
sqlite/mem/insert_bulk/person/multi_index/load=0/count=100 101.8±0.98µs 105.2±0.87µs +3.34%
sqlite/mem/insert_bulk/person/multi_index/load=1000/count=100 192.8±1.34µs 195.8±2.83µs +1.56%
sqlite/mem/insert_bulk/person/non_unique/load=0/count=100 35.8±0.48µs 27.3 KElem/sec N/A N/A
sqlite/mem/insert_bulk/person/non_unique/load=1000/count=100 42.1±0.98µs 23.2 KElem/sec N/A N/A
sqlite/mem/insert_bulk/person/unique/load=0/count=100 38.9±0.22µs 25.1 KElem/sec N/A N/A
sqlite/mem/insert_bulk/person/unique/load=1000/count=100 43.3±0.35µs 22.6 KElem/sec N/A N/A
sqlite/mem/iterate/location/unique/count=100 7.0±0.08µs 139.7 KElem/sec N/A N/A
sqlite/mem/iterate/person/unique/count=100 7.3±0.03µs 133.1 KElem/sec N/A N/A
stdb_module/disk/empty 26.0±1.26µs 26.4±1.20µs +1.54%
stdb_module/disk/filter/string/indexed/load=1000/count=10 59.1±5.47µs 16.5 KElem/sec N/A N/A
stdb_module/disk/filter/string/non_indexed/load=1000/count=10 171.5±6.86µs 186.6±6.28µs +8.80%
stdb_module/disk/filter/u64/indexed/load=1000/count=10 53.6±3.98µs 18.2 KElem/sec N/A N/A
stdb_module/disk/filter/u64/non_indexed/load=1000/count=10 145.0±2.21µs 145.9±10.06µs +0.62%
stdb_module/disk/find_unique/u32/load=1000 35.4±2.24µs 27.6 KElem/sec N/A N/A
stdb_module/disk/insert_1/location/multi_index/load=0 53.1±4.15µs 18.4 KElem/sec N/A N/A
stdb_module/disk/insert_1/location/multi_index/load=1000 367.6±22.84µs 354.7±22.09µs -3.51%
stdb_module/disk/insert_1/location/non_unique/load=0 44.7±4.09µs 21.8 KElem/sec N/A N/A
stdb_module/disk/insert_1/location/non_unique/load=1000 301.0±22.76µs 308.8±19.33µs +2.59%
stdb_module/disk/insert_1/location/unique/load=0 50.4±2.78µs 19.4 KElem/sec N/A N/A
stdb_module/disk/insert_1/location/unique/load=1000 323.8±27.74µs 350.1±18.27µs +8.12%
stdb_module/disk/insert_1/person/multi_index/load=0 54.3±1.36µs 18.0 KElem/sec N/A N/A
stdb_module/disk/insert_1/person/multi_index/load=1000 461.4±48.18µs 497.5±57.49µs +7.82%
stdb_module/disk/insert_1/person/non_unique/load=0 51.9±5.32µs 18.8 KElem/sec N/A N/A
stdb_module/disk/insert_1/person/non_unique/load=1000 321.3±30.11µs 354.5±42.35µs +10.33%
stdb_module/disk/insert_1/person/unique/load=0 51.5±4.31µs 19.0 KElem/sec N/A N/A
stdb_module/disk/insert_1/person/unique/load=1000 357.9±37.62µs 361.0±27.97µs +0.87%
stdb_module/disk/insert_bulk/location/multi_index/load=0/count=100 879.9±16.83µs 874.8±19.50µs -0.58%
stdb_module/disk/insert_bulk/location/multi_index/load=1000/count=100 1188.9±50.01µs 1167.0±46.38µs -1.84%
stdb_module/disk/insert_bulk/location/non_unique/load=0/count=100 621.5±8.60µs 620.1±20.42µs -0.23%
stdb_module/disk/insert_bulk/location/non_unique/load=1000/count=100 832.4±34.43µs 783.4±24.20µs -5.89%
stdb_module/disk/insert_bulk/location/unique/load=0/count=100 750.5±12.22µs 761.1±15.36µs +1.41%
stdb_module/disk/insert_bulk/location/unique/load=1000/count=100 1009.9±120.28µs 986.1±31.82µs -2.36%
stdb_module/disk/insert_bulk/person/multi_index/load=0/count=100 1476.8±45.62µs 1420.6±56.06µs -3.81%
stdb_module/disk/insert_bulk/person/multi_index/load=1000/count=100 1842.7±95.92µs 1877.6±70.60µs +1.89%
stdb_module/disk/insert_bulk/person/non_unique/load=0/count=100 787.8±16.77µs 826.1±70.76µs +4.86%
stdb_module/disk/insert_bulk/person/non_unique/load=1000/count=100 977.0±35.57µs 1082.5±60.84µs +10.80%
stdb_module/disk/insert_bulk/person/unique/load=0/count=100 1064.9±26.19µs 1062.6±49.05µs -0.22%
stdb_module/disk/insert_bulk/person/unique/load=1000/count=100 1434.9±54.16µs 1612.6±351.33µs +12.38%
stdb_module/disk/iterate/location/unique/count=100 139.3±3.43µs 139.4±6.32µs +0.07%
stdb_module/disk/iterate/person/unique/count=100 222.3±5.11µs 238.5±17.70µs +7.29%
stdb_module/large_arguments/64KiB 105.4±3.69µs 109.3±1.85µs +3.70%
stdb_module/mem/empty 26.8±1.16µs 26.6±1.10µs -0.75%
stdb_module/mem/filter/string/indexed/load=1000/count=10 70.3±7.31µs 13.9 KElem/sec N/A N/A
stdb_module/mem/filter/string/non_indexed/load=1000/count=10 196.1±18.29µs 179.9±10.72µs -8.26%
stdb_module/mem/filter/u64/indexed/load=1000/count=10 53.3±5.41µs 18.3 KElem/sec N/A N/A
stdb_module/mem/filter/u64/non_indexed/load=1000/count=10 204.6±33.92µs 139.8±6.73µs -31.67%
stdb_module/mem/find_unique/u32/load=1000 35.2±3.15µs 27.8 KElem/sec N/A N/A
stdb_module/mem/insert_1/location/multi_index/load=0 46.1±2.35µs 21.2 KElem/sec N/A N/A
stdb_module/mem/insert_1/location/multi_index/load=1000 384.7±26.38µs 346.0±23.67µs -10.06%
stdb_module/mem/insert_1/location/non_unique/load=0 40.9±1.81µs 23.9 KElem/sec N/A N/A
stdb_module/mem/insert_1/location/non_unique/load=1000 182.4±29.55µs 274.9±41.23µs +50.71%
stdb_module/mem/insert_1/location/unique/load=0 43.1±3.28µs 22.7 KElem/sec N/A N/A
stdb_module/mem/insert_1/location/unique/load=1000 276.0±25.40µs 292.7±24.07µs +6.05%
stdb_module/mem/insert_1/person/multi_index/load=0 52.5±5.25µs 18.6 KElem/sec N/A N/A
stdb_module/mem/insert_1/person/multi_index/load=1000 364.3±76.42µs 439.1±74.33µs +20.53%
stdb_module/mem/insert_1/person/non_unique/load=0 43.2±2.95µs 22.6 KElem/sec N/A N/A
stdb_module/mem/insert_1/person/non_unique/load=1000 300.2±39.08µs 329.2±41.45µs +9.66%
stdb_module/mem/insert_1/person/unique/load=0 44.7±1.17µs 21.9 KElem/sec N/A N/A
stdb_module/mem/insert_1/person/unique/load=1000 321.9±38.05µs 354.7±28.66µs +10.19%
stdb_module/mem/insert_bulk/location/multi_index/load=0/count=100 768.8±10.12µs 751.4±15.55µs -2.26%
stdb_module/mem/insert_bulk/location/multi_index/load=1000/count=100 1027.9±26.42µs 1010.6±40.51µs -1.68%
stdb_module/mem/insert_bulk/location/non_unique/load=0/count=100 509.6±6.75µs 497.3±17.12µs -2.41%
stdb_module/mem/insert_bulk/location/non_unique/load=1000/count=100 640.6±32.36µs 657.6±29.78µs +2.65%
stdb_module/mem/insert_bulk/location/unique/load=0/count=100 641.6±7.76µs 638.5±15.82µs -0.48%
stdb_module/mem/insert_bulk/location/unique/load=1000/count=100 914.1±28.94µs 867.0±36.52µs -5.15%
stdb_module/mem/insert_bulk/person/multi_index/load=0/count=100 1370.9±41.94µs 1324.0±32.42µs -3.42%
stdb_module/mem/insert_bulk/person/multi_index/load=1000/count=100 1688.8±24.78µs 1697.9±52.37µs +0.54%
stdb_module/mem/insert_bulk/person/non_unique/load=0/count=100 738.5±7.85µs 702.8±16.88µs -4.83%
stdb_module/mem/insert_bulk/person/non_unique/load=1000/count=100 938.9±23.43µs 914.7±34.62µs -2.58%
stdb_module/mem/insert_bulk/person/unique/load=0/count=100 948.8±25.72µs 949.6±30.62µs +0.08%
stdb_module/mem/insert_bulk/person/unique/load=1000/count=100 1239.7±47.92µs 1226.8±39.09µs -1.04%
stdb_module/mem/iterate/location/unique/count=100 143.6±4.47µs 138.4±7.35µs -3.62%
stdb_module/mem/iterate/person/unique/count=100 237.8±10.85µs 251.7±20.43µs +5.85%
stdb_module/print_bulk/lines=1 33.2±2.10µs 35.9±2.41µs +8.13%
stdb_module/print_bulk/lines=100 335.8±4.63µs 360.4±7.49µs +7.33%
stdb_module/print_bulk/lines=1000 3.1±0.12ms 3.1±0.51ms 0.00%
stdb_raw/disk/empty 102.8±0.28ns 102.2±0.36ns -0.58%
stdb_raw/disk/filter/string/indexed/load=1000/count=10 2.7±0.01µs 366.7 KElem/sec N/A N/A
stdb_raw/disk/filter/string/non_indexed/load=1000/count=10 129.8±0.37µs 122.6±0.89µs -5.55%
stdb_raw/disk/filter/u64/indexed/load=1000/count=10 2.5±0.04µs 391.4 KElem/sec N/A N/A
stdb_raw/disk/filter/u64/non_indexed/load=1000/count=10 109.6±1.20µs 105.1±0.23µs -4.11%
stdb_raw/disk/find_unique/u32/load=1000 580.1±6.09ns 1683.5 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/multi_index/load=0 6.3±0.04µs 156.0 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/multi_index/load=1000 34.1±8.45µs 28.6 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/non_unique/load=0 3.9±0.06µs 247.5 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/non_unique/load=1000 21.0±1.90µs 46.5 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/unique/load=0 5.1±0.03µs 192.5 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/unique/load=1000 27.0±0.91µs 36.2 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/multi_index/load=0 10.4±0.02µs 94.0 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/multi_index/load=1000 34.2±10.34µs 28.6 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/non_unique/load=0 4.7±0.02µs 207.9 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/non_unique/load=1000 17.6±4.91µs 55.5 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/unique/load=0 7.0±0.09µs 140.1 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/unique/load=1000 26.7±0.85µs 36.6 KElem/sec N/A N/A
stdb_raw/disk/insert_bulk/location/multi_index/load=0/count=100 370.1±1.42µs 378.6±3.32µs +2.30%
stdb_raw/disk/insert_bulk/location/multi_index/load=1000/count=100 436.1±3.58µs 446.9±5.56µs +2.48%
stdb_raw/disk/insert_bulk/location/non_unique/load=0/count=100 165.3±0.73µs 168.5±2.61µs +1.94%
stdb_raw/disk/insert_bulk/location/non_unique/load=1000/count=100 188.8±2.84µs 193.9±5.20µs +2.70%
stdb_raw/disk/insert_bulk/location/unique/load=0/count=100 264.0±1.71µs 270.1±1.43µs +2.31%
stdb_raw/disk/insert_bulk/location/unique/load=1000/count=100 324.5±3.42µs 331.5±4.28µs +2.16%
stdb_raw/disk/insert_bulk/person/multi_index/load=0/count=100 759.0±15.93µs 752.3±2.42µs -0.88%
stdb_raw/disk/insert_bulk/person/multi_index/load=1000/count=100 847.9±5.88µs 831.8±11.59µs -1.90%
stdb_raw/disk/insert_bulk/person/non_unique/load=0/count=100 229.6±0.87µs 233.0±2.39µs +1.48%
stdb_raw/disk/insert_bulk/person/non_unique/load=1000/count=100 255.1±2.26µs 257.3±10.19µs +0.86%
stdb_raw/disk/insert_bulk/person/unique/load=0/count=100 427.0±2.88µs 430.4±1.30µs +0.80%
stdb_raw/disk/insert_bulk/person/unique/load=1000/count=100 485.5±6.94µs 488.6±6.75µs +0.64%
stdb_raw/disk/iterate/location/unique/count=100 10.1±1.49µs 96.5 KElem/sec N/A N/A
stdb_raw/disk/iterate/person/unique/count=100 11.3±0.05µs 86.5 KElem/sec N/A N/A
stdb_raw/mem/empty 102.9±1.01ns 102.3±0.58ns -0.58%
stdb_raw/mem/filter/string/indexed/load=1000/count=10 2.6±0.01µs 371.1 KElem/sec N/A N/A
stdb_raw/mem/filter/string/non_indexed/load=1000/count=10 130.2±0.50µs 122.3±1.47µs -6.07%
stdb_raw/mem/filter/u64/indexed/load=1000/count=10 2.5±0.02µs 389.0 KElem/sec N/A N/A
stdb_raw/mem/filter/u64/non_indexed/load=1000/count=10 110.4±0.60µs 104.5±0.68µs -5.34%
stdb_raw/mem/find_unique/u32/load=1000 578.8±6.75ns 1687.3 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/multi_index/load=0 4.8±0.05µs 203.4 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/multi_index/load=1000 26.9±1.76µs 36.3 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/non_unique/load=0 2.5±0.02µs 388.9 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/non_unique/load=1000 18.5±0.29µs 52.9 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/unique/load=0 3.5±0.02µs 281.7 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/unique/load=1000 23.6±0.52µs 41.4 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/multi_index/load=0 8.7±0.01µs 112.2 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/multi_index/load=1000 27.7±1.59µs 35.2 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/non_unique/load=0 3.2±0.03µs 303.3 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/non_unique/load=1000 14.2±0.35µs 68.9 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/unique/load=0 5.2±0.02µs 188.0 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/unique/load=1000 21.0±0.69µs 46.6 KElem/sec N/A N/A
stdb_raw/mem/insert_bulk/location/multi_index/load=0/count=100 374.4±1.16µs 375.2±1.63µs +0.21%
stdb_raw/mem/insert_bulk/location/multi_index/load=1000/count=100 424.3±1.67µs 427.8±2.51µs +0.82%
stdb_raw/mem/insert_bulk/location/non_unique/load=0/count=100 159.7±1.23µs 160.3±0.76µs +0.38%
stdb_raw/mem/insert_bulk/location/non_unique/load=1000/count=100 182.8±0.50µs 183.6±1.56µs +0.44%
stdb_raw/mem/insert_bulk/location/unique/load=0/count=100 260.2±2.74µs 265.0±1.33µs +1.84%
stdb_raw/mem/insert_bulk/location/unique/load=1000/count=100 317.7±1.27µs 317.9±2.06µs +0.06%
stdb_raw/mem/insert_bulk/person/multi_index/load=0/count=100 737.6±3.03µs 744.2±5.55µs +0.89%
stdb_raw/mem/insert_bulk/person/multi_index/load=1000/count=100 809.3±10.83µs 812.1±3.82µs +0.35%
stdb_raw/mem/insert_bulk/person/non_unique/load=0/count=100 227.0±2.49µs 230.4±7.33µs +1.50%
stdb_raw/mem/insert_bulk/person/non_unique/load=1000/count=100 250.3±1.24µs 250.1±1.66µs -0.08%
stdb_raw/mem/insert_bulk/person/unique/load=0/count=100 420.6±0.49µs 425.9±2.72µs +1.26%
stdb_raw/mem/insert_bulk/person/unique/load=1000/count=100 476.8±2.23µs 479.6±2.39µs +0.59%
stdb_raw/mem/iterate/location/unique/count=100 9.8±0.06µs 99.3 KElem/sec N/A N/A
stdb_raw/mem/iterate/person/unique/count=100 11.2±0.10µs 86.9 KElem/sec N/A N/A

Please sign in to comment.