Skip to content

Commit

Permalink
Remove email and recovery related identity endpoints (#1833)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsdt authored Oct 15, 2024
1 parent df5b78a commit 83310eb
Show file tree
Hide file tree
Showing 16 changed files with 50 additions and 723 deletions.
239 changes: 2 additions & 237 deletions crates/cli/src/subcommands/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ use crate::{
config::{Config, IdentityConfig},
util::{init_default, y_or_n, IdentityTokenJson, InitDefaultResultType},
};
use std::io::Write;

use crate::util::print_identity_config;
use anyhow::Context;
use clap::{Arg, ArgAction, ArgMatches, Command};
use email_address::EmailAddress;
use reqwest::{StatusCode, Url};
use serde::Deserialize;
use reqwest::Url;
use spacetimedb::auth::identity::decode_token;
use spacetimedb_client_api_messages::recovery::RecoveryCodeResponse;
use spacetimedb_lib::Identity;
use tabled::{
settings::{object::Columns, Alignment, Modify, Style},
Expand All @@ -29,15 +25,6 @@ pub fn cli() -> Command {

fn get_subcommands() -> Vec<Command> {
vec![
Command::new("find").about("Find an identity for an email")
.arg(
Arg::new("email")
.required(true)
.help("The email associated with the identity that you would like to find"),
)
.arg(common_args::server()
.help("The server to search for identities matching the email"),
),
Command::new("import")
.about("Import an existing identity into your spacetime config")
.arg(
Expand Down Expand Up @@ -113,20 +100,6 @@ fn get_subcommands() -> Vec<Command> {
.help("Nickname for this identity")
.conflicts_with("no-save"),
)
.arg(
Arg::new("email")
.long("email")
.short('e')
.help("Recovery email for this identity")
.conflicts_with("no-email"),
)
.arg(
Arg::new("no-email")
.long("no-email")
.help("Creates an identity without a recovery email")
.conflicts_with("email")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("default")
.help("Make the new identity the default for the server")
Expand All @@ -135,21 +108,6 @@ fn get_subcommands() -> Vec<Command> {
.conflicts_with("no-save")
.action(ArgAction::SetTrue),
),
Command::new("recover")
.about("Recover an existing identity and import it into your local config")
.arg(
Arg::new("email")
.required(true)
.help("The email associated with the identity that you would like to recover."),
)
.arg(common_args::identity().required(true).help(
"The identity you would like to recover. This identity must be associated with the email provided.",
).value_parser(clap::value_parser!(Identity)))
.arg(common_args::server()
.help("The server from which to request recovery codes"),
)
// TODO: project flag?
,
Command::new("remove")
.about("Removes a saved identity from your spacetime config")
.arg(common_args::identity()
Expand Down Expand Up @@ -191,31 +149,6 @@ fn get_subcommands() -> Vec<Command> {
)
// TODO: project flag?
,
Command::new("set-email")
.about("Associates an email address with an identity")
.arg(
common_args::identity()
.help("The identity string or name that should be associated with the email")
.required(true),
)
.arg(
Arg::new("email")
.help("The email that should be assigned to the provided identity")
.required(true),
)
.arg(
common_args::server()
.help("The server that should be informed of the email change")
.conflicts_with("all-servers")
)
.arg(
Arg::new("all-servers")
.long("all-servers")
.short('a')
.action(ArgAction::SetTrue)
.help("Inform all known servers of the email change")
.conflicts_with("server")
),
Command::new("set-name").about("Set the name of an identity or rename an existing identity nickname").arg(
common_args::identity()
.help("The identity string or name to be named. If a name is supplied, the corresponding identity will be renamed.")
Expand All @@ -241,10 +174,7 @@ async fn exec_subcommand(config: Config, cmd: &str, args: &ArgMatches) -> Result
"remove" => exec_remove(config, args).await,
"set-name" => exec_set_name(config, args).await,
"import" => exec_import(config, args).await,
"set-email" => exec_set_email(config, args).await,
"find" => exec_find(config, args).await,
"token" => exec_token(config, args).await,
"recover" => exec_recover(config, args).await,
unknown => Err(anyhow::anyhow!("Invalid subcommand: {}", unknown)),
}
}
Expand Down Expand Up @@ -370,21 +300,7 @@ async fn exec_new(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E
config.can_set_name(x)?;
}

let email = args.get_one::<String>("email");
let no_email = args.get_flag("no-email");
if email.is_none() && !no_email {
return Err(anyhow::anyhow!(
"You must either supply an email with --email <email>, or pass the --no-email flag."
));
}

let mut query_params = Vec::<(&str, &str)>::new();
if let Some(email) = email {
if !EmailAddress::is_valid(email.as_str()) {
return Err(anyhow::anyhow!("The email you provided is malformed: {}", email));
}
query_params.push(("email", email.as_str()))
}
let query_params = Vec::<(&str, &str)>::new();

let mut builder = reqwest::Client::new().post(Url::parse_with_params(
format!("{}/identity", config.get_host_url(server)?).as_str(),
Expand Down Expand Up @@ -413,7 +329,6 @@ async fn exec_new(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::E

println!(" IDENTITY {}", identity);
println!(" NAME {}", alias.unwrap_or(&String::new()));
println!(" EMAIL {}", email.unwrap_or(&String::new()));

Ok(())
}
Expand Down Expand Up @@ -510,45 +425,6 @@ Fetch the server's fingerprint with:
Ok(())
}

#[derive(Debug, Clone, Deserialize)]
struct GetIdentityResponse {
identities: Vec<GetIdentityResponseEntry>,
}

#[derive(Debug, Clone, Deserialize)]
struct GetIdentityResponseEntry {
identity: String,
email: String,
}

/// Executes the `identity find` command which finds an identity by email.
async fn exec_find(config: Config, args: &ArgMatches) -> Result<(), anyhow::Error> {
let email = args.get_one::<String>("email").unwrap().clone();
let server = args.get_one::<String>("server").map(|s| s.as_ref());
let client = reqwest::Client::new();
let builder = client.get(format!("{}/identity?email={}", config.get_host_url(server)?, email));

let res = builder.send().await?;

if res.status() == StatusCode::OK {
let response: GetIdentityResponse = res.json().await?;
if response.identities.is_empty() {
return Err(anyhow::anyhow!("Could not find identity for: {}", email));
}

for identity in response.identities {
println!("Identity");
println!(" IDENTITY {}", identity.identity);
println!(" EMAIL {}", identity.email);
}
Ok(())
} else if res.status() == StatusCode::NOT_FOUND {
Err(anyhow::anyhow!("Could not find identity for: {}", email))
} else {
Err(anyhow::anyhow!("Error occurred in lookup: {}", res.status()))
}
}

/// Executes the `identity token` command which prints the token for an identity.
async fn exec_token(config: Config, args: &ArgMatches) -> Result<(), anyhow::Error> {
let identity = args.get_one::<String>("identity").unwrap();
Expand All @@ -573,114 +449,3 @@ async fn exec_set_name(mut config: Config, args: &ArgMatches) -> Result<(), anyh
config.save();
Ok(())
}

/// Executes the `identity set-email` command which sets the email for an identity.
async fn exec_set_email(config: Config, args: &ArgMatches) -> Result<(), anyhow::Error> {
let email = args.get_one::<String>("email").unwrap().clone();
let server = args.get_one::<String>("server").map(|s| s.as_ref());
let identity = args.get_one::<String>("identity").unwrap();
let identity_config = config
.get_identity_config(identity)
.ok_or_else(|| anyhow::anyhow!("Missing identity credentials for identity: {identity}"))?;

// TODO: check that the identity is valid for the server

reqwest::Client::new()
.post(format!(
"{}/identity/{}/set-email?email={}",
config.get_host_url(server)?,
identity_config.identity,
email
))
.basic_auth("token", Some(&identity_config.token))
.send()
.await?
.error_for_status()?;

println!(" Associated email with identity");
print_identity_config(identity_config);
println!(" EMAIL {}", email);

Ok(())
}

/// Executes the `identity recover` command which recovers an identity from an email.
async fn exec_recover(mut config: Config, args: &ArgMatches) -> Result<(), anyhow::Error> {
let identity = args.get_one::<Identity>("identity").unwrap();
let email = args.get_one::<String>("email").unwrap();
let server = args.get_one::<String>("server").map(|s| s.as_ref());

let query_params = [
("email", email.as_str()),
("identity", &*identity.to_hex()),
("link", "false"),
];

if config.get_identity_config_by_identity(identity).is_some() {
return Err(anyhow::anyhow!("No need to recover this identity, it is already stored in your config. Use `spacetime identity list` to list identities."));
}

let client = reqwest::Client::new();
let builder = client.post(Url::parse_with_params(
format!("{}/identity/request_recovery_code", config.get_host_url(server)?,).as_str(),
query_params,
)?);
let res = builder.send().await?;
res.error_for_status()?;

println!(
"We have successfully sent a recovery code to {}. Enter the code now.",
email
);
for _ in 0..5 {
print!("Recovery Code: ");
std::io::stdout().flush()?;
let mut line = String::new();
std::io::stdin().read_line(&mut line).unwrap();
let code = match line.trim().parse::<u32>() {
Ok(value) => value,
Err(_) => {
println!("Malformed code. Please try again.");
continue;
}
};

let client = reqwest::Client::new();
let builder = client.post(Url::parse_with_params(
format!("{}/identity/confirm_recovery_code", config.get_host_url(server)?,).as_str(),
vec![
("code", code.to_string().as_str()),
("email", email.as_str()),
("identity", identity.to_hex().as_str()),
],
)?);
let res = builder.send().await?;
match res.error_for_status() {
Ok(res) => {
let buf = res.bytes().await?.to_vec();
let utf8 = String::from_utf8(buf)?;
let response: RecoveryCodeResponse = serde_json::from_str(utf8.as_str())?;
let identity_config = IdentityConfig {
nickname: None,
identity: response.identity,
token: response.token,
};
config.identity_configs_mut().push(identity_config.clone());
config.set_default_identity_if_unset(server, &identity_config.identity.to_hex())?;
config.save();
println!("Success. Identity imported.");
print_identity_config(&identity_config);
// TODO: Remove this once print_identity_config prints email
println!(" EMAIL {}", email);
return Ok(());
}
Err(_) => {
println!("Invalid recovery code, please try again.");
}
}
}

Err(anyhow::anyhow!(
"Maximum amount of attempts reached. Please start the process over."
))
}
1 change: 0 additions & 1 deletion crates/client-api-messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@
pub mod energy;
pub mod name;
pub mod recovery;
pub mod timestamp;
pub mod websocket;
19 changes: 0 additions & 19 deletions crates/client-api-messages/src/recovery.rs

This file was deleted.

11 changes: 10 additions & 1 deletion crates/client-api/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use axum::response::IntoResponse;
use axum_extra::typed_header::TypedHeader;
use headers::{authorization, HeaderMapExt};
use http::{request, HeaderValue, StatusCode};
use rand::Rng;
use serde::Deserialize;
use spacetimedb::auth::identity::{
decode_token, encode_token, DecodingKey, EncodingKey, JwtError, JwtErrorKind, SpacetimeIdentityClaims,
Expand Down Expand Up @@ -96,7 +97,15 @@ pub struct SpacetimeAuth {
impl SpacetimeAuth {
/// Allocate a new identity, and mint a new token for it.
pub async fn alloc(ctx: &(impl NodeDelegate + ControlStateDelegate + ?Sized)) -> axum::response::Result<Self> {
let identity = ctx.create_identity().await.map_err(log_and_500)?;
// TODO: I'm just sticking in a random string until we change how identities are generated.
let identity = {
let mut rng = rand::thread_rng();
let mut random_bytes = [0u8; 16]; // Example: 16 random bytes
rng.fill(&mut random_bytes);

let preimg = [b"clockworklabs:", &random_bytes[..]].concat();
Identity::from_hashing_bytes(preimg)
};
let creds = SpacetimeCreds::encode_token(ctx.private_key(), identity).map_err(log_and_500)?;
Ok(Self { creds, identity })
}
Expand Down
Loading

2 comments on commit 83310eb

@github-actions
Copy link

@github-actions github-actions bot commented on 83310eb Oct 15, 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.8±2.23ns 421.3±1.67ns - -
sqlite 🧠 400.8±1.52ns 411.5±1.51ns - -
stdb_raw 💿 626.0±0.88ns 626.1±1.00ns - -
stdb_raw 🧠 626.1±3.41ns 625.9±1.13ns - -

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 588.6±1.07µs 586.5±1.68µs 1698 tx/sec 1705 tx/sec
sqlite 💿 u32_u64_str unique_0 2048 256 151.6±0.29µs 158.1±10.95µs 6.4 Ktx/sec 6.2 Ktx/sec
sqlite 💿 u32_u64_u64 btree_each_column 2048 256 472.3±0.72µs 470.4±0.62µs 2.1 Ktx/sec 2.1 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 2048 256 140.0±1.45µs 139.9±0.73µs 7.0 Ktx/sec 7.0 Ktx/sec
sqlite 🧠 u32_u64_str btree_each_column 2048 256 452.0±0.62µs 446.2±0.45µs 2.2 Ktx/sec 2.2 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 2048 256 124.2±0.91µs 123.8±0.84µs 7.9 Ktx/sec 7.9 Ktx/sec
sqlite 🧠 u32_u64_u64 btree_each_column 2048 256 371.5±0.61µs 370.9±0.84µs 2.6 Ktx/sec 2.6 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 2048 256 112.3±0.39µs 106.9±0.59µs 8.7 Ktx/sec 9.1 Ktx/sec
stdb_raw 💿 u32_u64_str btree_each_column 2048 256 634.0±18.36µs 644.1±16.20µs 1577 tx/sec 1552 tx/sec
stdb_raw 💿 u32_u64_str unique_0 2048 256 497.6±19.61µs 497.0±19.12µs 2009 tx/sec 2011 tx/sec
stdb_raw 💿 u32_u64_u64 btree_each_column 2048 256 392.0±6.76µs 381.0±6.51µs 2.5 Ktx/sec 2.6 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 2048 256 321.4±6.28µs 348.7±10.99µs 3.0 Ktx/sec 2.8 Ktx/sec
stdb_raw 🧠 u32_u64_str btree_each_column 2048 256 310.1±0.55µs 308.6±0.29µs 3.1 Ktx/sec 3.2 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 2048 256 244.9±0.29µs 242.4±0.33µs 4.0 Ktx/sec 4.0 Ktx/sec
stdb_raw 🧠 u32_u64_u64 btree_each_column 2048 256 246.0±0.38µs 247.0±0.10µs 4.0 Ktx/sec 4.0 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 2048 256 221.8±0.36µs 222.0±0.18µs 4.4 Ktx/sec 4.4 Ktx/sec

iterate

db on disk schema indices new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str unique_0 21.9±0.18µs 21.8±0.06µs 44.6 Ktx/sec 44.7 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 20.5±0.24µs 19.4±0.15µs 47.7 Ktx/sec 50.3 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 19.3±0.31µs 19.3±0.23µs 50.5 Ktx/sec 50.6 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 18.2±0.25µs 17.0±0.09µs 53.7 Ktx/sec 57.3 Ktx/sec
stdb_raw 💿 u32_u64_str unique_0 4.8±0.00µs 4.0±0.00µs 205.5 Ktx/sec 246.6 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 4.6±0.00µs 3.9±0.00µs 210.2 Ktx/sec 253.0 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 4.7±0.00µs 4.0±0.00µs 205.9 Ktx/sec 246.8 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 4.6±0.00µs 3.9±0.00µs 210.3 Ktx/sec 253.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 70.3±0.28µs 67.5±0.20µs 13.9 Ktx/sec 14.5 Ktx/sec
sqlite 💿 u64 index 2048 256 68.0±0.32µs 62.0±0.17µs 14.4 Ktx/sec 15.7 Ktx/sec
sqlite 🧠 string index 2048 256 66.5±0.28µs 63.3±0.19µs 14.7 Ktx/sec 15.4 Ktx/sec
sqlite 🧠 u64 index 2048 256 62.4±0.41µs 57.3±0.11µs 15.6 Ktx/sec 17.0 Ktx/sec
stdb_raw 💿 string index 2048 256 4.9±0.00µs 4.9±0.00µs 199.1 Ktx/sec 198.8 Ktx/sec
stdb_raw 💿 u64 index 2048 256 4.7±0.00µs 4.8±0.00µs 208.2 Ktx/sec 205.0 Ktx/sec
stdb_raw 🧠 string index 2048 256 4.9±0.00µs 4.9±0.00µs 199.1 Ktx/sec 198.8 Ktx/sec
stdb_raw 🧠 u64 index 2048 256 4.7±0.00µs 4.8±0.00µs 208.5 Ktx/sec 205.2 Ktx/sec

serialize

schema format count new latency old latency new throughput old throughput
u32_u64_str bflatn_to_bsatn_fast_path 100 3.3±0.01µs 3.3±0.01µs 29.1 Mtx/sec 29.2 Mtx/sec
u32_u64_str bflatn_to_bsatn_slow_path 100 3.5±0.00µs 3.4±0.01µs 27.6 Mtx/sec 28.3 Mtx/sec
u32_u64_str bsatn 100 2.4±0.01µs 2.4±0.02µs 39.2 Mtx/sec 40.2 Mtx/sec
u32_u64_str bsatn 100 40.5±0.09ns 40.5±0.09ns 2.3 Gtx/sec 2.3 Gtx/sec
u32_u64_str json 100 4.9±0.03µs 5.1±0.06µs 19.3 Mtx/sec 18.9 Mtx/sec
u32_u64_str json 100 8.3±0.11µs 8.5±0.05µs 11.5 Mtx/sec 11.2 Mtx/sec
u32_u64_str product_value 100 1016.0±0.66ns 1014.8±0.62ns 93.9 Mtx/sec 94.0 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_fast_path 100 1123.9±1.11ns 1101.0±12.16ns 84.9 Mtx/sec 86.6 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_slow_path 100 2.8±0.00µs 2.8±0.04µs 34.4 Mtx/sec 34.4 Mtx/sec
u32_u64_u64 bsatn 100 1709.1±31.56ns 1722.1±27.87ns 55.8 Mtx/sec 55.4 Mtx/sec
u32_u64_u64 bsatn 100 39.3±0.10ns 39.3±0.05ns 2.4 Gtx/sec 2.4 Gtx/sec
u32_u64_u64 json 100 3.4±0.03µs 3.2±0.05µs 28.4 Mtx/sec 30.2 Mtx/sec
u32_u64_u64 json 100 5.0±0.09µs 5.2±0.00µs 19.0 Mtx/sec 18.4 Mtx/sec
u32_u64_u64 product_value 100 1013.5±1.67ns 1014.5±1.38ns 94.1 Mtx/sec 94.0 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_fast_path 100 895.3±0.76ns 892.2±1.94ns 106.5 Mtx/sec 106.9 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_slow_path 100 2.8±0.01µs 2.8±0.01µs 34.3 Mtx/sec 34.3 Mtx/sec
u64_u64_u32 bsatn 100 1719.1±30.47ns 1701.5±32.51ns 55.5 Mtx/sec 56.1 Mtx/sec
u64_u64_u32 bsatn 100 751.3±0.32ns 1093.3±2.68ns 126.9 Mtx/sec 87.2 Mtx/sec
u64_u64_u32 json 100 3.3±0.03µs 3.2±0.04µs 28.7 Mtx/sec 30.1 Mtx/sec
u64_u64_u32 json 100 5.0±0.01µs 4.9±0.19µs 19.1 Mtx/sec 19.3 Mtx/sec
u64_u64_u32 product_value 100 1014.5±0.49ns 1014.9±0.62ns 94.0 Mtx/sec 94.0 Mtx/sec

stdb_module_large_arguments

arg size new latency old latency new throughput old throughput
64KiB 116.2±12.20µs 109.5±6.71µs - -

stdb_module_print_bulk

line count new latency old latency new throughput old throughput
1 56.7±6.02µs 55.2±5.89µs - -
100 596.8±7.16µs 602.4±8.58µs - -
1000 3.5±0.47ms 3.7±0.65ms - -

remaining

name new latency old latency new throughput old throughput
special/db_game/circles/load=10 297.9±3.46µs 292.7±2.12µs - -
special/db_game/circles/load=100 299.2±2.35µs 291.2±2.80µs - -
special/db_game/ia_loop/load=10 0.0±0.00ns 0.0±0.00ns - -
special/db_game/ia_loop/load=100 0.0±0.00ns 0.0±0.00ns - -
sqlite/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 55.3±0.42µs 53.6±0.51µs 17.7 Ktx/sec 18.2 Ktx/sec
sqlite/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 47.5±0.04µs 45.8±0.17µs 20.6 Ktx/sec 21.3 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 40.4±0.32µs 39.4±0.27µs 24.2 Ktx/sec 24.8 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 36.4±0.23µs 35.1±0.23µs 26.9 Ktx/sec 27.8 Ktx/sec
stdb_module/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 1274.0±10.34µs 1277.2±25.55µs 784 tx/sec 782 tx/sec
stdb_module/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 1047.9±10.52µs 1033.2±17.44µs 954 tx/sec 967 tx/sec
stdb_raw/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 551.7±13.88µs 638.2±20.43µs 1812 tx/sec 1566 tx/sec
stdb_raw/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 494.0±13.86µs 491.4±11.22µs 2024 tx/sec 2035 tx/sec
stdb_raw/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 376.4±0.22µs 379.5±0.34µs 2.6 Ktx/sec 2.6 Ktx/sec
stdb_raw/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 339.4±0.46µs 340.5±0.27µs 2.9 Ktx/sec 2.9 Ktx/sec

@github-actions
Copy link

@github-actions github-actions bot commented on 83310eb Oct 15, 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 5386 5386 0.00% 5496 5500 -0.07%
sqlite 5509 5509 0.00% 5963 6009 -0.77%

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 75563 75563 0.00% 76201 76205 -0.01%
stdb_raw u32_u64_str no_index 64 128 2 string 117974 117974 0.00% 118710 118846 -0.11%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 24066 24065 0.00% 24810 24737 0.30%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 23033 23033 0.00% 23691 23595 0.41%
sqlite u32_u64_str no_index 64 128 2 string 144677 144677 0.00% 146147 146139 0.01%
sqlite u32_u64_str no_index 64 128 1 u64 124027 124027 0.00% 125327 125363 -0.03%
sqlite u32_u64_str btree_each_column 64 128 1 u64 131344 131344 0.00% 132828 132692 0.10%
sqlite u32_u64_str btree_each_column 64 128 2 string 134476 134476 0.00% 136150 136070 0.06%

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 901710 902067 -0.04% 957242 949525 0.81%
stdb_raw u32_u64_str btree_each_column 64 128 1054294 1052609 0.16% 1123680 1118167 0.49%
sqlite u32_u64_str unique_0 64 128 398158 398158 0.00% 415810 413020 0.68%
sqlite u32_u64_str btree_each_column 64 128 983475 983475 0.00% 1022491 1016491 0.59%

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 152816 152816 0.00% 152902 152970 -0.04%
stdb_raw u32_u64_str unique_0 64 15841 15841 0.00% 15923 15991 -0.43%
sqlite u32_u64_str unique_0 1024 1046653 1046659 -0.00% 1050025 1050201 -0.02%
sqlite u32_u64_str unique_0 64 74799 74799 0.00% 75893 75893 0.00%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47374 47374 0.00% 49958 49958 0.00%
64 bsatn 25716 25716 0.00% 27960 27994 -0.12%
16 bsatn 8117 8117 0.00% 9443 9477 -0.36%
16 json 12126 12126 0.00% 13962 13962 0.00%

callgrind: update bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 1024 20725012 20905561 -0.86% 21338852 21409327 -0.33%
stdb_raw u32_u64_str unique_0 64 128 1308438 1307940 0.04% 1383722 1374390 0.68%
sqlite u32_u64_str unique_0 1024 1024 1802091 1802091 0.00% 1811187 1811271 -0.00%
sqlite u32_u64_str unique_0 64 128 128437 128437 0.00% 131289 131297 -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 5396 5396 0.00% 5506 5510 -0.07%
sqlite 5551 5551 0.00% 6057 6115 -0.95%

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 75573 75573 0.00% 76203 76207 -0.01%
stdb_raw u32_u64_str no_index 64 128 2 string 118005 117984 0.02% 118753 118784 -0.03%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 24076 24075 0.00% 24820 24747 0.29%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 23043 23043 0.00% 23705 23601 0.44%
sqlite u32_u64_str no_index 64 128 1 u64 125948 125948 0.00% 127500 127572 -0.06%
sqlite u32_u64_str no_index 64 128 2 string 146598 146598 0.00% 148380 148424 -0.03%
sqlite u32_u64_str btree_each_column 64 128 2 string 136616 136598 0.01% 138684 138562 0.09%
sqlite u32_u64_str btree_each_column 64 128 1 u64 133440 133440 0.00% 135202 135098 0.08%

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 850002 851285 -0.15% 902530 898029 0.50%
stdb_raw u32_u64_str btree_each_column 64 128 1001614 1002178 -0.06% 1069088 1066230 0.27%
sqlite u32_u64_str unique_0 64 128 415695 415695 0.00% 432651 429823 0.66%
sqlite u32_u64_str btree_each_column 64 128 1021736 1021736 0.00% 1059282 1053364 0.56%

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 152826 152826 0.00% 152904 152972 -0.04%
stdb_raw u32_u64_str unique_0 64 15851 15851 0.00% 15929 15997 -0.43%
sqlite u32_u64_str unique_0 1024 1049721 1049721 0.00% 1053503 1053435 0.01%
sqlite u32_u64_str unique_0 64 76571 76571 0.00% 77885 77837 0.06%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47374 47374 0.00% 49958 49958 0.00%
64 bsatn 25716 25716 0.00% 27960 27994 -0.12%
16 bsatn 8117 8117 0.00% 9443 9477 -0.36%
16 json 12126 12126 0.00% 13962 13962 0.00%

callgrind: update bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 1024 19424772 19425499 -0.00% 20117548 20011577 0.53%
stdb_raw u32_u64_str unique_0 64 128 1261177 1261172 0.00% 1332817 1327982 0.36%
sqlite u32_u64_str unique_0 1024 1024 1809652 1809652 0.00% 1818284 1818212 0.00%
sqlite u32_u64_str unique_0 64 128 132563 132563 0.00% 135543 135475 0.05%

Please sign in to comment.