Skip to content

Commit 19f8c4f

Browse files
committed
PVC-705: switch to typed queries for performance benefits
Currently, each query requires three RTTs to the DB. By switching to typed queries, we can do the parse, bind and execute all in a single RTT. Queries which use `SqlNamespaceStatus` were not ported due to me not being able to figure out which type they have. It's a user-generated type, and I'm not sure there's a matching type in `postgres-types::Type`. In any case, this just means we eat the extra RTTs when creating or updating namespaces. This feels fine to me, since at least the hot path is able to be typed. Related tokio-postgres PR: sfackler/rust-postgres#1147
1 parent 2e614f0 commit 19f8c4f

File tree

2 files changed

+43
-32
lines changed

2 files changed

+43
-32
lines changed

crates/plexi-backend-postgres/src/schema/signature.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
use anyhow::Context;
12
use chrono::{DateTime, Utc};
23
use const_format::formatc;
34
use plexi_core::{Ciphersuite, Epoch, SignatureResponse};
4-
use postgres_types::{FromSql, ToSql};
5+
use postgres_types::{FromSql, ToSql, Type};
56
use tokio_postgres::{Row, Transaction};
67

78
use crate::schema::namespace::{SqlAccountId, SqlCiphersuite};
@@ -49,21 +50,21 @@ impl SqlSignature {
4950
tracing::info!("getting signature by epoch");
5051

5152
let row = tx
52-
.query_opt(
53+
.query_typed(
5354
formatc!(
5455
"SELECT {SIGNATURE_FIELDS}
5556
FROM signature
5657
WHERE account_id=$1 AND namespace=$2 AND epoch=$3",
5758
),
5859
&[
59-
&SqlAccountId::from(account_id),
60-
&namespace,
61-
&SqlEpoch::from(epoch),
60+
(&SqlAccountId::from(account_id), Type::INT8),
61+
(&namespace, Type::TEXT),
62+
(&SqlEpoch::from(epoch), Type::INT8),
6263
],
6364
)
6465
.await?;
6566

66-
row.map(SqlSignature::try_from).transpose()
67+
row.first().cloned().map(SqlSignature::try_from).transpose()
6768
}
6869

6970
pub async fn get_by_digest(
@@ -75,17 +76,21 @@ impl SqlSignature {
7576
tracing::info!("getting signature by digest");
7677

7778
let row = tx
78-
.query_opt(
79+
.query_typed(
7980
formatc!(
8081
"SELECT {SIGNATURE_FIELDS}
8182
FROM signature
8283
WHERE account_id=$1 AND namespace=$2 AND digest=$3",
8384
),
84-
&[&SqlAccountId::from(account_id), &namespace, &digest],
85+
&[
86+
(&SqlAccountId::from(account_id), Type::INT8),
87+
(&namespace, Type::TEXT),
88+
(&digest, Type::BYTEA),
89+
],
8590
)
8691
.await?;
8792

88-
row.map(SqlSignature::try_from).transpose()
93+
row.first().cloned().map(SqlSignature::try_from).transpose()
8994
}
9095

9196
/// In this flow, we assume that the transaction has serialized isolation level.
@@ -98,27 +103,30 @@ impl SqlSignature {
98103
tracing::info!("inserting signature");
99104

100105
let row = tx
101-
.query_one(
106+
.query_typed(
102107
formatc!(
103108
"INSERT INTO signature VALUES
104109
($1, $2, $3, $4, $5, $6, $7, $8, $9)
105110
RETURNING {SIGNATURE_FIELDS}",
106111
),
107112
&[
108-
&SqlAccountId::from(account_id), // $1
109-
&sig_resp.namespace(), // $2
110-
&SqlEpoch::from(*sig_resp.epoch()), // $3
111-
&ts_to_datetime(sig_resp.timestamp())?, //$4
112-
&sig_resp.digest().as_slice(), // $5
113-
&SqlCiphersuite::from(*sig_resp.ciphersuite()), // $6
114-
&sig_resp.signature().as_slice(), // $7
115-
&sig_resp.key_id().map(|v| vec![v]).unwrap_or_default(), // $8
116-
&sig_resp.serialized_message(), // $9
113+
(&SqlAccountId::from(account_id), Type::INT8), // $1
114+
(&sig_resp.namespace(), Type::TEXT), // $2
115+
(&SqlEpoch::from(*sig_resp.epoch()), Type::INT8), // $3
116+
(&ts_to_datetime(sig_resp.timestamp())?, Type::TIMESTAMPTZ), //$4
117+
(&sig_resp.digest().as_slice(), Type::BYTEA), // $5
118+
(&SqlCiphersuite::from(*sig_resp.ciphersuite()), Type::INT4), // $6
119+
(&sig_resp.signature().as_slice(), Type::BYTEA), // $7
120+
(
121+
&sig_resp.key_id().map(|v| vec![v]).unwrap_or_default(),
122+
Type::BYTEA,
123+
), // $8
124+
(&sig_resp.serialized_message(), Type::BYTEA), // $9
117125
],
118126
)
119127
.await?;
120128

121-
SqlSignature::try_from(row)
129+
SqlSignature::try_from(row.first().context("empty insert")?.clone())
122130
}
123131
}
124132

crates/plexi-backend-postgres/src/schema/signing_key.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use const_format::formatc;
44
use plexi_core::auditor::KeyInfo;
55
use plexi_core::crypto::ed25519_dalek::{SecretKey, SigningKey};
66
use plexi_core::crypto::KeyPair;
7+
use postgres_types::Type;
78
use tokio_postgres::{Row, Transaction};
89

910
#[derive(Debug, Clone, Copy)]
@@ -45,7 +46,7 @@ impl SqlSigningKey {
4546
tracing::info!("getting first available signing key");
4647

4748
let row = tx
48-
.query_opt(
49+
.query_typed(
4950
formatc!(
5051
"SELECT {SIGNING_KEY_FIELDS}
5152
FROM signing_key
@@ -57,7 +58,9 @@ impl SqlSigningKey {
5758
)
5859
.await?;
5960

60-
row.map(SqlSigningKey::try_from)
61+
row.first()
62+
.cloned()
63+
.map(SqlSigningKey::try_from)
6164
.transpose()?
6265
.context("auditor not initialized")
6366
}
@@ -66,7 +69,7 @@ impl SqlSigningKey {
6669
tracing::info!("getting all signing keys");
6770

6871
let row = tx
69-
.query(
72+
.query_typed(
7073
formatc!(
7174
"SELECT {SIGNING_KEY_FIELDS}
7275
FROM signing_key
@@ -84,25 +87,25 @@ impl SqlSigningKey {
8487

8588
pub async fn insert(&self, tx: &mut Transaction<'_>) -> anyhow::Result<SqlSigningKey> {
8689
let row = tx
87-
.query_one(
90+
.query_typed(
8891
formatc!(
8992
"INSERT INTO signing_key VALUES
9093
($1, $2, $3, $4, $5, $6, $7)
9194
RETURNING {SIGNING_KEY_FIELDS}"
9295
),
9396
&[
94-
&self.verifying_key, // $1
95-
&self.signing_key, // $2
96-
&(self.curve as i32), // $3
97-
&self.not_before, // $4
98-
&self.created_at, // $5
99-
&self.updated_at, // $6
100-
&self.disabled_at, // $7
97+
(&self.verifying_key, Type::BYTEA), // $1
98+
(&self.signing_key, Type::BYTEA), // $2
99+
(&(self.curve as i32), Type::INT4), // $3
100+
(&self.not_before, Type::TIMESTAMPTZ), // $4
101+
(&self.created_at, Type::TIMESTAMPTZ), // $5
102+
(&self.updated_at, Type::TIMESTAMPTZ), // $6
103+
(&self.disabled_at, Type::TIMESTAMPTZ), // $7
101104
],
102105
)
103106
.await?;
104107

105-
SqlSigningKey::try_from(row)
108+
SqlSigningKey::try_from(row.first().context("empty insert")?.clone())
106109
}
107110
}
108111

0 commit comments

Comments
 (0)