Skip to content

Commit d4974cf

Browse files
committed
Merge branch 'release-mainnet-1.2.0-rc' into release-test-hash-id-migration-1.2.0
2 parents 6df71ba + e4ea214 commit d4974cf

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

  • crates/espresso/node/src/persistence
  • hotshot-query-service/src/data_source/storage/sql

crates/espresso/node/src/persistence/sql.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,19 @@ pub struct PostgresOptions {
106106
/// Use TLS for an encrypted connection to the database.
107107
#[clap(long, env = "ESPRESSO_NODE_POSTGRES_USE_TLS")]
108108
pub(crate) use_tls: bool,
109+
110+
/// Disable `DEFERRABLE` on read transactions for the query service.
111+
///
112+
/// When true, read transactions on Postgres start with `SERIALIZABLE READ ONLY` (no
113+
/// `DEFERRABLE`), so they begin immediately rather than waiting for a safe serializable
114+
/// snapshot. This trades start-up latency for the chance of a serialization-error retry,
115+
/// and is opt-in.
116+
#[clap(
117+
long,
118+
env = "ESPRESSO_NODE_POSTGRES_NO_DEFERRABLE",
119+
default_value_t = false
120+
)]
121+
pub(crate) no_deferrable: bool,
109122
}
110123

111124
impl Default for PostgresOptions {
@@ -349,6 +362,10 @@ impl From<PostgresOptions> for Config {
349362
cfg = cfg.slow_statement_threshold(Duration::from_secs(1));
350363
cfg = cfg.statement_timeout(Duration::from_secs(600)); // 10 minutes default
351364

365+
hotshot_query_service::data_source::storage::sql::set_no_deferrable_on_read(
366+
opt.no_deferrable,
367+
);
368+
352369
cfg
353370
}
354371
}
@@ -436,6 +453,10 @@ impl TryFrom<&Options> for Config {
436453
cfg.query_max_connections(opt.query_max_connections.unwrap_or(opt.max_connections));
437454
cfg =
438455
cfg.query_min_connections(opt.query_min_connections.unwrap_or(opt.min_connections));
456+
457+
hotshot_query_service::data_source::storage::sql::set_no_deferrable_on_read(
458+
opt.postgres_options.no_deferrable,
459+
);
439460
}
440461

441462
cfg = cfg.connection_timeout(opt.connection_timeout);

hotshot-query-service/src/data_source/storage/sql/transaction.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,24 @@ use crate::{
6868
types::HeightIndexed,
6969
};
7070

71+
/// When set to `true`, read transactions begin with
72+
/// `SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY` (no `DEFERRABLE`),
73+
/// so they start immediately instead of waiting for a safe serializable snapshot.
74+
#[cfg(not(feature = "embedded-db"))]
75+
static NO_DEFERRABLE_ON_READ: std::sync::atomic::AtomicBool =
76+
std::sync::atomic::AtomicBool::new(false);
77+
78+
/// Configure whether read transactions on Postgres should omit `DEFERRABLE`.
79+
///
80+
/// When `true`, `Read::begin` issues `SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY`
81+
/// (no `DEFERRABLE`) so the transaction starts immediately rather than waiting for a safe
82+
/// serializable snapshot. Default: `false`. Call this once at startup based on the operator's
83+
/// chosen configuration.
84+
#[cfg(not(feature = "embedded-db"))]
85+
pub fn set_no_deferrable_on_read(value: bool) {
86+
NO_DEFERRABLE_ON_READ.store(value, std::sync::atomic::Ordering::Relaxed);
87+
}
88+
7189
pub type Query<'q> = sqlx::query::Query<'q, Db, <Db as Database>::Arguments<'q>>;
7290
pub type QueryAs<'q, T> = sqlx::query::QueryAs<'q, Db, T, <Db as Database>::Arguments<'q>>;
7391

@@ -186,12 +204,23 @@ impl TransactionMode for Read {
186204
// (SERIALIZABLE), and we want to wait until this is possible rather than failing
187205
// (DEFERRABLE).
188206
//
207+
// Setting `ESPRESSO_NODE_POSTGRES_NO_DEFERRABLE=true` disables the DEFERRABLE
208+
// option, so that read transactions start immediately and may instead fail with a
209+
// serialization error if they conflict with a concurrent write. This trades start-up
210+
// latency for the chance of a retry, and is opt-in.
211+
//
189212
// With SQLite, there is nothing to be done here, as SQLite automatically starts
190213
// transactions in read-only mode, and always has serializable concurrency unless we
191214
// explicitly opt in to dirty reads with a pragma.
192215
#[cfg(not(feature = "embedded-db"))]
193-
conn.execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY, DEFERRABLE")
194-
.await?;
216+
{
217+
let sql = if NO_DEFERRABLE_ON_READ.load(std::sync::atomic::Ordering::Relaxed) {
218+
"SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY"
219+
} else {
220+
"SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY, DEFERRABLE"
221+
};
222+
conn.execute(sql).await?;
223+
}
195224

196225
Ok(())
197226
}

0 commit comments

Comments
 (0)