From 21cced05c1dece28e3f1320751320dfacd2913ef Mon Sep 17 00:00:00 2001 From: cloudhead Date: Tue, 14 May 2024 16:34:30 +0200 Subject: [PATCH] node: Allow for "WAL" mode in sqlite This solves concurrency issues between the node and http daemon. --- radicle-cli/examples/rad-config.md | 3 +++ radicle-httpd/src/api/v1/profile.rs | 1 + radicle-node/src/runtime.rs | 2 +- radicle/src/node/config.rs | 14 +++++++++++++- radicle/src/node/db.rs | 26 ++++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/radicle-cli/examples/rad-config.md b/radicle-cli/examples/rad-config.md index dda65e1c..bd3c6840 100644 --- a/radicle-cli/examples/rad-config.md +++ b/radicle-cli/examples/rad-config.md @@ -26,6 +26,9 @@ $ rad config }, "connect": [], "externalAddresses": [], + "db": { + "journalMode": "rollback" + }, "tor": null, "network": "main", "log": "INFO", diff --git a/radicle-httpd/src/api/v1/profile.rs b/radicle-httpd/src/api/v1/profile.rs index 5916f902..7814803a 100644 --- a/radicle-httpd/src/api/v1/profile.rs +++ b/radicle-httpd/src/api/v1/profile.rs @@ -89,6 +89,7 @@ mod routes { }, "connect": [], "externalAddresses": [], + "db": { "journalMode": "rollback" }, "tor": null, "network": "main", "log": "INFO", diff --git a/radicle-node/src/runtime.rs b/radicle-node/src/runtime.rs index 0e8729e3..9406f129 100644 --- a/radicle-node/src/runtime.rs +++ b/radicle-node/src/runtime.rs @@ -156,7 +156,7 @@ impl Runtime { let policy = config.policy; log::info!(target: "node", "Opening node database.."); - let db = home.database_mut()?; + let db = home.database_mut()?.journal_mode(config.db.journal_mode)?; let mut stores: service::Stores<_> = db.clone().into(); log::info!(target: "node", "Opening policy database.."); diff --git a/radicle/src/node/config.rs b/radicle/src/node/config.rs index 4cc1a6a6..5d1bb160 100644 --- a/radicle/src/node/config.rs +++ b/radicle/src/node/config.rs @@ -7,7 +7,7 @@ use localtime::LocalDuration; use crate::node; use crate::node::policy::{Policy, Scope}; -use crate::node::{Address, Alias, NodeId}; +use crate::node::{db, Address, Alias, NodeId}; /// Target number of peers to maintain connections to. pub const TARGET_OUTBOUND_PEERS: usize = 8; @@ -260,6 +260,14 @@ pub enum TorConfig { Transparent, } +/// Database configuration. +#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DbConfig { + #[serde(default)] + pub journal_mode: db::JournalMode, +} + /// Service configuration. #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] @@ -279,6 +287,9 @@ pub struct Config { /// Specify the node's public addresses #[serde(default)] pub external_addresses: Vec
, + /// Database config. + #[serde(default)] + pub db: DbConfig, /// Tor configuration. #[serde(default)] pub tor: Option, @@ -321,6 +332,7 @@ impl Config { listen: vec![], connect: HashSet::default(), external_addresses: vec![], + db: DbConfig::default(), network: Network::default(), tor: None, relay: Relay::default(), diff --git a/radicle/src/node/db.rs b/radicle/src/node/db.rs index 6ac32515..71bfcda8 100644 --- a/radicle/src/node/db.rs +++ b/radicle/src/node/db.rs @@ -40,6 +40,19 @@ pub enum Error { NoRows, } +/// Database journal mode. +#[derive(Debug, Default, Copy, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum JournalMode { + /// "WAL" mode. Good for concurrent reads & writes, but keeps some extra files around. + #[serde(rename = "wal")] + WriteAheadLog, + /// Default "rollback" mode. Certain writes may block reads. + #[serde(alias = "rollback")] + #[default] + Rollback, +} + /// A file-backed database storing information about the network. #[derive(Clone)] pub struct Database { @@ -93,6 +106,19 @@ impl Database { Ok(Self { db: Arc::new(db) }) } + /// Set journal mode. + pub fn journal_mode(self, mode: JournalMode) -> Result { + match mode { + JournalMode::Rollback => { + self.db.execute("PRAGMA journal_mode = DELETE;")?; + } + JournalMode::WriteAheadLog => { + self.db.execute("PRAGMA journal_mode = WAL;")?; + } + } + Ok(self) + } + /// Create a new in-memory database. pub fn memory() -> Result { let db = sql::Connection::open_thread_safe(":memory:")?;