Skip to content

Commit

Permalink
Make both TX offset counters agree (#1332)
Browse files Browse the repository at this point in the history
* Make both TX offset counters agree

Prior to this commit, `CommittedState::next_tx_offset` got out of sync
with the commitlog/durability's notion of the tx offset,
because the former counted all committed TXes,
while the latter excluded certain empty TXes
(namely, empty TXes
which were not `__identity_connected__` or `__identity_disconnected__` reducers).

With this commit, the skipping logic is moved earlier into `CommittedState`,
so that it can maintain a counter consistent with that used by the commitlog.

* Remove duplicated increment
  • Loading branch information
gefjon authored Jun 4, 2024
1 parent db34ff6 commit 697a581
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,36 @@ impl CommittedState {
table.get_row_ref(&self.blob_store, row_ptr).unwrap()
}

/// True if the transaction `(tx_data, ctx)` will be written to the commitlog,
/// and therefore consumes a value from `self.next_tx_offset`.
///
/// A TX is written to the logs if any of the following holds:
/// - The TX inserted at least one row.
/// - The TX deleted at least one row.
/// - The TX was the result of the reducers `__identity_connected__` or `__identity_disconnected__`.
fn tx_consumes_offset(&self, tx_data: &TxData, ctx: &ExecutionContext) -> bool {
// Avoid appending transactions to the commitlog which don't modify
// any tables.
//
// An exception are connect / disconnect calls, which we always want
// paired in the log, so as to be able to disconnect clients
// automatically after a server crash. See:
// [`crate::host::ModuleHost::call_identity_connected_disconnected`]
//
// Note that this may change in the future: some analytics and/or
// timetravel queries may benefit from seeing all inputs, even if
// the database state did not change.
tx_data.inserts().any(|(_, inserted_rows)| !inserted_rows.is_empty())
|| tx_data.deletes().any(|(_, deleted_rows)| !deleted_rows.is_empty())
|| matches!(
ctx.reducer_context().map(|rcx| rcx.name.strip_prefix("__identity_")),
Some(Some("connected__" | "disconnected__"))
)
}

pub fn merge(&mut self, tx_state: TxState, ctx: &ExecutionContext) -> TxData {
let mut tx_data = TxData::default();

self.next_tx_offset += 1;

// First, apply deletes. This will free up space in the committed tables.
self.merge_apply_deletes(&mut tx_data, tx_state.delete_tables, ctx);

Expand All @@ -373,6 +398,13 @@ impl CommittedState {

self.merge_apply_inserts(&mut tx_data, tx_state.insert_tables, tx_state.blob_store, ctx);

// If the TX will be logged, record its projected tx offset,
// then increment the counter.
if self.tx_consumes_offset(&tx_data, ctx) {
tx_data.set_tx_offset(self.next_tx_offset);
self.next_tx_offset += 1;
}

tx_data
}

Expand Down
19 changes: 19 additions & 0 deletions crates/core/src/db/datastore/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,29 @@ pub struct TxData {
/// Map of all `TableId`s in both `inserts` and `deletes` to their
/// corresponding table name.
tables: IntMap<TableId, String>,
/// Tx offset of the transaction which performed these operations.
///
/// `None` implies that `inserts` and `deletes` are both empty,
/// but `Some` does not necessarily imply that either is non-empty.
tx_offset: Option<u64>,
// TODO: Store an `Arc<String>` or equivalent instead.
}

impl TxData {
/// Set `tx_offset` as the expected on-disk transaction offset of this transaction.
pub fn set_tx_offset(&mut self, tx_offset: u64) {
self.tx_offset = Some(tx_offset);
}

/// Read the expected on-disk transaction offset of this transaction.
///
/// `None` implies that this [`TxData`] contains zero inserted or deleted rows,
/// but the inverse is not necessarily true;
/// a [`TxData`] may have a `tx_offset` but no row operations.
pub fn tx_offset(&self) -> Option<u64> {
self.tx_offset
}

/// Set `rows` as the inserted rows for `(table_id, table_name)`.
pub fn set_inserts_for_table(&mut self, table_id: TableId, table_name: &str, rows: Arc<[ProductValue]>) {
self.inserts.insert(table_id, rows);
Expand Down
90 changes: 42 additions & 48 deletions crates/core/src/db/relational_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use super::db_metrics::DB_METRICS;
use super::relational_operators::Relation;
use crate::config::DatabaseConfig;
use crate::error::{DBError, DatabaseError, TableError};
use crate::execution_context::{ExecutionContext, ReducerContext};
use crate::execution_context::ExecutionContext;
use crate::util::slow::SlowQueryConfig;
use fs2::FileExt;
use parking_lot::RwLock;
Expand Down Expand Up @@ -365,63 +365,57 @@ impl RelationalDB {
Ok(Some((tx_data, tx)))
}

/// If `(tx_data, ctx)` should be appended to the commitlog, do so.
///
/// Note that by this stage,
/// [`crate::db::datastore::locking_tx_datastore::committed_state::tx_consumes_offset`]
/// has already decided based on the reducer and operations whether the transaction should be appended;
/// this method is responsible only for reading its decision out of the `tx_data`
/// and calling `durability.append_tx`.
fn do_durability(durability: &dyn Durability<TxData = Txdata>, ctx: &ExecutionContext, tx_data: &TxData) {
use commitlog::payload::{
txdata::{Mutations, Ops},
Txdata,
};

let inserts: Box<_> = tx_data
.inserts()
.map(|(table_id, rowdata)| Ops {
table_id: *table_id,
rowdata: rowdata.clone(),
})
.collect();
let deletes: Box<_> = tx_data
.deletes()
.map(|(table_id, rowdata)| Ops {
table_id: *table_id,
rowdata: rowdata.clone(),
})
.collect();

// Avoid appending transactions to the commitlog which don't modify
// any tables.
//
// An exception ar connect / disconnect calls, which we always want
// paired in the log, so as to be able to disconnect clients
// automatically after a server crash. See:
// [`crate::host::ModuleHost::call_identity_connected_disconnected`]
//
// Note that this may change in the future: some analytics and/or
// timetravel queries may benefit from seeing all inputs, even if
// the database state did not change.
let is_noop = || inserts.is_empty() && deletes.is_empty();
let is_connect_disconnect = |ctx: &ReducerContext| {
matches!(
ctx.name.strip_prefix("__identity_"),
Some("connected__" | "disconnected__")
)
};
let inputs = ctx
.reducer_context()
.and_then(|rcx| (!is_noop() || is_connect_disconnect(rcx)).then(|| rcx.into()));

let txdata = Txdata {
inputs,
outputs: None,
mutations: Some(Mutations {
inserts,
deletes,
truncates: [].into(),
}),
};
if tx_data.tx_offset().is_some() {
let inserts: Box<_> = tx_data
.inserts()
.map(|(table_id, rowdata)| Ops {
table_id: *table_id,
rowdata: rowdata.clone(),
})
.collect();
let deletes: Box<_> = tx_data
.deletes()
.map(|(table_id, rowdata)| Ops {
table_id: *table_id,
rowdata: rowdata.clone(),
})
.collect();

let inputs = ctx.reducer_context().map(|rcx| rcx.into());

let txdata = Txdata {
inputs,
outputs: None,
mutations: Some(Mutations {
inserts,
deletes,
truncates: [].into(),
}),
};

if !txdata.is_empty() {
log::trace!("append {txdata:?}");
// TODO: Should measure queuing time + actual write
durability.append_tx(txdata);
} else {
debug_assert!(tx_data.inserts().all(|(_, inserted_rows)| inserted_rows.is_empty()));
debug_assert!(tx_data.deletes().all(|(_, deleted_rows)| deleted_rows.is_empty()));
debug_assert!(!matches!(
ctx.reducer_context().map(|rcx| rcx.name.strip_prefix("__identity_")),
Some(Some("connected__" | "disconnected__"))
));
}
}

Expand Down

3 comments on commit 697a581

@github-actions
Copy link

@github-actions github-actions bot commented on 697a581 Jun 4, 2024

Choose a reason for hiding this comment

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

Bot test failed. Please check the workflow run for details.

@github-actions
Copy link

@github-actions github-actions bot commented on 697a581 Jun 4, 2024

Choose a reason for hiding this comment

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

Criterion benchmark results

Criterion benchmark report

YOU SHOULD PROBABLY IGNORE THESE RESULTS.

Criterion is a wall time based benchmarking system that is extremely noisy when run on CI. We collect these results for longitudinal analysis, but they are not reliable for comparing individual PRs.

Go look at the callgrind report instead.

empty

db on disk new latency old latency new throughput old throughput
sqlite 💿 413.1±1.67ns 428.6±1.74ns - -
sqlite 🧠 407.1±2.46ns 417.9±1.36ns - -
stdb_raw 💿 727.9±0.65ns 721.5±0.68ns - -
stdb_raw 🧠 723.6±1.56ns 691.1±0.59ns - -

insert_1

db on disk schema indices preload new latency old latency new throughput old throughput

insert_bulk

db on disk schema indices preload count new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str btree_each_column 2048 256 516.5±0.91µs 523.3±41.33µs 1936 tx/sec 1910 tx/sec
sqlite 💿 u32_u64_str unique_0 2048 256 137.0±0.39µs 141.4±12.49µs 7.1 Ktx/sec 6.9 Ktx/sec
sqlite 💿 u32_u64_u64 btree_each_column 2048 256 418.6±0.23µs 412.2±0.29µs 2.3 Ktx/sec 2.4 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 2048 256 122.2±0.49µs 123.3±0.65µs 8.0 Ktx/sec 7.9 Ktx/sec
sqlite 🧠 u32_u64_str btree_each_column 2048 256 445.2±0.42µs 443.8±1.96µs 2.2 Ktx/sec 2.2 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 2048 256 121.1±0.70µs 120.0±0.49µs 8.1 Ktx/sec 8.1 Ktx/sec
sqlite 🧠 u32_u64_u64 btree_each_column 2048 256 366.2±0.56µs 360.4±0.66µs 2.7 Ktx/sec 2.7 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 2048 256 103.9±0.72µs 104.1±0.38µs 9.4 Ktx/sec 9.4 Ktx/sec
stdb_raw 💿 u32_u64_str btree_each_column 2048 256 571.3±19.63µs 487.9±9.94µs 1750 tx/sec 2.0 Ktx/sec
stdb_raw 💿 u32_u64_str unique_0 2048 256 485.6±57.32µs 392.6±17.17µs 2.0 Ktx/sec 2.5 Ktx/sec
stdb_raw 💿 u32_u64_u64 btree_each_column 2048 256 378.1±7.82µs 372.4±12.73µs 2.6 Ktx/sec 2.6 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 2048 256 341.0±10.05µs 350.6±9.26µs 2.9 Ktx/sec 2.8 Ktx/sec
stdb_raw 🧠 u32_u64_str btree_each_column 2048 256 310.3±0.26µs 312.1±0.60µs 3.1 Ktx/sec 3.1 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 2048 256 239.4±0.37µs 235.7±0.60µs 4.1 Ktx/sec 4.1 Ktx/sec
stdb_raw 🧠 u32_u64_u64 btree_each_column 2048 256 245.8±0.25µs 250.0±0.23µs 4.0 Ktx/sec 3.9 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 2048 256 219.0±0.86µs 217.4±0.15µs 4.5 Ktx/sec 4.5 Ktx/sec

iterate

db on disk schema indices new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str unique_0 20.3±0.11µs 18.9±0.17µs 48.0 Ktx/sec 51.5 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 19.1±0.26µs 16.8±0.05µs 51.2 Ktx/sec 58.2 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 19.6±0.10µs 17.4±0.03µs 49.7 Ktx/sec 56.2 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 18.0±0.32µs 15.9±0.22µs 54.4 Ktx/sec 61.6 Ktx/sec
stdb_raw 💿 u32_u64_str unique_0 4.9±0.00µs 3.8±0.01µs 201.1 Ktx/sec 255.6 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 4.7±0.00µs 3.7±0.00µs 206.6 Ktx/sec 262.5 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 4.9±0.00µs 3.8±0.00µs 201.0 Ktx/sec 257.1 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 4.7±0.00µs 3.7±0.00µs 206.4 Ktx/sec 264.0 Ktx/sec

find_unique

db on disk key type preload new latency old latency new throughput old throughput

filter

db on disk key type index strategy load count new latency old latency new throughput old throughput
sqlite 💿 string index 2048 256 66.3±0.26µs 65.6±0.16µs 14.7 Ktx/sec 14.9 Ktx/sec
sqlite 💿 u64 index 2048 256 63.6±0.06µs 62.9±0.12µs 15.3 Ktx/sec 15.5 Ktx/sec
sqlite 🧠 string index 2048 256 64.4±0.13µs 64.1±0.11µs 15.2 Ktx/sec 15.2 Ktx/sec
sqlite 🧠 u64 index 2048 256 59.7±0.07µs 58.4±0.17µs 16.3 Ktx/sec 16.7 Ktx/sec
stdb_raw 💿 string index 2048 256 5.1±0.00µs 5.1±0.00µs 191.7 Ktx/sec 189.7 Ktx/sec
stdb_raw 💿 u64 index 2048 256 5.0±0.00µs 5.1±0.00µs 194.7 Ktx/sec 192.4 Ktx/sec
stdb_raw 🧠 string index 2048 256 5.1±0.00µs 5.1±0.00µs 191.9 Ktx/sec 190.5 Ktx/sec
stdb_raw 🧠 u64 index 2048 256 5.0±0.00µs 5.0±0.00µs 194.7 Ktx/sec 193.6 Ktx/sec

serialize

schema format count new latency old latency new throughput old throughput
u32_u64_str bflatn_to_bsatn_fast_path 100 3.7±0.01µs 3.7±0.01µs 25.8 Mtx/sec 25.8 Mtx/sec
u32_u64_str bflatn_to_bsatn_slow_path 100 3.5±0.01µs 3.5±0.00µs 27.1 Mtx/sec 27.6 Mtx/sec
u32_u64_str bsatn 100 2.5±0.03µs 2.3±0.08µs 37.4 Mtx/sec 41.3 Mtx/sec
u32_u64_str json 100 4.8±0.07µs 5.1±0.06µs 20.0 Mtx/sec 18.5 Mtx/sec
u32_u64_str product_value 100 1014.4±1.46ns 1016.4±0.41ns 94.0 Mtx/sec 93.8 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_fast_path 100 1111.4±33.47ns 1119.3±1.86ns 85.8 Mtx/sec 85.2 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_slow_path 100 2.9±0.01µs 2.9±0.01µs 33.2 Mtx/sec 33.4 Mtx/sec
u32_u64_u64 bsatn 100 1737.1±34.97ns 1770.9±54.03ns 54.9 Mtx/sec 53.9 Mtx/sec
u32_u64_u64 json 100 3.2±0.09µs 3.4±0.06µs 30.3 Mtx/sec 27.9 Mtx/sec
u32_u64_u64 product_value 100 1008.4±0.32ns 1010.1±1.02ns 94.6 Mtx/sec 94.4 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_fast_path 100 887.8±4.51ns 901.3±1.61ns 107.4 Mtx/sec 105.8 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_slow_path 100 2.9±0.01µs 2.9±0.01µs 33.1 Mtx/sec 33.2 Mtx/sec
u64_u64_u32 bsatn 100 1633.7±52.59ns 1682.0±32.15ns 58.4 Mtx/sec 56.7 Mtx/sec
u64_u64_u32 json 100 3.4±0.05µs 3.4±0.03µs 28.4 Mtx/sec 27.7 Mtx/sec
u64_u64_u32 product_value 100 1010.0±0.60ns 1009.8±0.44ns 94.4 Mtx/sec 94.4 Mtx/sec

stdb_module_large_arguments

arg size new latency old latency new throughput old throughput
64KiB 90.9±4.78µs 84.5±9.34µs - -

stdb_module_print_bulk

line count new latency old latency new throughput old throughput
1 46.9±3.83µs 39.9±3.88µs - -
100 362.4±136.13µs 368.4±129.35µs - -
1000 2.9±0.01ms 2.2±0.25ms - -

remaining

name new latency old latency new throughput old throughput
sqlite/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 46.2±0.21µs 43.9±0.07µs 21.1 Ktx/sec 22.2 Ktx/sec
sqlite/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 40.3±0.11µs 38.8±0.07µs 24.2 Ktx/sec 25.1 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 38.9±0.24µs 37.3±0.06µs 25.1 Ktx/sec 26.2 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 34.8±0.12µs 33.7±0.16µs 28.1 Ktx/sec 29.0 Ktx/sec
stdb_module/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 1282.8±9.17µs 1296.3±24.38µs 779 tx/sec 771 tx/sec
stdb_module/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 969.7±11.50µs 1018.7±33.78µs 1031 tx/sec 981 tx/sec
stdb_raw/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 637.5±12.13µs 639.0±29.48µs 1568 tx/sec 1565 tx/sec
stdb_raw/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 441.2±4.39µs 499.8±9.98µs 2.2 Ktx/sec 2000 tx/sec
stdb_raw/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 389.4±0.17µs 388.6±0.26µs 2.5 Ktx/sec 2.5 Ktx/sec
stdb_raw/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 352.5±0.29µs 349.2±0.12µs 2.8 Ktx/sec 2.8 Ktx/sec

@github-actions
Copy link

@github-actions github-actions bot commented on 697a581 Jun 4, 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 6181 6077 1.71% 7047 7003 0.63%
sqlite 5676 5676 0.00% 6226 6190 0.58%

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 79667 79559 0.14% 80151 80163 -0.01%
stdb_raw u32_u64_str no_index 64 128 2 string 121954 121846 0.09% 122600 122588 0.01%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 24364 24260 0.43% 24712 24840 -0.52%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 25403 25299 0.41% 25853 25941 -0.34%
sqlite u32_u64_str no_index 64 128 2 string 143663 143663 0.00% 145147 145227 -0.06%
sqlite u32_u64_str no_index 64 128 1 u64 123004 123004 0.00% 124282 124310 -0.02%
sqlite u32_u64_str btree_each_column 64 128 2 string 133526 133526 0.00% 135288 135196 0.07%
sqlite u32_u64_str btree_each_column 64 128 1 u64 130321 130321 0.00% 131901 131777 0.09%

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 889313 890669 -0.15% 940353 943257 -0.31%
stdb_raw u32_u64_str btree_each_column 64 128 1017288 1018320 -0.10% 1040068 1050376 -0.98%
sqlite u32_u64_str unique_0 64 128 398417 398417 0.00% 418633 420339 -0.41%
sqlite u32_u64_str btree_each_column 64 128 971490 971490 0.00% 1013308 1009496 0.38%

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 152312 152208 0.07% 152386 152322 0.04%
stdb_raw u32_u64_str unique_0 64 16286 16191 0.59% 16356 16305 0.31%
sqlite u32_u64_str unique_0 1024 1046895 1046901 -0.00% 1050255 1050331 -0.01%
sqlite u32_u64_str unique_0 64 75041 75041 0.00% 76173 76217 -0.06%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47438 47438 0.00% 50060 50026 0.07%
64 bsatn 25717 25717 0.00% 28097 28131 -0.12%
16 bsatn 8118 8118 0.00% 9546 9580 -0.35%
16 json 12142 12142 0.00% 14012 13978 0.24%

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 20341851 20361740 -0.10% 20920151 20938330 -0.09%
stdb_raw u32_u64_str unique_0 64 128 1308334 1309307 -0.07% 1381896 1381787 0.01%
sqlite u32_u64_str unique_0 1024 1024 1802033 1802033 0.00% 1811337 1811373 -0.00%
sqlite u32_u64_str unique_0 64 128 128569 128569 0.00% 131537 131525 0.01%
On-disk benchmarks

callgrind: empty transaction

db total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw 6183 6442 -4.02% 7037 7378 -4.62%
sqlite 5718 5718 0.00% 6286 6250 0.58%

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 79669 79924 -0.32% 80125 80572 -0.55%
stdb_raw u32_u64_str no_index 64 128 2 string 121935 122190 -0.21% 122697 123064 -0.30%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 24366 24625 -1.05% 24698 25205 -2.01%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 25583 25666 -0.32% 26033 26332 -1.14%
sqlite u32_u64_str no_index 64 128 1 u64 124925 124925 0.00% 126591 126659 -0.05%
sqlite u32_u64_str no_index 64 128 2 string 145584 145584 0.00% 147524 147452 0.05%
sqlite u32_u64_str btree_each_column 64 128 1 u64 132417 132417 0.00% 134327 134275 0.04%
sqlite u32_u64_str btree_each_column 64 128 2 string 135576 135576 0.00% 137668 137608 0.04%

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 839548 840749 -0.14% 858398 861435 -0.35%
stdb_raw u32_u64_str btree_each_column 64 128 965822 967220 -0.14% 986676 998830 -1.22%
sqlite u32_u64_str unique_0 64 128 415980 415965 0.00% 435666 437479 -0.41%
sqlite u32_u64_str btree_each_column 64 128 1022065 1022065 0.00% 1062683 1059069 0.34%

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 152314 152573 -0.17% 152384 152727 -0.22%
stdb_raw u32_u64_str unique_0 64 16297 16556 -1.56% 16367 16710 -2.05%
sqlite u32_u64_str unique_0 1024 1049963 1049963 0.00% 1053751 1053803 -0.00%
sqlite u32_u64_str unique_0 64 76813 76813 0.00% 78301 78305 -0.01%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47438 47438 0.00% 50060 50026 0.07%
64 bsatn 25717 25717 0.00% 28097 28131 -0.12%
16 bsatn 8118 8118 0.00% 9546 9580 -0.35%
16 json 12142 12142 0.00% 14012 13978 0.24%

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 19294708 19312312 -0.09% 19954888 19971872 -0.09%
stdb_raw u32_u64_str unique_0 64 128 1251580 1252870 -0.10% 1292730 1293234 -0.04%
sqlite u32_u64_str unique_0 1024 1024 1809829 1809829 0.00% 1818573 1818609 -0.00%
sqlite u32_u64_str unique_0 64 128 132717 132717 0.00% 135809 135821 -0.01%

Please sign in to comment.