Skip to content

Commit

Permalink
Fix "identity not yet recieved" intermittent failure in tests (#445)
Browse files Browse the repository at this point in the history
This error turns out to have been a legitimate, albeit rare, race condition,
which could have (but apparently didn't) manifested in user code.

The cause, ultimately, was holding locks for too-short scopes
while initializing the connection.
It was possible for a new connection to receive and completely process
its `IdentityToken` message before calling `maybe_set_credentials`,
which would then clobber the received identity.

This is now fixed (hopefully) by holding the `CredentialStore` lock
for the duration of `BackgroundDbConnection::connect`.
Two other locks, on `ClientCache` and `ReducerCallbacks`,
are also newly held for the duration to avoid similar issues.

In addition, this commit adds a call to `disconnect` to the beginning of `connect`.
This will prevent pathological user code
which connects twice in a row without an intervening disconnect
from encountering bizarre errors
caused by the first connection's background workers staying active.

This commit also bumps the `RUST_LOG` env variable for the SDK test clients to `trace`,
and adds several trace-level logs to the SDK,
which were instrumental in pinning down the failure.
This does mean that log output of failed SDK tests will now be much noisier.
  • Loading branch information
gefjon authored Oct 23, 2023
1 parent b78ae84 commit 60b77ae
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 29 deletions.
60 changes: 36 additions & 24 deletions crates/sdk/src/background_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,37 @@ impl BackgroundDbConnection {
IntoUri: TryInto<http::Uri>,
<IntoUri as TryInto<http::Uri>>::Error: std::error::Error + Send + Sync + 'static,
{
let client_address = {
let mut lock = self.credentials.lock().expect("CredentialStore Mutex is poisoned");
lock.get_or_init_address()
};
// Disconnect to prevent any outstanding messages from contending for unique resources,
// i.e. the reducer callbacks, credential store and client cache.
self.disconnect();

// Hold all internal locks for the duration of this method,
// to prevent races if the connection starts receiving messages
// before this method returns.
let mut reducer_callbacks_lock = self
.reducer_callbacks
.lock()
.expect("ReducerCallbacks Mutex is poisoned");
let mut credentials_lock = self.credentials.lock().expect("CredentialStore Mutex is poisoned");
let mut client_cache_lock = self.client_cache.lock().expect("ClientCache Mutex is poisoned");

// Specialize the reducer callbacks for this module.
// Registering callbacks doesn't require the module, but firing them does,
// in order to parse arguments with appropriate types.
reducer_callbacks_lock.set_module(module.clone());

// If credentials were passed to connect, store them in the credential store.
// If not, unset any stale credentials in the credential store.
credentials_lock.maybe_set_credentials(credentials.clone());

let client_address = credentials_lock.get_or_init_address();

// Construct a new client cache specialized for this module.
// The client cache needs to know the module
// in order to parse rows and issue callbacks with appropriate types.
let client_cache = Arc::new(ClientCache::new(module.clone()));
*client_cache_lock = Some(client_cache);

// `block_in_place` is required here, as tokio won't allow us to call
// `block_on` if it would block the current thread of an outer runtime
let connection = tokio::task::block_in_place(|| {
Expand All @@ -328,41 +355,26 @@ impl BackgroundDbConnection {
))
})?;

let client_cache = Arc::new(ClientCache::new(module.clone()));

{
// Set the global `CLIENT_CACHE` to our newly-constructed cache.
// Do this inside a short scope to avoid holding the lock unnecessarily.
let mut client_cache_lock = self.client_cache.lock().expect("ClientCache mutex is poisoned");
*client_cache_lock = Some(client_cache);
}

let (websocket_loop_handle, recv_chan, send_chan) = connection.spawn_message_loop(&self.handle);
let recv_handle = self.spawn_receiver(recv_chan, self.client_cache.clone());

self.send_chan = Some(send_chan);
self.websocket_loop_handle = Some(websocket_loop_handle);
self.recv_handle = Some(recv_handle);

self.reducer_callbacks
.lock()
.expect("ReducerCallbacks Mutex is poisoned")
.set_module(module);
self.credentials
.lock()
.expect("CredentialStore Mutex is poisoned")
.maybe_set_credentials(credentials);

Ok(())
}

pub fn disconnect(&mut self) {
self.send_chan = None;

// `block_in_place` over `block_on` allows us to wait for a future to complete
// regardless of whether we're currently running in an `async` task or not.
if let Some(h) = self.websocket_loop_handle.take() {
let _ = self.handle.block_on(h);
let _ = tokio::task::block_in_place(|| self.handle.block_on(h));
}
if let Some(h) = self.recv_handle.take() {
let _ = self.handle.block_on(h);
let _ = tokio::task::block_in_place(|| self.handle.block_on(h));
}
}

Expand Down
29 changes: 25 additions & 4 deletions crates/sdk/src/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ impl<Args: OwnedArgs> CallbackMap<Args> {
// Enter a dynamic context where `CURRENT_STATE`
// is the state which caused this callback invocation.
let _guard = CurrentStateGuard::with_current_state(db_state);
log::trace!(
"CallbackMap worker: received invoke message for args {} and got state guard",
std::any::type_name::<Args>(),
);

// We're invoking several callbacks, so none of them may consume `args`.
let borrowed = args.borrow();
Expand Down Expand Up @@ -408,6 +412,7 @@ impl<Args: OwnedArgs> CallbackMap<Args> {

/// Invoke each currently-registered callback in `self` with `args`.
fn invoke(&self, args: Args, db_state: ClientCacheView) {
log::trace!("CallbackMap: invoking for args type {}", std::any::type_name::<Args>());
self.send
.unbounded_send(CallbackMessage::Invoke { args, db_state })
// TODO: properly handle this error somehow
Expand Down Expand Up @@ -857,6 +862,15 @@ impl CredentialStore {
///
/// Do not invoke on-connect callbacks.
pub(crate) fn maybe_set_credentials(&mut self, credentials: Option<Credentials>) {
if let Some(creds) = &credentials {
log::trace!(
"maybe_set_credentials: Setting stored credentials to Some({:?})",
creds.identity,
);
} else {
log::trace!("maybe_set_credentials: Setting stored credentials to None");
}

self.credentials = credentials;
}

Expand Down Expand Up @@ -915,12 +929,16 @@ impl CredentialStore {
return;
}

let identity = Identity::from_bytes(identity);
log::trace!("handle_identity_token: received identity {:?}", identity);

let creds = Credentials {
identity: Identity::from_bytes(identity),
identity,
token: Token { string: token },
};

let address = Address::from_slice(&address);
log::trace!("handle_identity_token: received address {:?}", address);

if Some(address) != self.address {
log::error!(
Expand All @@ -930,8 +948,6 @@ impl CredentialStore {
);
}

self.callbacks.invoke((creds.clone(), address), state);

if let Some(existing_creds) = &self.credentials {
// If we already have credentials, make sure that they match. Log an error if
// they don't.
Expand All @@ -944,10 +960,15 @@ impl CredentialStore {
creds,
existing_creds,
);
} else {
log::trace!("handle_identity_token: received creds match local record.");
}
} else {
self.credentials = Some(creds);
self.credentials = Some(creds.clone());
log::trace!("handle_identity_token: storing new credentials");
}

self.callbacks.invoke((creds.clone(), address), state);
}

/// Return the current connection's `Identity`, if one is stored.
Expand Down
2 changes: 1 addition & 1 deletion crates/testing/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ fn run_client(run_command: &str, client_project: &str, db_name: &str, test_name:
.dir(client_project)
.env(TEST_CLIENT_PROJECT_ENV_VAR, client_project)
.env(TEST_DB_NAME_ENV_VAR, db_name)
.env("RUST_LOG", "info")
.env("RUST_LOG", "trace")
.stderr_to_stdout()
.stdout_capture()
.unchecked()
Expand Down

1 comment on commit 60b77ae

@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 results

Benchmark Report

Legend:

  • load: number of rows pre-loaded into the database
  • count: number of rows touched by the transaction
  • index types:
    • unique: a single index on the id column
    • non_unique: no indexes
    • multi_index: non-unique index on every column
  • schemas:
    • person(id: u32, name: String, age: u64)
    • location(id: u32, x: u64, y: u64)

All throughputs are single-threaded.

Empty transaction

db on disk new latency old latency new throughput old throughput
sqlite 💿 440.6±2.18ns 441.4±2.13ns - -
sqlite 🧠 433.6±1.07ns 433.5±2.05ns - -
stdb_module 💿 15.8±0.42µs 15.5±0.41µs - -
stdb_module 🧠 16.4±0.58µs 15.8±0.41µs - -
stdb_raw 💿 102.0±0.86ns 101.2±0.70ns - -
stdb_raw 🧠 101.7±0.78ns 101.2±0.24ns - -

Single-row insertions

db on disk schema index type load new latency old latency new throughput old throughput
sqlite 💿 location multi_index 0 14.6±0.04µs 14.9±0.93µs 66.9 Ktx/sec 65.5 Ktx/sec
sqlite 💿 location multi_index 1000 15.9±0.12µs 16.0±0.17µs 61.3 Ktx/sec 61.0 Ktx/sec
sqlite 💿 location non_unique 0 7.3±0.05µs 7.4±0.54µs 134.0 Ktx/sec 132.2 Ktx/sec
sqlite 💿 location non_unique 1000 7.0±0.03µs 7.1±0.07µs 138.5 Ktx/sec 138.1 Ktx/sec
sqlite 💿 location unique 0 7.3±0.27µs 7.4±0.44µs 134.0 Ktx/sec 132.4 Ktx/sec
sqlite 💿 location unique 1000 7.1±0.10µs 7.2±0.04µs 136.6 Ktx/sec 135.6 Ktx/sec
sqlite 💿 person multi_index 0 14.4±0.06µs 15.3±4.88µs 67.7 Ktx/sec 63.8 Ktx/sec
sqlite 💿 person multi_index 1000 16.1±0.19µs 16.3±0.11µs 60.5 Ktx/sec 60.1 Ktx/sec
sqlite 💿 person non_unique 0 7.4±0.04µs 7.4±0.04µs 131.4 Ktx/sec 132.2 Ktx/sec
sqlite 💿 person non_unique 1000 7.3±0.04µs 7.4±0.06µs 134.5 Ktx/sec 132.4 Ktx/sec
sqlite 💿 person unique 0 7.5±0.38µs 7.5±0.31µs 130.6 Ktx/sec 130.9 Ktx/sec
sqlite 💿 person unique 1000 7.4±0.04µs 7.4±0.05µs 132.2 Ktx/sec 131.8 Ktx/sec
sqlite 🧠 location multi_index 0 4.1±0.01µs 4.1±0.01µs 237.0 Ktx/sec 236.4 Ktx/sec
sqlite 🧠 location multi_index 1000 5.3±0.03µs 5.4±0.10µs 185.7 Ktx/sec 180.8 Ktx/sec
sqlite 🧠 location non_unique 0 1876.0±6.14ns 1845.5±5.19ns 520.6 Ktx/sec 529.2 Ktx/sec
sqlite 🧠 location non_unique 1000 1931.3±12.26ns 1933.7±9.41ns 505.6 Ktx/sec 505.0 Ktx/sec
sqlite 🧠 location unique 0 1850.0±6.98ns 1839.9±4.84ns 527.9 Ktx/sec 530.8 Ktx/sec
sqlite 🧠 location unique 1000 1958.9±6.41ns 1975.5±15.25ns 498.5 Ktx/sec 494.3 Ktx/sec
sqlite 🧠 person multi_index 0 3.7±0.01µs 3.7±0.01µs 261.8 Ktx/sec 261.5 Ktx/sec
sqlite 🧠 person multi_index 1000 5.5±0.02µs 5.5±0.05µs 178.0 Ktx/sec 176.8 Ktx/sec
sqlite 🧠 person non_unique 0 1957.7±6.77ns 1938.3±7.11ns 498.8 Ktx/sec 503.8 Ktx/sec
sqlite 🧠 person non_unique 1000 2.0±0.02µs 2.0±0.01µs 480.6 Ktx/sec 480.8 Ktx/sec
sqlite 🧠 person unique 0 1949.8±6.81ns 1945.9±8.00ns 500.8 Ktx/sec 501.9 Ktx/sec
sqlite 🧠 person unique 1000 2.1±0.01µs 2.0±0.01µs 473.3 Ktx/sec 476.5 Ktx/sec
stdb_module 💿 location multi_index 0 36.6±3.35µs 38.1±3.17µs 26.7 Ktx/sec 25.6 Ktx/sec
stdb_module 💿 location multi_index 1000 263.4±2.80µs 132.6±53.82µs 3.7 Ktx/sec 7.4 Ktx/sec
stdb_module 💿 location non_unique 0 32.8±3.10µs 32.9±3.38µs 29.8 Ktx/sec 29.7 Ktx/sec
stdb_module 💿 location non_unique 1000 181.4±77.71µs 242.8±47.30µs 5.4 Ktx/sec 4.0 Ktx/sec
stdb_module 💿 location unique 0 34.7±3.60µs 32.6±2.82µs 28.1 Ktx/sec 29.9 Ktx/sec
stdb_module 💿 location unique 1000 122.7±16.93µs 96.2±15.97µs 8.0 Ktx/sec 10.1 Ktx/sec
stdb_module 💿 person multi_index 0 46.9±4.65µs 44.5±4.72µs 20.8 Ktx/sec 21.9 Ktx/sec
stdb_module 💿 person multi_index 1000 283.9±4.67µs 174.1±73.51µs 3.4 Ktx/sec 5.6 Ktx/sec
stdb_module 💿 person non_unique 0 32.4±2.43µs 30.9±2.90µs 30.2 Ktx/sec 31.6 Ktx/sec
stdb_module 💿 person non_unique 1000 172.9±18.03µs 150.4±19.87µs 5.6 Ktx/sec 6.5 Ktx/sec
stdb_module 💿 person unique 0 39.2±3.01µs 37.5±2.71µs 24.9 Ktx/sec 26.0 Ktx/sec
stdb_module 💿 person unique 1000 248.2±4.13µs 178.7±75.77µs 3.9 Ktx/sec 5.5 Ktx/sec
stdb_module 🧠 location multi_index 0 30.9±3.14µs 29.2±2.13µs 31.6 Ktx/sec 33.5 Ktx/sec
stdb_module 🧠 location multi_index 1000 159.8±86.50µs 105.3±11.80µs 6.1 Ktx/sec 9.3 Ktx/sec
stdb_module 🧠 location non_unique 0 26.1±1.61µs 26.5±2.03µs 37.4 Ktx/sec 36.8 Ktx/sec
stdb_module 🧠 location non_unique 1000 204.3±36.40µs 259.7±18.86µs 4.8 Ktx/sec 3.8 Ktx/sec
stdb_module 🧠 location unique 0 31.0±2.70µs 28.3±2.67µs 31.5 Ktx/sec 34.6 Ktx/sec
stdb_module 🧠 location unique 1000 95.2±7.14µs 191.8±53.75µs 10.3 Ktx/sec 5.1 Ktx/sec
stdb_module 🧠 person multi_index 0 32.9±2.43µs 35.3±2.25µs 29.7 Ktx/sec 27.7 Ktx/sec
stdb_module 🧠 person multi_index 1000 265.4±5.62µs 125.7±2.22µs 3.7 Ktx/sec 7.8 Ktx/sec
stdb_module 🧠 person non_unique 0 27.2±1.68µs 28.8±2.05µs 36.0 Ktx/sec 33.9 Ktx/sec
stdb_module 🧠 person non_unique 1000 166.2±19.84µs 136.3±6.14µs 5.9 Ktx/sec 7.2 Ktx/sec
stdb_module 🧠 person unique 0 30.2±1.90µs 29.7±1.60µs 32.3 Ktx/sec 32.9 Ktx/sec
stdb_module 🧠 person unique 1000 101.0±4.48µs 142.6±26.40µs 9.7 Ktx/sec 6.8 Ktx/sec
stdb_raw 💿 location multi_index 0 5.0±0.05µs 4.9±0.23µs 196.5 Ktx/sec 198.3 Ktx/sec
stdb_raw 💿 location multi_index 1000 7.1±0.15µs 23.3±162.96µs 136.9 Ktx/sec 41.9 Ktx/sec
stdb_raw 💿 location non_unique 0 3.4±0.01µs 3.4±0.02µs 285.3 Ktx/sec 284.4 Ktx/sec
stdb_raw 💿 location non_unique 1000 4.6±0.15µs 6.9±24.99µs 213.6 Ktx/sec 141.0 Ktx/sec
stdb_raw 💿 location unique 0 4.2±0.01µs 4.1±0.02µs 234.9 Ktx/sec 235.7 Ktx/sec
stdb_raw 💿 location unique 1000 15.0±88.68µs 16.9±110.80µs 65.1 Ktx/sec 57.7 Ktx/sec
stdb_raw 💿 person multi_index 0 8.5±0.18µs 8.4±0.21µs 114.8 Ktx/sec 116.4 Ktx/sec
stdb_raw 💿 person multi_index 1000 40.0±287.79µs 23.7±125.76µs 24.4 Ktx/sec 41.3 Ktx/sec
stdb_raw 💿 person non_unique 0 4.0±0.01µs 4.0±0.01µs 246.5 Ktx/sec 245.4 Ktx/sec
stdb_raw 💿 person non_unique 1000 17.7±124.03µs 15.4±101.27µs 55.0 Ktx/sec 63.3 Ktx/sec
stdb_raw 💿 person unique 0 5.7±0.17µs 5.7±0.48µs 171.9 Ktx/sec 172.1 Ktx/sec
stdb_raw 💿 person unique 1000 23.0±153.62µs 7.6±0.11µs 42.4 Ktx/sec 128.4 Ktx/sec
stdb_raw 🧠 location multi_index 0 3.6±0.01µs 3.6±0.01µs 270.9 Ktx/sec 271.3 Ktx/sec
stdb_raw 🧠 location multi_index 1000 5.0±0.06µs 5.0±0.03µs 193.5 Ktx/sec 196.8 Ktx/sec
stdb_raw 🧠 location non_unique 0 2.1±0.01µs 2.2±0.01µs 457.8 Ktx/sec 453.8 Ktx/sec
stdb_raw 🧠 location non_unique 1000 2.7±0.02µs 2.8±0.03µs 359.7 Ktx/sec 352.5 Ktx/sec
stdb_raw 🧠 location unique 0 2.8±0.01µs 2.8±0.00µs 349.6 Ktx/sec 349.8 Ktx/sec
stdb_raw 🧠 location unique 1000 4.0±0.03µs 3.9±0.03µs 242.8 Ktx/sec 250.7 Ktx/sec
stdb_raw 🧠 person multi_index 0 6.9±0.01µs 6.9±0.01µs 140.5 Ktx/sec 140.9 Ktx/sec
stdb_raw 🧠 person multi_index 1000 8.9±0.11µs 8.8±0.07µs 110.0 Ktx/sec 110.6 Ktx/sec
stdb_raw 🧠 person non_unique 0 2.6±0.00µs 2.7±0.00µs 369.7 Ktx/sec 367.1 Ktx/sec
stdb_raw 🧠 person non_unique 1000 3.2±0.02µs 3.3±0.02µs 301.1 Ktx/sec 298.3 Ktx/sec
stdb_raw 🧠 person unique 0 4.3±0.01µs 4.3±0.01µs 226.3 Ktx/sec 227.1 Ktx/sec
stdb_raw 🧠 person unique 1000 5.5±0.02µs 5.5±0.03µs 177.6 Ktx/sec 177.7 Ktx/sec

Multi-row insertions

db on disk schema index type load count new latency old latency new throughput old throughput
sqlite 💿 location multi_index 0 100 132.3±0.42µs 132.1±2.19µs 7.4 Ktx/sec 7.4 Ktx/sec
sqlite 💿 location multi_index 1000 100 205.9±1.10µs 204.7±1.13µs 4.7 Ktx/sec 4.8 Ktx/sec
sqlite 💿 location non_unique 0 100 51.9±1.54µs 51.1±0.83µs 18.8 Ktx/sec 19.1 Ktx/sec
sqlite 💿 location non_unique 1000 100 55.1±0.48µs 53.4±0.28µs 17.7 Ktx/sec 18.3 Ktx/sec
sqlite 💿 location unique 0 100 53.6±1.15µs 53.3±3.91µs 18.2 Ktx/sec 18.3 Ktx/sec
sqlite 💿 location unique 1000 100 58.3±0.22µs 57.8±0.24µs 16.7 Ktx/sec 16.9 Ktx/sec
sqlite 💿 person multi_index 0 100 119.6±5.59µs 120.1±3.50µs 8.2 Ktx/sec 8.1 Ktx/sec
sqlite 💿 person multi_index 1000 100 230.2±1.28µs 229.8±2.36µs 4.2 Ktx/sec 4.2 Ktx/sec
sqlite 💿 person non_unique 0 100 48.7±1.71µs 49.4±1.36µs 20.1 Ktx/sec 19.7 Ktx/sec
sqlite 💿 person non_unique 1000 100 61.7±13.63µs 62.1±12.16µs 15.8 Ktx/sec 15.7 Ktx/sec
sqlite 💿 person unique 0 100 50.1±1.31µs 51.3±1.27µs 19.5 Ktx/sec 19.0 Ktx/sec
sqlite 💿 person unique 1000 100 56.0±0.24µs 56.1±0.55µs 17.4 Ktx/sec 17.4 Ktx/sec
sqlite 🧠 location multi_index 0 100 120.7±0.61µs 120.9±0.39µs 8.1 Ktx/sec 8.1 Ktx/sec
sqlite 🧠 location multi_index 1000 100 171.7±0.20µs 171.5±0.45µs 5.7 Ktx/sec 5.7 Ktx/sec
sqlite 🧠 location non_unique 0 100 44.4±0.25µs 43.9±0.25µs 22.0 Ktx/sec 22.2 Ktx/sec
sqlite 🧠 location non_unique 1000 100 47.1±0.51µs 44.9±0.38µs 20.7 Ktx/sec 21.8 Ktx/sec
sqlite 🧠 location unique 0 100 46.5±0.40µs 45.5±0.40µs 21.0 Ktx/sec 21.5 Ktx/sec
sqlite 🧠 location unique 1000 100 50.1±0.38µs 49.0±0.26µs 19.5 Ktx/sec 19.9 Ktx/sec
sqlite 🧠 person multi_index 0 100 108.1±0.33µs 108.2±0.31µs 9.0 Ktx/sec 9.0 Ktx/sec
sqlite 🧠 person multi_index 1000 100 191.4±0.46µs 190.4±0.66µs 5.1 Ktx/sec 5.1 Ktx/sec
sqlite 🧠 person non_unique 0 100 41.9±0.56µs 41.8±0.28µs 23.3 Ktx/sec 23.3 Ktx/sec
sqlite 🧠 person non_unique 1000 100 46.3±0.24µs 46.4±0.18µs 21.1 Ktx/sec 21.1 Ktx/sec
sqlite 🧠 person unique 0 100 44.5±0.41µs 44.5±0.32µs 21.9 Ktx/sec 21.9 Ktx/sec
sqlite 🧠 person unique 1000 100 47.7±0.29µs 48.4±0.31µs 20.5 Ktx/sec 20.2 Ktx/sec
stdb_module 💿 location multi_index 0 100 611.0±122.68µs 541.7±107.84µs 1636 tx/sec 1846 tx/sec
stdb_module 💿 location multi_index 1000 100 796.0±3.63µs 839.0±176.83µs 1256 tx/sec 1191 tx/sec
stdb_module 💿 location non_unique 0 100 465.7±14.56µs 463.8±34.44µs 2.1 Ktx/sec 2.1 Ktx/sec
stdb_module 💿 location non_unique 1000 100 530.6±41.11µs 514.2±5.74µs 1884 tx/sec 1944 tx/sec
stdb_module 💿 location unique 0 100 441.0±78.15µs 447.6±76.09µs 2.2 Ktx/sec 2.2 Ktx/sec
stdb_module 💿 location unique 1000 100 740.7±89.76µs 863.4±5.17µs 1350 tx/sec 1158 tx/sec
stdb_module 💿 person multi_index 0 100 847.8±135.15µs 894.0±13.76µs 1179 tx/sec 1118 tx/sec
stdb_module 💿 person multi_index 1000 100 1113.4±21.95µs 1098.6±92.35µs 898 tx/sec 910 tx/sec
stdb_module 💿 person non_unique 0 100 524.4±46.71µs 464.5±45.88µs 1907 tx/sec 2.1 Ktx/sec
stdb_module 💿 person non_unique 1000 100 689.3±4.35µs 808.3±31.55µs 1450 tx/sec 1237 tx/sec
stdb_module 💿 person unique 0 100 610.2±1.78µs 618.3±12.93µs 1638 tx/sec 1617 tx/sec
stdb_module 💿 person unique 1000 100 848.2±4.61µs 771.2±53.78µs 1179 tx/sec 1296 tx/sec
stdb_module 🧠 location multi_index 0 100 390.0±55.04µs 453.0±64.44µs 2.5 Ktx/sec 2.2 Ktx/sec
stdb_module 🧠 location multi_index 1000 100 534.9±34.08µs 805.5±60.58µs 1869 tx/sec 1241 tx/sec
stdb_module 🧠 location non_unique 0 100 288.5±26.90µs 302.6±47.53µs 3.4 Ktx/sec 3.2 Ktx/sec
stdb_module 🧠 location non_unique 1000 100 488.0±64.14µs 559.3±19.43µs 2.0 Ktx/sec 1788 tx/sec
stdb_module 🧠 location unique 0 100 461.7±67.91µs 289.4±5.10µs 2.1 Ktx/sec 3.4 Ktx/sec
stdb_module 🧠 location unique 1000 100 531.0±4.54µs 410.4±97.91µs 1883 tx/sec 2.4 Ktx/sec
stdb_module 🧠 person multi_index 0 100 712.6±10.19µs 825.7±20.40µs 1403 tx/sec 1211 tx/sec
stdb_module 🧠 person multi_index 1000 100 790.6±24.88µs 900.0±2.91µs 1264 tx/sec 1111 tx/sec
stdb_module 🧠 person non_unique 0 100 443.3±50.33µs 366.8±18.54µs 2.2 Ktx/sec 2.7 Ktx/sec
stdb_module 🧠 person non_unique 1000 100 571.5±65.94µs 513.7±5.79µs 1749 tx/sec 1946 tx/sec
stdb_module 🧠 person unique 0 100 569.2±8.54µs 469.0±9.88µs 1756 tx/sec 2.1 Ktx/sec
stdb_module 🧠 person unique 1000 100 755.0±9.36µs 508.9±1.53µs 1324 tx/sec 1964 tx/sec
stdb_raw 💿 location multi_index 0 100 267.2±0.47µs 263.1±0.93µs 3.7 Ktx/sec 3.7 Ktx/sec
stdb_raw 💿 location multi_index 1000 100 309.2±177.93µs 309.3±175.62µs 3.2 Ktx/sec 3.2 Ktx/sec
stdb_raw 💿 location non_unique 0 100 122.5±0.64µs 122.4±0.09µs 8.0 Ktx/sec 8.0 Ktx/sec
stdb_raw 💿 location non_unique 1000 100 127.2±25.28µs 131.6±44.16µs 7.7 Ktx/sec 7.4 Ktx/sec
stdb_raw 💿 location unique 0 100 191.2±0.64µs 190.5±0.43µs 5.1 Ktx/sec 5.1 Ktx/sec
stdb_raw 💿 location unique 1000 100 209.1±1.41µs 222.3±124.20µs 4.7 Ktx/sec 4.4 Ktx/sec
stdb_raw 💿 person multi_index 0 100 568.2±3.42µs 565.2±1.40µs 1759 tx/sec 1769 tx/sec
stdb_raw 💿 person multi_index 1000 100 626.2±295.15µs 627.8±293.41µs 1597 tx/sec 1592 tx/sec
stdb_raw 💿 person non_unique 0 100 176.0±0.37µs 176.6±10.89µs 5.5 Ktx/sec 5.5 Ktx/sec
stdb_raw 💿 person non_unique 1000 100 178.8±0.43µs 178.1±0.43µs 5.5 Ktx/sec 5.5 Ktx/sec
stdb_raw 💿 person unique 0 100 324.0±1.64µs 322.4±0.56µs 3.0 Ktx/sec 3.0 Ktx/sec
stdb_raw 💿 person unique 1000 100 341.4±1.72µs 356.5±156.01µs 2.9 Ktx/sec 2.7 Ktx/sec
stdb_raw 🧠 location multi_index 0 100 262.3±0.52µs 259.2±0.53µs 3.7 Ktx/sec 3.8 Ktx/sec
stdb_raw 🧠 location multi_index 1000 100 286.6±0.38µs 287.0±0.26µs 3.4 Ktx/sec 3.4 Ktx/sec
stdb_raw 🧠 location non_unique 0 100 120.2±1.27µs 119.5±0.70µs 8.1 Ktx/sec 8.2 Ktx/sec
stdb_raw 🧠 location non_unique 1000 100 122.4±0.17µs 121.3±0.12µs 8.0 Ktx/sec 8.0 Ktx/sec
stdb_raw 🧠 location unique 0 100 188.4±0.14µs 186.6±0.82µs 5.2 Ktx/sec 5.2 Ktx/sec
stdb_raw 🧠 location unique 1000 100 205.8±1.62µs 206.1±0.23µs 4.7 Ktx/sec 4.7 Ktx/sec
stdb_raw 🧠 person multi_index 0 100 560.7±3.19µs 560.0±1.09µs 1783 tx/sec 1785 tx/sec
stdb_raw 🧠 person multi_index 1000 100 589.3±1.60µs 594.4±1.25µs 1696 tx/sec 1682 tx/sec
stdb_raw 🧠 person non_unique 0 100 171.8±1.92µs 172.4±0.09µs 5.7 Ktx/sec 5.7 Ktx/sec
stdb_raw 🧠 person non_unique 1000 100 174.2±1.26µs 174.6±0.18µs 5.6 Ktx/sec 5.6 Ktx/sec
stdb_raw 🧠 person unique 0 100 316.5±0.62µs 318.1±0.42µs 3.1 Ktx/sec 3.1 Ktx/sec
stdb_raw 🧠 person unique 1000 100 334.8±0.37µs 337.6±1.01µs 2.9 Ktx/sec 2.9 Ktx/sec

Full table iterate

db on disk schema index type new latency old latency new throughput old throughput
sqlite 💿 location unique 9.0±0.13µs 8.9±0.05µs 108.9 Ktx/sec 110.2 Ktx/sec
sqlite 💿 person unique 9.6±0.09µs 9.4±0.12µs 101.5 Ktx/sec 104.4 Ktx/sec
sqlite 🧠 location unique 7.6±0.10µs 7.7±0.05µs 128.3 Ktx/sec 127.3 Ktx/sec
sqlite 🧠 person unique 8.4±0.09µs 8.2±0.15µs 116.9 Ktx/sec 119.0 Ktx/sec
stdb_module 💿 location unique 31.5±1.98µs 31.1±2.85µs 31.0 Ktx/sec 31.4 Ktx/sec
stdb_module 💿 person unique 45.4±4.52µs 47.2±3.72µs 21.5 Ktx/sec 20.7 Ktx/sec
stdb_module 🧠 location unique 31.2±2.91µs 32.0±2.07µs 31.3 Ktx/sec 30.5 Ktx/sec
stdb_module 🧠 person unique 47.4±3.15µs 46.7±4.24µs 20.6 Ktx/sec 20.9 Ktx/sec
stdb_raw 💿 location unique 3.4±0.04µs 3.4±0.00µs 287.0 Ktx/sec 283.4 Ktx/sec
stdb_raw 💿 person unique 3.4±0.01µs 3.4±0.00µs 287.5 Ktx/sec 283.8 Ktx/sec
stdb_raw 🧠 location unique 3.4±0.01µs 3.4±0.03µs 287.5 Ktx/sec 284.9 Ktx/sec
stdb_raw 🧠 person unique 3.4±0.05µs 3.4±0.01µs 287.8 Ktx/sec 284.0 Ktx/sec

Find unique key

db on disk key type load new latency old latency new throughput old throughput
sqlite 💿 u32 1000 2.4±0.01µs 2.4±0.01µs 412.1 Ktx/sec 414.0 Ktx/sec
sqlite 🧠 u32 1000 1133.8±10.54ns 1155.7±4.62ns 861.3 Ktx/sec 845.0 Ktx/sec
stdb_module 💿 u32 1000 17.8±0.39µs 17.7±0.60µs 54.8 Ktx/sec 55.3 Ktx/sec
stdb_module 🧠 u32 1000 17.9±0.31µs 17.9±1.14µs 54.6 Ktx/sec 54.6 Ktx/sec
stdb_raw 💿 u32 1000 366.4±1.42ns 364.7±0.60ns 2.6 Mtx/sec 2.6 Mtx/sec
stdb_raw 🧠 u32 1000 365.2±0.46ns 368.4±0.43ns 2.6 Mtx/sec 2.6 Mtx/sec

Filter

db on disk key type index strategy load count new latency old latency new throughput old throughput
sqlite 💿 string indexed 1000 10 5.6±0.04µs 5.8±0.01µs 173.6 Ktx/sec 169.3 Ktx/sec
sqlite 💿 string non_indexed 1000 10 49.4±0.28µs 49.5±0.30µs 19.8 Ktx/sec 19.7 Ktx/sec
sqlite 💿 u64 indexed 1000 10 5.4±0.02µs 5.6±0.02µs 180.7 Ktx/sec 174.1 Ktx/sec
sqlite 💿 u64 non_indexed 1000 10 32.8±0.07µs 32.9±0.06µs 29.8 Ktx/sec 29.7 Ktx/sec
sqlite 🧠 string indexed 1000 10 4.2±0.05µs 4.3±0.04µs 235.1 Ktx/sec 224.9 Ktx/sec
sqlite 🧠 string non_indexed 1000 10 47.8±0.31µs 47.2±0.21µs 20.4 Ktx/sec 20.7 Ktx/sec
sqlite 🧠 u64 indexed 1000 10 4.0±0.02µs 4.2±0.01µs 246.1 Ktx/sec 232.5 Ktx/sec
sqlite 🧠 u64 non_indexed 1000 10 31.5±0.20µs 31.4±0.06µs 31.0 Ktx/sec 31.1 Ktx/sec
stdb_module 💿 string indexed 1000 10 22.6±1.65µs 22.3±1.46µs 43.2 Ktx/sec 43.8 Ktx/sec
stdb_module 💿 string non_indexed 1000 10 112.3±8.26µs 113.2±5.68µs 8.7 Ktx/sec 8.6 Ktx/sec
stdb_module 💿 u64 indexed 1000 10 20.5±1.30µs 19.8±1.01µs 47.6 Ktx/sec 49.4 Ktx/sec
stdb_module 💿 u64 non_indexed 1000 10 91.6±16.29µs 85.6±6.78µs 10.7 Ktx/sec 11.4 Ktx/sec
stdb_module 🧠 string indexed 1000 10 22.6±1.66µs 21.6±1.12µs 43.3 Ktx/sec 45.3 Ktx/sec
stdb_module 🧠 string non_indexed 1000 10 121.3±5.25µs 111.0±3.18µs 8.1 Ktx/sec 8.8 Ktx/sec
stdb_module 🧠 u64 indexed 1000 10 20.9±1.59µs 20.1±1.40µs 46.8 Ktx/sec 48.7 Ktx/sec
stdb_module 🧠 u64 non_indexed 1000 10 87.2±6.92µs 84.1±1.64µs 11.2 Ktx/sec 11.6 Ktx/sec
stdb_raw 💿 string indexed 1000 10 1229.9±0.95ns 1238.4±2.67ns 794.0 Ktx/sec 788.6 Ktx/sec
stdb_raw 💿 string non_indexed 1000 10 80.6±0.14µs 80.6±0.17µs 12.1 Ktx/sec 12.1 Ktx/sec
stdb_raw 💿 u64 indexed 1000 10 1154.6±1.01ns 1151.2±2.03ns 845.8 Ktx/sec 848.3 Ktx/sec
stdb_raw 💿 u64 non_indexed 1000 10 55.2±0.17µs 60.6±0.11µs 17.7 Ktx/sec 16.1 Ktx/sec
stdb_raw 🧠 string indexed 1000 10 1231.0±1.01ns 1236.3±13.21ns 793.3 Ktx/sec 789.9 Ktx/sec
stdb_raw 🧠 string non_indexed 1000 10 79.7±0.25µs 80.2±0.25µs 12.3 Ktx/sec 12.2 Ktx/sec
stdb_raw 🧠 u64 indexed 1000 10 1153.4±1.50ns 1153.9±2.62ns 846.7 Ktx/sec 846.3 Ktx/sec
stdb_raw 🧠 u64 non_indexed 1000 10 54.7±0.13µs 60.3±0.14µs 17.9 Ktx/sec 16.2 Ktx/sec

Serialize

schema format count new latency old latency new throughput old throughput
location bsatn 100 1738.5±31.23ns 1741.3±31.07ns 54.9 Mtx/sec 54.8 Mtx/sec
location json 100 3.1±0.03µs 3.1±0.02µs 30.8 Mtx/sec 31.1 Mtx/sec
location product_value 100 845.3±0.74ns 848.3±1.14ns 112.8 Mtx/sec 112.4 Mtx/sec
person bsatn 100 2.5±0.01µs 2.5±0.01µs 37.9 Mtx/sec 38.2 Mtx/sec
person json 100 5.0±0.07µs 5.0±0.04µs 19.2 Mtx/sec 19.1 Mtx/sec
person product_value 100 1120.1±0.59ns 1118.0±4.09ns 85.1 Mtx/sec 85.3 Mtx/sec

Module: invoke with large arguments

arg size new latency old latency new throughput old throughput
64KiB 73.5±10.22µs 81.3±9.64µs - -

Module: print bulk

line count new latency old latency new throughput old throughput
1 19.5±1.19µs 19.6±0.88µs - -
100 193.9±1.48µs 193.3±4.87µs - -
1000 1762.1±54.75µs 1774.2±39.73µs - -

Remaining benchmarks

name new latency old latency new throughput old throughput

Please sign in to comment.