Skip to content

Commit

Permalink
Add address: Address to ReducerContext (#299)
Browse files Browse the repository at this point in the history
* Add `address: Address` to `ReducerContext`

Initial support for identifying connections via an `Address`,
passed as the caller address in `ReducerContext`.

Notable design choices:

- The same type `Address` is used for clients and dbs,
  as opposed to having distinct `DbAddress` and `ClientAddress` types.
- For automatic reducers (init, scheduled, &c), the passed `Address`
  is the database's address, not the address of the client which called `publish`.
- Clients may specify an `Address` as a query parameter
  to the `subscribe` and `call` endpoints.
  If they do not, an `Address` will be randomly generated for them.

Still to do:

- Send the client's `Address` alongside their `Identity` and token
  upon WebSocket init in `IdentityToken`,
  so the client can save its `Address` for re-connection.
- SDK support.
- C# module support.
- Documentation.
- Refuse new connections if an existing connection
  with the same `(Identity, Address)` pair exists.
- Ensure we can store `Address` in tables,
  so modules can track connected clients,
  and ser/de `Address`, so those tables can be synced to clients.

* Use `None` in `ReducerContext` for HTTP calls without client address

* Fix typo in trait argument name

* `Address` representation amenable to SDK usage

Similar to `Identity`, make `Address` a product type with a double-underscored field name.

This will allow SDKs to distinguish `Address` from `Vec<u8>`,
but does necessitate some ugly `AddressForUrl` hackery
to get ser/de working correctly in different contexts.

This commit does not yet include SDK support for `Address`,
only the server-side machinery necessary for it.

* Add client_address parameter to /publish; pass to init and update reducers

Per discussion with Kim, it's useful for SpacetimeDB-cloud
for the client_address passed to the init reducer
to be that of the caller of /database/publish,
rather than the database's address.

This commit implements that behavior. Now:
- `init` and `update` take the client_address passed to publish, if any,
  or `None` if no client_address was supplied.
- Scheduled reducers never receive a client_address.
- Reducers invoked by HTTP /call take the client_address passed to /call, if any,
  or `None` if no client_address was supplied.
- Reducers invoked by WebSocket always receive the address of the WebSocket connection.

* `Address` support in Rust client SDK

* Add test that addresses are stable within a client process

* Run rustfmt against merge changes

* Not sure why my local `cargo fmt` didn't get this...

* Add caller_address argument to reducer arguments in Rust SDK

* rustfmt again...

* Add caller address to `EventJson` message

* Python codegen for client addresses

* C# module support for client addresses

* Fix scoping error

* Add `Address`-related stuff to C# codegen

- Emit `SpacetimeDB.Address` for address types
- Add `callerAddress` field to `ReducerEvent`

* TypeScript codegen changes

* Fix merge conflict with new test

* Run rustfmt

---------

Co-authored-by: Ingvar Stepanyan <[email protected]>
  • Loading branch information
gefjon and RReverser authored Sep 30, 2023
1 parent d8395fe commit 59159db
Show file tree
Hide file tree
Showing 59 changed files with 1,112 additions and 267 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/bindings-csharp/Runtime/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ private static byte[] DescribeModule()
private static string? CallReducer(
uint id,
byte[] sender_identity,
byte[] sender_address,
ulong timestamp,
byte[] args
)
Expand All @@ -197,7 +198,7 @@ byte[] args
{
using var stream = new MemoryStream(args);
using var reader = new BinaryReader(stream);
reducers[(int)id].Invoke(reader, new(sender_identity, timestamp));
reducers[(int)id].Invoke(reader, new(sender_identity, sender_address, timestamp));
if (stream.Position != stream.Length)
{
throw new Exception("Unrecognised extra bytes in the reducer arguments");
Expand Down
57 changes: 52 additions & 5 deletions crates/bindings-csharp/Runtime/Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,14 +216,61 @@ public override int GetHashCode() =>
public static SpacetimeDB.SATS.TypeInfo<Identity> GetSatsTypeInfo() => satsTypeInfo;
}

public struct Address : IEquatable<Address>
{
private readonly byte[] bytes;

public Address(byte[] bytes) => this.bytes = bytes;

public static readonly Address Zero = new(new byte[16]);

public bool Equals(Address other) =>
StructuralComparisons.StructuralEqualityComparer.Equals(bytes, other.bytes);

public override bool Equals(object? obj) => obj is Address other && Equals(other);

public static bool operator ==(Address left, Address right) => left.Equals(right);

public static bool operator !=(Address left, Address right) => !left.Equals(right);

public override int GetHashCode() =>
StructuralComparisons.StructuralEqualityComparer.GetHashCode(bytes);

public override string ToString() => BitConverter.ToString(bytes);

private static SpacetimeDB.SATS.TypeInfo<Address> satsTypeInfo =
new(
// We need to set type info to inlined address type as `generate` CLI currently can't recognise type references for built-ins.
new SpacetimeDB.SATS.ProductType
{
{ "__address_bytes", SpacetimeDB.SATS.BuiltinType.BytesTypeInfo.AlgebraicType }
},
// Concern: We use this "packed" representation (as Bytes)
// in the caller_id field of reducer arguments,
// but in table rows,
// we send the "unpacked" representation as a product value.
// It's possible that these happen to be identical
// because BSATN is minimally self-describing,
// but that doesn't seem like something we should count on.
reader => new(SpacetimeDB.SATS.BuiltinType.BytesTypeInfo.Read(reader)),
(writer, value) =>
SpacetimeDB.SATS.BuiltinType.BytesTypeInfo.Write(writer, value.bytes)
);

public static SpacetimeDB.SATS.TypeInfo<Address> GetSatsTypeInfo() => satsTypeInfo;
}

public class DbEventArgs : EventArgs
{
public readonly Identity Sender;
public readonly DateTimeOffset Time;
public readonly Address? Address;

public DbEventArgs(byte[] senderIdentity, ulong timestamp_us)
public DbEventArgs(byte[] senderIdentity, byte[] senderAddress, ulong timestamp_us)
{
Sender = new Identity(senderIdentity);
var addr = new Address(senderAddress);
Address = addr == Runtime.Address.Zero ? null : addr;
// timestamp is in microseconds; the easiest way to convert those w/o losing precision is to get Unix origin and add ticks which are 0.1ms each.
Time = DateTimeOffset.UnixEpoch.AddTicks(10 * (long)timestamp_us);
}
Expand All @@ -233,11 +280,11 @@ public DbEventArgs(byte[] senderIdentity, ulong timestamp_us)
public static event Action<DbEventArgs>? OnDisconnect;

// Note: this is accessed by C bindings.
private static string? IdentityConnected(byte[] sender_identity, ulong timestamp)
private static string? IdentityConnected(byte[] sender_identity, byte[] sender_address, ulong timestamp)
{
try
{
OnConnect?.Invoke(new(sender_identity, timestamp));
OnConnect?.Invoke(new(sender_identity, sender_address, timestamp));
return null;
}
catch (Exception e)
Expand All @@ -247,11 +294,11 @@ public DbEventArgs(byte[] senderIdentity, ulong timestamp_us)
}

// Note: this is accessed by C bindings.
private static string? IdentityDisconnected(byte[] sender_identity, ulong timestamp)
private static string? IdentityDisconnected(byte[] sender_identity, byte[] sender_address, ulong timestamp)
{
try
{
OnDisconnect?.Invoke(new(sender_identity, timestamp));
OnDisconnect?.Invoke(new(sender_identity, sender_address, timestamp));
return null;
}
catch (Exception e)
Expand Down
22 changes: 13 additions & 9 deletions crates/bindings-csharp/Runtime/bindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,33 +434,37 @@ static Buffer return_result_buf(MonoObject* str) {

__attribute__((export_name("__call_reducer__"))) Buffer __call_reducer__(
uint32_t id,
Buffer sender_,
Buffer sender_id_,
Buffer sender_address_,
uint64_t timestamp,
Buffer args_) {
MonoArray* sender = stdb_buffer_consume(sender_);
MonoArray* sender_id = stdb_buffer_consume(sender_id_);
MonoArray* sender_address = stdb_buffer_consume(sender_address_);
MonoArray* args = stdb_buffer_consume(args_);

return return_result_buf(INVOKE_DOTNET_METHOD(
"SpacetimeDB.Runtime.dll", "SpacetimeDB.Module", "FFI", "CallReducer",
NULL, &id, sender, &timestamp, args));
NULL, &id, sender_id, sender_address, &timestamp, args));
}

__attribute__((export_name("__identity_connected__"))) Buffer
__identity_connected__(Buffer sender_, uint64_t timestamp) {
MonoArray* sender = stdb_buffer_consume(sender_);
__identity_connected__(Buffer sender_id_, Buffer sender_address_, uint64_t timestamp) {
MonoArray* sender_id = stdb_buffer_consume(sender_id_);
MonoArray* sender_address = stdb_buffer_consume(sender_address_);

return return_result_buf(
INVOKE_DOTNET_METHOD("SpacetimeDB.Runtime.dll", "SpacetimeDB", "Runtime",
"IdentityConnected", NULL, sender, &timestamp));
"IdentityConnected", NULL, sender_id, sender_address, &timestamp));
}

__attribute__((export_name("__identity_disconnected__"))) Buffer
__identity_disconnected__(Buffer sender_, uint64_t timestamp) {
MonoArray* sender = stdb_buffer_consume(sender_);
__identity_disconnected__(Buffer sender_id_, Buffer sender_address_, uint64_t timestamp) {
MonoArray* sender_id = stdb_buffer_consume(sender_id_);
MonoArray* sender_address = stdb_buffer_consume(sender_address_);

return return_result_buf(
INVOKE_DOTNET_METHOD("SpacetimeDB.Runtime.dll", "SpacetimeDB", "Runtime",
"IdentityDisconnected", NULL, sender, &timestamp));
"IdentityDisconnected", NULL, sender_id, sender_address, &timestamp));
}

// Shims to avoid dependency on WASI in the generated Wasm file.
Expand Down
25 changes: 21 additions & 4 deletions crates/bindings-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,23 @@ fn gen_reducer(original_function: ItemFn, reducer_name: &str, extra: ReducerExtr
};

let generated_function = quote! {
fn __reducer(__sender: spacetimedb::sys::Buffer, __timestamp: u64, __args: &[u8]) -> spacetimedb::sys::Buffer {
// NOTE: double-underscoring names here is unnecessary, as Rust macros are hygienic.
fn __reducer(
__sender: spacetimedb::sys::Buffer,
__caller_address: spacetimedb::sys::Buffer,
__timestamp: u64,
__args: &[u8]
) -> spacetimedb::sys::Buffer {
#(spacetimedb::rt::assert_reducerarg::<#arg_tys>();)*
#(spacetimedb::rt::assert_reducerret::<#ret_ty>();)*
spacetimedb::rt::invoke_reducer(#func_name, __sender, __timestamp, __args, |_res| { #epilogue })
spacetimedb::rt::invoke_reducer(
#func_name,
__sender,
__caller_address,
__timestamp,
__args,
|_res| { #epilogue },
)
}
};

Expand Down Expand Up @@ -889,8 +902,12 @@ fn spacetimedb_connect_disconnect(item: TokenStream, connect: bool) -> syn::Resu
let emission = quote! {
const _: () = {
#[export_name = #connect_disconnect_symbol]
extern "C" fn __connect_disconnect(__sender: spacetimedb::sys::Buffer, __timestamp: u64) -> spacetimedb::sys::Buffer {
spacetimedb::rt::invoke_connection_func(#func_name, __sender, __timestamp)
extern "C" fn __connect_disconnect(
__sender: spacetimedb::sys::Buffer,
__caller_address: spacetimedb::sys::Buffer,
__timestamp: u64,
) -> spacetimedb::sys::Buffer {
spacetimedb::rt::invoke_connection_func(#func_name, __sender, __caller_address, __timestamp)
}
};

Expand Down
10 changes: 10 additions & 0 deletions crates/bindings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub use spacetimedb_bindings_macro::{duration, query, spacetimedb, TableType};
pub use sats::SpacetimeType;
pub use spacetimedb_lib;
pub use spacetimedb_lib::sats;
pub use spacetimedb_lib::Address;
pub use spacetimedb_lib::AlgebraicValue;
pub use spacetimedb_lib::Identity;
pub use timestamp::Timestamp;
Expand Down Expand Up @@ -51,6 +52,14 @@ pub struct ReducerContext {
pub sender: Identity,
/// The time at which the reducer was started.
pub timestamp: Timestamp,
/// The `Address` of the client that invoked the reducer.
///
/// `None` if no `Address` was supplied to the `/database/call` HTTP endpoint,
/// or via the CLI's `spacetime call` subcommand.
///
/// For automatic reducers, i.e. `init`, `update` and scheduled reducers,
/// this will be the module's `Address`.
pub address: Option<Address>,
}

impl ReducerContext {
Expand All @@ -59,6 +68,7 @@ impl ReducerContext {
Self {
sender: Identity::__dummy(),
timestamp: Timestamp::UNIX_EPOCH,
address: None,
}
}
}
Expand Down
46 changes: 37 additions & 9 deletions crates/bindings/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use spacetimedb_lib::de::{self, Deserialize, SeqProductAccess};
use spacetimedb_lib::sats::typespace::TypespaceBuilder;
use spacetimedb_lib::sats::{impl_deserialize, impl_serialize, AlgebraicType, AlgebraicTypeRef, ProductTypeElement};
use spacetimedb_lib::ser::{Serialize, SerializeSeqProduct};
use spacetimedb_lib::{bsatn, Identity, MiscModuleExport, ModuleDef, ReducerDef, TableDef, TypeAlias};
use spacetimedb_lib::{bsatn, Address, Identity, MiscModuleExport, ModuleDef, ReducerDef, TableDef, TypeAlias};
use sys::Buffer;

pub use once_cell::sync::{Lazy, OnceCell};
Expand All @@ -28,11 +28,12 @@ pub use once_cell::sync::{Lazy, OnceCell};
pub fn invoke_reducer<'a, A: Args<'a>, T>(
reducer: impl Reducer<'a, A, T>,
sender: Buffer,
client_address: Buffer,
timestamp: u64,
args: &'a [u8],
epilogue: impl FnOnce(Result<(), &str>),
) -> Buffer {
let ctx = assemble_context(sender, timestamp);
let ctx = assemble_context(sender, timestamp, client_address);

// Deserialize the arguments from a bsatn encoding.
let SerDeArgs(args) = bsatn::from_slice(args).expect("unable to decode args");
Expand Down Expand Up @@ -71,21 +72,42 @@ pub fn create_index(index_name: &str, table_id: u32, index_type: sys::raw::Index
pub fn invoke_connection_func<R: ReducerResult>(
f: impl Fn(ReducerContext) -> R,
sender: Buffer,
client_address: Buffer,
timestamp: u64,
) -> Buffer {
let ctx = assemble_context(sender, timestamp);
let ctx = assemble_context(sender, timestamp, client_address);

let res = with_timestamp_set(ctx.timestamp, || f(ctx).into_result());
cvt_result(res)
}

/// Creates a reducer context from the given `sender` and `timestamp`.
fn assemble_context(sender: Buffer, timestamp: u64) -> ReducerContext {
/// Creates a reducer context from the given `sender`, `timestamp` and `client_address`.
///
/// `sender` must contain 32 bytes, from which we will read an `Identity`.
///
/// `timestamp` is a count of microseconds since the Unix epoch.
///
/// `client_address` must contain 16 bytes, from which we will read an `Address`.
/// The all-zeros `client_address` (constructed by [`Address::__dummy`]) is used as a sentinel,
/// and translated to `None`.
fn assemble_context(sender: Buffer, timestamp: u64, client_address: Buffer) -> ReducerContext {
let sender = Identity::from_byte_array(sender.read_array::<32>());

let timestamp = Timestamp::UNIX_EPOCH + Duration::from_micros(timestamp);

ReducerContext { sender, timestamp }
let address = Address::from_arr(&client_address.read_array::<16>());

let address = if address == Address::__dummy() {
None
} else {
Some(address)
};

ReducerContext {
sender,
timestamp,
address,
}
}

/// Converts `errno` into a string message.
Expand Down Expand Up @@ -471,7 +493,7 @@ impl TypespaceBuilder for ModuleBuilder {
static DESCRIBERS: Mutex<Vec<fn(&mut ModuleBuilder)>> = Mutex::new(Vec::new());

/// A reducer function takes in `(Sender, Timestamp, Args)` and writes to a new `Buffer`.
pub type ReducerFn = fn(Buffer, u64, &[u8]) -> Buffer;
pub type ReducerFn = fn(Buffer, Buffer, u64, &[u8]) -> Buffer;
static REDUCERS: OnceCell<Vec<ReducerFn>> = OnceCell::new();

/// Describes the module into a serialized form that is returned and writes the set of `REDUCERS`.
Expand All @@ -497,8 +519,14 @@ extern "C" fn __describe_module__() -> Buffer {
///
/// The result of the reducer is written into a fresh buffer.
#[no_mangle]
extern "C" fn __call_reducer__(id: usize, sender: Buffer, timestamp: u64, args: Buffer) -> Buffer {
extern "C" fn __call_reducer__(
id: usize,
sender: Buffer,
caller_address: Buffer,
timestamp: u64,
args: Buffer,
) -> Buffer {
let reducers = REDUCERS.get().unwrap();
let args = args.read();
reducers[id](sender, timestamp, &args)
reducers[id](sender, caller_address, timestamp, &args)
}
Loading

1 comment on commit 59159db

@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 59159db

Click to view benchmark
Test Base PR %
serialize/location/bsatn/count=100 2.8±0.05µs 34.3 MElem/sec N/A N/A
serialize/location/json/count=100 3.7±0.06µs 26.1 MElem/sec N/A N/A
serialize/location/product_value/count=100 2.6±0.02µs 36.8 MElem/sec N/A N/A
serialize/person/bsatn/count=100 3.5±0.03µs 27.5 MElem/sec N/A N/A
serialize/person/json/count=100 5.6±0.11µs 17.1 MElem/sec N/A N/A
serialize/person/product_value/count=100 1742.6±9.79ns 54.7 MElem/sec N/A N/A
sqlite/disk/empty 423.6±2.39ns 431.6±12.08ns +1.89%
sqlite/disk/filter/string/indexed/load=1000/count=10 5.5±0.03µs 177.7 KElem/sec N/A N/A
sqlite/disk/filter/string/non_indexed/load=1000/count=10 55.6±0.28µs 17.6 KElem/sec N/A N/A
sqlite/disk/filter/u64/indexed/load=1000/count=10 5.3±0.07µs 182.9 KElem/sec N/A N/A
sqlite/disk/filter/u64/non_indexed/load=1000/count=10 43.4±0.91µs 22.5 KElem/sec N/A N/A
sqlite/disk/find_unique/u32/load=1000 2.2±0.02µs 453.1 KElem/sec N/A N/A
sqlite/disk/insert_1/location/multi_index/load=0 14.7±0.20µs 66.3 KElem/sec N/A N/A
sqlite/disk/insert_1/location/multi_index/load=1000 17.4±0.80µs 56.1 KElem/sec N/A N/A
sqlite/disk/insert_1/location/non_unique/load=0 7.2±0.10µs 135.9 KElem/sec N/A N/A
sqlite/disk/insert_1/location/non_unique/load=1000 7.1±0.20µs 136.8 KElem/sec N/A N/A
sqlite/disk/insert_1/location/unique/load=0 7.1±0.05µs 138.1 KElem/sec N/A N/A
sqlite/disk/insert_1/location/unique/load=1000 7.0±0.14µs 139.4 KElem/sec N/A N/A
sqlite/disk/insert_1/person/multi_index/load=0 14.5±0.33µs 67.2 KElem/sec N/A N/A
sqlite/disk/insert_1/person/multi_index/load=1000 17.6±0.62µs 55.6 KElem/sec N/A N/A
sqlite/disk/insert_1/person/non_unique/load=0 7.1±0.09µs 136.7 KElem/sec N/A N/A
sqlite/disk/insert_1/person/non_unique/load=1000 7.2±0.21µs 135.1 KElem/sec N/A N/A
sqlite/disk/insert_1/person/unique/load=0 7.3±0.33µs 134.5 KElem/sec N/A N/A
sqlite/disk/insert_1/person/unique/load=1000 7.2±0.18µs 135.7 KElem/sec N/A N/A
sqlite/disk/insert_bulk/location/multi_index/load=0/count=100 125.7±2.49µs 122.0±1.99µs -2.94%
sqlite/disk/insert_bulk/location/multi_index/load=1000/count=100 206.1±3.73µs 208.7±5.00µs +1.26%
sqlite/disk/insert_bulk/location/non_unique/load=0/count=100 44.7±1.76µs 21.8 KElem/sec N/A N/A
sqlite/disk/insert_bulk/location/non_unique/load=1000/count=100 48.5±0.39µs 20.1 KElem/sec N/A N/A
sqlite/disk/insert_bulk/location/unique/load=0/count=100 46.2±0.78µs 21.1 KElem/sec N/A N/A
sqlite/disk/insert_bulk/location/unique/load=1000/count=100 52.9±0.67µs 18.5 KElem/sec N/A N/A
sqlite/disk/insert_bulk/person/multi_index/load=0/count=100 117.7±1.02µs 113.2±1.90µs -3.82%
sqlite/disk/insert_bulk/person/multi_index/load=1000/count=100 242.5±3.56µs 242.0±4.08µs -0.21%
sqlite/disk/insert_bulk/person/non_unique/load=0/count=100 45.6±0.35µs 21.4 KElem/sec N/A N/A
sqlite/disk/insert_bulk/person/non_unique/load=1000/count=100 60.2±1.31µs 16.2 KElem/sec N/A N/A
sqlite/disk/insert_bulk/person/unique/load=0/count=100 44.5±1.24µs 21.9 KElem/sec N/A N/A
sqlite/disk/insert_bulk/person/unique/load=1000/count=100 50.5±0.52µs 19.3 KElem/sec N/A N/A
sqlite/disk/iterate/location/unique/count=100 8.2±0.10µs 119.8 KElem/sec N/A N/A
sqlite/disk/iterate/person/unique/count=100 8.4±0.07µs 116.7 KElem/sec N/A N/A
sqlite/mem/empty 423.9±3.57ns 423.5±6.19ns -0.09%
sqlite/mem/filter/string/indexed/load=1000/count=10 4.1±0.04µs 240.0 KElem/sec N/A N/A
sqlite/mem/filter/string/non_indexed/load=1000/count=10 52.2±0.35µs 18.7 KElem/sec N/A N/A
sqlite/mem/filter/u64/indexed/load=1000/count=10 3.9±0.04µs 248.0 KElem/sec N/A N/A
sqlite/mem/filter/u64/non_indexed/load=1000/count=10 39.5±1.27µs 24.7 KElem/sec N/A N/A
sqlite/mem/find_unique/u32/load=1000 1035.2±12.67ns 943.4 KElem/sec N/A N/A
sqlite/mem/insert_1/location/multi_index/load=0 4.3±0.03µs 228.2 KElem/sec N/A N/A
sqlite/mem/insert_1/location/multi_index/load=1000 5.5±0.19µs 176.8 KElem/sec N/A N/A
sqlite/mem/insert_1/location/non_unique/load=0 1807.2±23.56ns 540.4 KElem/sec N/A N/A
sqlite/mem/insert_1/location/non_unique/load=1000 1830.7±32.76ns 533.4 KElem/sec N/A N/A
sqlite/mem/insert_1/location/unique/load=0 1741.2±26.69ns 560.9 KElem/sec N/A N/A
sqlite/mem/insert_1/location/unique/load=1000 1906.0±115.05ns 512.4 KElem/sec N/A N/A
sqlite/mem/insert_1/person/multi_index/load=0 4.2±0.05µs 232.2 KElem/sec N/A N/A
sqlite/mem/insert_1/person/multi_index/load=1000 6.5±0.20µs 150.9 KElem/sec N/A N/A
sqlite/mem/insert_1/person/non_unique/load=0 1830.6±18.15ns 533.5 KElem/sec N/A N/A
sqlite/mem/insert_1/person/non_unique/load=1000 1944.9±36.15ns 502.1 KElem/sec N/A N/A
sqlite/mem/insert_1/person/unique/load=0 1792.7±16.69ns 544.7 KElem/sec N/A N/A
sqlite/mem/insert_1/person/unique/load=1000 1948.2±62.70ns 501.3 KElem/sec N/A N/A
sqlite/mem/insert_bulk/location/multi_index/load=0/count=100 113.3±2.68µs 109.7±0.57µs -3.18%
sqlite/mem/insert_bulk/location/multi_index/load=1000/count=100 168.1±3.58µs 165.6±1.25µs -1.49%
sqlite/mem/insert_bulk/location/non_unique/load=0/count=100 36.8±0.67µs 26.5 KElem/sec N/A N/A
sqlite/mem/insert_bulk/location/non_unique/load=1000/count=100 39.3±0.74µs 24.9 KElem/sec N/A N/A
sqlite/mem/insert_bulk/location/unique/load=0/count=100 38.6±1.04µs 25.3 KElem/sec N/A N/A
sqlite/mem/insert_bulk/location/unique/load=1000/count=100 43.1±1.51µs 22.7 KElem/sec N/A N/A
sqlite/mem/insert_bulk/person/multi_index/load=0/count=100 103.7±1.12µs 101.7±0.86µs -1.93%
sqlite/mem/insert_bulk/person/multi_index/load=1000/count=100 196.7±1.22µs 194.9±5.00µs -0.92%
sqlite/mem/insert_bulk/person/non_unique/load=0/count=100 37.0±0.82µs 26.4 KElem/sec N/A N/A
sqlite/mem/insert_bulk/person/non_unique/load=1000/count=100 43.7±0.64µs 22.3 KElem/sec N/A N/A
sqlite/mem/insert_bulk/person/unique/load=0/count=100 38.5±0.51µs 25.4 KElem/sec N/A N/A
sqlite/mem/insert_bulk/person/unique/load=1000/count=100 43.6±0.57µs 22.4 KElem/sec N/A N/A
sqlite/mem/iterate/location/unique/count=100 7.1±0.17µs 136.9 KElem/sec N/A N/A
sqlite/mem/iterate/person/unique/count=100 7.3±0.41µs 133.2 KElem/sec N/A N/A
stdb_module/disk/empty 25.7±1.28µs 25.7±0.55µs 0.00%
stdb_module/disk/filter/string/indexed/load=1000/count=10 55.9±6.98µs 17.5 KElem/sec N/A N/A
stdb_module/disk/filter/string/non_indexed/load=1000/count=10 144.6±13.11µs 145.7±3.70µs +0.76%
stdb_module/disk/filter/u64/indexed/load=1000/count=10 47.1±5.75µs 20.7 KElem/sec N/A N/A
stdb_module/disk/filter/u64/non_indexed/load=1000/count=10 115.7±7.50µs 115.6±5.28µs -0.09%
stdb_module/disk/find_unique/u32/load=1000 33.8±1.49µs 28.9 KElem/sec N/A N/A
stdb_module/disk/insert_1/location/multi_index/load=0 47.3±2.57µs 20.7 KElem/sec N/A N/A
stdb_module/disk/insert_1/location/multi_index/load=1000 359.5±48.00µs 355.7±42.53µs -1.06%
stdb_module/disk/insert_1/location/non_unique/load=0 44.5±5.28µs 21.9 KElem/sec N/A N/A
stdb_module/disk/insert_1/location/non_unique/load=1000 286.0±24.85µs 312.4±18.74µs +9.23%
stdb_module/disk/insert_1/location/unique/load=0 49.2±5.47µs 19.9 KElem/sec N/A N/A
stdb_module/disk/insert_1/location/unique/load=1000 354.2±27.41µs 330.9±30.32µs -6.58%
stdb_module/disk/insert_1/person/multi_index/load=0 62.3±7.76µs 15.7 KElem/sec N/A N/A
stdb_module/disk/insert_1/person/multi_index/load=1000 454.6±49.60µs 441.2±84.31µs -2.95%
stdb_module/disk/insert_1/person/non_unique/load=0 47.6±3.97µs 20.5 KElem/sec N/A N/A
stdb_module/disk/insert_1/person/non_unique/load=1000 360.6±27.66µs 330.2±58.24µs -8.43%
stdb_module/disk/insert_1/person/unique/load=0 53.1±7.07µs 18.4 KElem/sec N/A N/A
stdb_module/disk/insert_1/person/unique/load=1000 388.3±28.07µs 379.7±34.63µs -2.21%
stdb_module/disk/insert_bulk/location/multi_index/load=0/count=100 867.9±20.35µs 865.7±16.46µs -0.25%
stdb_module/disk/insert_bulk/location/multi_index/load=1000/count=100 1160.1±53.92µs 1159.2±47.61µs -0.08%
stdb_module/disk/insert_bulk/location/non_unique/load=0/count=100 620.9±23.22µs 611.1±16.04µs -1.58%
stdb_module/disk/insert_bulk/location/non_unique/load=1000/count=100 808.8±28.11µs 808.4±21.66µs -0.05%
stdb_module/disk/insert_bulk/location/unique/load=0/count=100 746.8±15.95µs 743.7±20.30µs -0.42%
stdb_module/disk/insert_bulk/location/unique/load=1000/count=100 1006.8±36.33µs 1018.9±39.08µs +1.20%
stdb_module/disk/insert_bulk/person/multi_index/load=0/count=100 1503.4±21.87µs 1493.8±54.68µs -0.64%
stdb_module/disk/insert_bulk/person/multi_index/load=1000/count=100 1808.1±56.63µs 1814.4±143.06µs +0.35%
stdb_module/disk/insert_bulk/person/non_unique/load=0/count=100 823.3±43.16µs 795.4±12.01µs -3.39%
stdb_module/disk/insert_bulk/person/non_unique/load=1000/count=100 1067.3±30.75µs 1049.8±38.95µs -1.64%
stdb_module/disk/insert_bulk/person/unique/load=0/count=100 1029.9±36.96µs 1061.3±83.30µs +3.05%
stdb_module/disk/insert_bulk/person/unique/load=1000/count=100 1386.5±43.44µs 1388.8±103.74µs +0.17%
stdb_module/disk/iterate/location/unique/count=100 133.1±3.61µs 143.8±7.59µs +8.04%
stdb_module/disk/iterate/person/unique/count=100 213.0±5.18µs 243.5±10.03µs +14.32%
stdb_module/large_arguments/64KiB 102.6±2.29µs 101.9±0.78µs -0.68%
stdb_module/mem/empty 26.5±1.34µs 26.4±1.18µs -0.38%
stdb_module/mem/filter/string/indexed/load=1000/count=10 54.0±4.98µs 18.1 KElem/sec N/A N/A
stdb_module/mem/filter/string/non_indexed/load=1000/count=10 140.8±4.45µs 137.5±3.12µs -2.34%
stdb_module/mem/filter/u64/indexed/load=1000/count=10 44.5±4.27µs 21.9 KElem/sec N/A N/A
stdb_module/mem/filter/u64/non_indexed/load=1000/count=10 109.3±1.90µs 117.7±12.80µs +7.69%
stdb_module/mem/find_unique/u32/load=1000 34.5±2.43µs 28.3 KElem/sec N/A N/A
stdb_module/mem/insert_1/location/multi_index/load=0 43.0±2.54µs 22.7 KElem/sec N/A N/A
stdb_module/mem/insert_1/location/multi_index/load=1000 327.3±32.05µs 295.4±34.83µs -9.75%
stdb_module/mem/insert_1/location/non_unique/load=0 39.6±1.80µs 24.7 KElem/sec N/A N/A
stdb_module/mem/insert_1/location/non_unique/load=1000 200.3±18.87µs 199.8±31.76µs -0.25%
stdb_module/mem/insert_1/location/unique/load=0 40.3±1.94µs 24.3 KElem/sec N/A N/A
stdb_module/mem/insert_1/location/unique/load=1000 267.1±36.66µs 261.6±17.03µs -2.06%
stdb_module/mem/insert_1/person/multi_index/load=0 47.4±3.69µs 20.6 KElem/sec N/A N/A
stdb_module/mem/insert_1/person/multi_index/load=1000 358.3±58.24µs 407.6±39.25µs +13.76%
stdb_module/mem/insert_1/person/non_unique/load=0 40.7±2.70µs 24.0 KElem/sec N/A N/A
stdb_module/mem/insert_1/person/non_unique/load=1000 273.4±30.32µs 290.6±42.86µs +6.29%
stdb_module/mem/insert_1/person/unique/load=0 46.0±4.22µs 21.2 KElem/sec N/A N/A
stdb_module/mem/insert_1/person/unique/load=1000 370.2±27.22µs 326.5±22.55µs -11.80%
stdb_module/mem/insert_bulk/location/multi_index/load=0/count=100 765.8±16.55µs 761.9±18.62µs -0.51%
stdb_module/mem/insert_bulk/location/multi_index/load=1000/count=100 1018.6±29.73µs 1008.7±42.50µs -0.97%
stdb_module/mem/insert_bulk/location/non_unique/load=0/count=100 512.1±14.28µs 510.1±15.31µs -0.39%
stdb_module/mem/insert_bulk/location/non_unique/load=1000/count=100 645.9±43.27µs 628.8±38.20µs -2.65%
stdb_module/mem/insert_bulk/location/unique/load=0/count=100 639.2±13.38µs 632.9±15.96µs -0.99%
stdb_module/mem/insert_bulk/location/unique/load=1000/count=100 861.2±22.87µs 851.1±32.06µs -1.17%
stdb_module/mem/insert_bulk/person/multi_index/load=0/count=100 1333.0±44.56µs 1357.9±54.42µs +1.87%
stdb_module/mem/insert_bulk/person/multi_index/load=1000/count=100 1694.8±70.42µs 1676.4±50.99µs -1.09%
stdb_module/mem/insert_bulk/person/non_unique/load=0/count=100 712.1±15.29µs 721.9±39.87µs +1.38%
stdb_module/mem/insert_bulk/person/non_unique/load=1000/count=100 908.2±32.76µs 919.2±36.64µs +1.21%
stdb_module/mem/insert_bulk/person/unique/load=0/count=100 929.9±13.22µs 917.3±12.27µs -1.35%
stdb_module/mem/insert_bulk/person/unique/load=1000/count=100 1225.4±36.61µs 1250.2±28.18µs +2.02%
stdb_module/mem/iterate/location/unique/count=100 128.5±2.10µs 136.7±6.81µs +6.38%
stdb_module/mem/iterate/person/unique/count=100 195.7±2.56µs 221.0±3.90µs +12.93%
stdb_module/print_bulk/lines=1 34.1±1.67µs 35.4±2.72µs +3.81%
stdb_module/print_bulk/lines=100 320.2±11.69µs 320.0±1.77µs -0.06%
stdb_module/print_bulk/lines=1000 3.0±0.06ms 3.0±0.04ms 0.00%
stdb_raw/disk/empty 102.8±0.99ns 102.8±1.17ns 0.00%
stdb_raw/disk/filter/string/indexed/load=1000/count=10 2.6±0.05µs 372.5 KElem/sec N/A N/A
stdb_raw/disk/filter/string/non_indexed/load=1000/count=10 93.0±1.02µs 10.5 KElem/sec N/A N/A
stdb_raw/disk/filter/u64/indexed/load=1000/count=10 2.4±0.02µs 404.4 KElem/sec N/A N/A
stdb_raw/disk/filter/u64/non_indexed/load=1000/count=10 75.3±0.84µs 13.0 KElem/sec N/A N/A
stdb_raw/disk/find_unique/u32/load=1000 565.9±4.88ns 1725.8 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/multi_index/load=0 6.2±0.10µs 157.7 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/multi_index/load=1000 33.1±4.43µs 29.5 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/non_unique/load=0 4.0±0.03µs 244.5 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/non_unique/load=1000 20.7±1.86µs 47.1 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/unique/load=0 4.9±0.09µs 198.3 KElem/sec N/A N/A
stdb_raw/disk/insert_1/location/unique/load=1000 26.5±0.83µs 36.9 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/multi_index/load=0 10.3±0.11µs 95.0 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/multi_index/load=1000 33.3±6.18µs 29.3 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/non_unique/load=0 4.7±0.06µs 209.9 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/non_unique/load=1000 16.9±0.66µs 57.8 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/unique/load=0 6.8±0.07µs 144.5 KElem/sec N/A N/A
stdb_raw/disk/insert_1/person/unique/load=1000 26.1±1.43µs 37.4 KElem/sec N/A N/A
stdb_raw/disk/insert_bulk/location/multi_index/load=0/count=100 368.1±7.48µs 366.8±8.51µs -0.35%
stdb_raw/disk/insert_bulk/location/multi_index/load=1000/count=100 429.3±4.71µs 432.2±7.73µs +0.68%
stdb_raw/disk/insert_bulk/location/non_unique/load=0/count=100 164.3±0.84µs 164.4±1.90µs +0.06%
stdb_raw/disk/insert_bulk/location/non_unique/load=1000/count=100 190.0±2.30µs 193.0±6.34µs +1.58%
stdb_raw/disk/insert_bulk/location/unique/load=0/count=100 259.9±4.44µs 260.7±3.28µs +0.31%
stdb_raw/disk/insert_bulk/location/unique/load=1000/count=100 320.3±3.29µs 320.3±10.79µs 0.00%
stdb_raw/disk/insert_bulk/person/multi_index/load=0/count=100 739.7±12.55µs 743.5±8.09µs +0.51%
stdb_raw/disk/insert_bulk/person/multi_index/load=1000/count=100 818.7±13.85µs 827.3±10.60µs +1.05%
stdb_raw/disk/insert_bulk/person/non_unique/load=0/count=100 229.8±1.25µs 230.3±4.40µs +0.22%
stdb_raw/disk/insert_bulk/person/non_unique/load=1000/count=100 257.6±7.22µs 254.5±2.30µs -1.20%
stdb_raw/disk/insert_bulk/person/unique/load=0/count=100 422.7±3.85µs 421.7±4.86µs -0.24%
stdb_raw/disk/insert_bulk/person/unique/load=1000/count=100 479.9±3.90µs 475.4±11.43µs -0.94%
stdb_raw/disk/iterate/location/unique/count=100 7.0±0.07µs 139.6 KElem/sec N/A N/A
stdb_raw/disk/iterate/person/unique/count=100 8.3±0.09µs 117.5 KElem/sec N/A N/A
stdb_raw/mem/empty 102.8±1.24ns 102.6±0.82ns -0.19%
stdb_raw/mem/filter/string/indexed/load=1000/count=10 2.6±0.07µs 370.8 KElem/sec N/A N/A
stdb_raw/mem/filter/string/non_indexed/load=1000/count=10 93.2±0.57µs 10.5 KElem/sec N/A N/A
stdb_raw/mem/filter/u64/indexed/load=1000/count=10 2.5±0.05µs 396.8 KElem/sec N/A N/A
stdb_raw/mem/filter/u64/non_indexed/load=1000/count=10 75.5±0.51µs 12.9 KElem/sec N/A N/A
stdb_raw/mem/find_unique/u32/load=1000 563.0±6.60ns 1734.4 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/multi_index/load=0 5.0±0.08µs 196.9 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/multi_index/load=1000 26.8±0.90µs 36.4 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/non_unique/load=0 2.6±0.03µs 379.2 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/non_unique/load=1000 18.7±0.36µs 52.2 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/unique/load=0 3.5±0.02µs 279.5 KElem/sec N/A N/A
stdb_raw/mem/insert_1/location/unique/load=1000 23.3±0.74µs 41.9 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/multi_index/load=0 8.6±0.09µs 113.3 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/multi_index/load=1000 26.6±2.16µs 36.8 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/non_unique/load=0 3.2±0.05µs 305.8 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/non_unique/load=1000 14.1±0.45µs 69.4 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/unique/load=0 5.3±0.06µs 185.3 KElem/sec N/A N/A
stdb_raw/mem/insert_1/person/unique/load=1000 20.3±1.10µs 48.1 KElem/sec N/A N/A
stdb_raw/mem/insert_bulk/location/multi_index/load=0/count=100 379.2±9.26µs 371.4±4.78µs -2.06%
stdb_raw/mem/insert_bulk/location/multi_index/load=1000/count=100 420.9±2.58µs 418.0±16.54µs -0.69%
stdb_raw/mem/insert_bulk/location/non_unique/load=0/count=100 163.5±1.61µs 161.1±1.84µs -1.47%
stdb_raw/mem/insert_bulk/location/non_unique/load=1000/count=100 183.5±1.82µs 181.7±2.65µs -0.98%
stdb_raw/mem/insert_bulk/location/unique/load=0/count=100 262.9±2.29µs 255.2±3.90µs -2.93%
stdb_raw/mem/insert_bulk/location/unique/load=1000/count=100 311.8±2.28µs 304.8±2.79µs -2.25%
stdb_raw/mem/insert_bulk/person/multi_index/load=0/count=100 727.7±5.70µs 728.4±4.48µs +0.10%
stdb_raw/mem/insert_bulk/person/multi_index/load=1000/count=100 800.4±13.74µs 796.8±5.71µs -0.45%
stdb_raw/mem/insert_bulk/person/non_unique/load=0/count=100 225.7±0.72µs 225.9±2.18µs +0.09%
stdb_raw/mem/insert_bulk/person/non_unique/load=1000/count=100 250.5±4.49µs 248.2±1.16µs -0.92%
stdb_raw/mem/insert_bulk/person/unique/load=0/count=100 417.0±6.17µs 416.1±1.70µs -0.22%
stdb_raw/mem/insert_bulk/person/unique/load=1000/count=100 471.5±3.80µs 467.2±8.19µs -0.91%
stdb_raw/mem/iterate/location/unique/count=100 7.0±0.06µs 140.0 KElem/sec N/A N/A
stdb_raw/mem/iterate/person/unique/count=100 8.3±0.05µs 117.8 KElem/sec N/A N/A

Please sign in to comment.