From 750cf8d4ee8409f04907083eba2bf782edc4a0d2 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 18 Jan 2026 19:45:50 +0000 Subject: [PATCH] Revert "Improve DB contention" This reverts commit 0e1849061bbbd35afbb92a9ca8e18b14996d8297. --- sync-server/src/app_state/database.rs | 30 ++++++++++++++------------- sync-server/src/consts.rs | 1 - 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/sync-server/src/app_state/database.rs b/sync-server/src/app_state/database.rs index 7308ec1a..95dbf5ec 100644 --- a/sync-server/src/app_state/database.rs +++ b/sync-server/src/app_state/database.rs @@ -10,7 +10,7 @@ use sqlx::{ConnectOptions, sqlite::SqliteConnectOptions, types::chrono::Utc}; pub mod models; use sqlx::{Pool, Sqlite, sqlite::SqlitePoolOptions}; -use tokio::sync::RwLock; +use tokio::sync::Mutex; use tokio::time::Instant; use uuid::fmt::Hyphenated; @@ -39,7 +39,7 @@ impl std::fmt::Debug for PoolWithTimestamp { pub struct Database { config: DatabaseConfig, broadcasts: Broadcasts, - connection_pools: Arc>>, + connection_pools: Arc>>, } pub type Transaction<'a> = sqlx::Transaction<'a, Sqlite>; @@ -83,7 +83,7 @@ impl Database { let database = Self { config: config.clone(), - connection_pools: Arc::new(RwLock::new(connection_pools)), + connection_pools: Arc::new(Mutex::new(connection_pools)), broadcasts: broadcasts.clone(), }; @@ -130,12 +130,11 @@ impl Database { } async fn get_connection_pool(&self, vault: &VaultId) -> Result> { - // Fast path: check if pool exists with a read lock (no blocking other readers) + // First, check if the pool exists without holding the lock during creation { - let pools = self.connection_pools.read().await; - if let Some(pool_with_timestamp) = pools.get(vault) { - // Skip updating last_accessed here - it's only used for idle cleanup - // and will be updated when the pool is created or reused after recreation + let mut pools = self.connection_pools.lock().await; + if let Some(pool_with_timestamp) = pools.get_mut(vault) { + pool_with_timestamp.last_accessed = Instant::now(); return Ok(pool_with_timestamp.pool.clone()); } } @@ -145,8 +144,8 @@ impl Database { // under high concurrency, but only one will be kept let new_pool = Self::create_vault_database(&self.config, vault).await?; - // Re-acquire lock (write) and insert (or use existing if another task created it) - let mut pools = self.connection_pools.write().await; + // Re-acquire lock and insert (or use existing if another task created it) + let mut pools = self.connection_pools.lock().await; let pool_with_timestamp = pools .entry(vault.clone()) .or_insert_with(|| PoolWithTimestamp { @@ -481,19 +480,22 @@ impl Database { Ok(()) } + /// Cleanup idle connection pools that haven't been accessed in more than 5 minutes async fn cleanup_idle_pools(&self) { - use crate::consts::IDLE_POOL_TIMEOUT; - - let mut pools = self.connection_pools.write().await; + let mut pools = self.connection_pools.lock().await; let now = Instant::now(); + let idle_timeout = Duration::from_secs(5 * 60); // 5 minutes + + // Collect vaults to remove let vaults_to_remove: Vec = pools .iter() .filter(|(_, pool_with_timestamp)| { - now.duration_since(pool_with_timestamp.last_accessed) > IDLE_POOL_TIMEOUT + now.duration_since(pool_with_timestamp.last_accessed) > idle_timeout }) .map(|(vault_id, _)| vault_id.clone()) .collect(); + // Close and remove idle pools for vault_id in &vaults_to_remove { if let Some(pool_with_timestamp) = pools.remove(vault_id) { info!("Closing idle database connection pool for vault `{vault_id}`"); diff --git a/sync-server/src/consts.rs b/sync-server/src/consts.rs index ca1d7fbf..9e9890c0 100644 --- a/sync-server/src/consts.rs +++ b/sync-server/src/consts.rs @@ -7,7 +7,6 @@ pub const DEFAULT_CONFIG_PATH: &str = "config.yml"; pub const DEFAULT_DATABASES_DIRECTORY_PATH: &str = "databases"; pub const DEFAULT_MAX_CONNECTIONS_PER_VAULT: u32 = 12; pub const DEFAULT_CURSOR_TIMEOUT: Duration = Duration::from_secs(60); -pub const IDLE_POOL_TIMEOUT: Duration = Duration::from_secs(5 * 60); pub const DEFAULT_HOST: &str = "127.0.0.1"; pub const DEFAULT_PORT: u16 = 3000;