From 330103b466d30be25c16998e47989bad01acde8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Cig=C3=A1nek?= Date: Tue, 18 Jun 2024 15:24:43 +0200 Subject: [PATCH 1/3] fix race condition in pool close (#3217) --- sqlx-core/src/pool/inner.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/sqlx-core/src/pool/inner.rs b/sqlx-core/src/pool/inner.rs index 4254aee325..4b1d3beb2c 100644 --- a/sqlx-core/src/pool/inner.rs +++ b/sqlx-core/src/pool/inner.rs @@ -97,19 +97,14 @@ impl PoolInner { self.mark_closed(); async move { - for permits in 1..=self.options.max_connections { - // Close any currently idle connections in the pool. - while let Some(idle) = self.idle_conns.pop() { - let _ = idle.live.float((*self).clone()).close().await; - } - - if self.size() == 0 { - break; - } + let _permits = self.semaphore.acquire(self.options.max_connections).await; - // Wait for all permits to be released. - let _permits = self.semaphore.acquire(permits).await; + while let Some(idle) = self.idle_conns.pop() { + let _ = idle.live.raw.close().await; } + + self.num_idle.store(0, Ordering::Release); + self.size.store(0, Ordering::Release); } } From 396a75709be41b530969c68521d23a6c271b4e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Cig=C3=A1nek?= Date: Thu, 6 Feb 2025 13:04:25 +0100 Subject: [PATCH 2/3] fix deadlock in the postgres/listen example --- examples/postgres/listen/src/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/postgres/listen/src/main.rs b/examples/postgres/listen/src/main.rs index 587dab2a8f..fe39db73dc 100644 --- a/examples/postgres/listen/src/main.rs +++ b/examples/postgres/listen/src/main.rs @@ -68,6 +68,10 @@ async fn main() -> Result<(), Box> { } } + // The stream is holding one connection. It needs to be dropped to allow the connection to + // return to the pool, otherwise `pool.close()` would never return. + drop(stream); + pool.close().await; Ok(()) From 0c32efe3ed1194369cb7ffa52847079c2180e348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Sampaio?= Date: Mon, 28 Jul 2025 21:46:44 -0400 Subject: [PATCH 3/3] Only acquire as many permits as a child pool can offer --- sqlx-core/src/pool/inner.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sqlx-core/src/pool/inner.rs b/sqlx-core/src/pool/inner.rs index 4b1d3beb2c..b698dc9df0 100644 --- a/sqlx-core/src/pool/inner.rs +++ b/sqlx-core/src/pool/inner.rs @@ -97,7 +97,17 @@ impl PoolInner { self.mark_closed(); async move { - let _permits = self.semaphore.acquire(self.options.max_connections).await; + // For child pools, we need to acquire permits we actually have rather than + // max_connections + let permits_to_acquire = if self.options.parent_pool.is_some() { + // Child pools start with 0 permits, so we acquire based on current size + self.size() + } else { + // Parent pools can acquire all max_connections permits + self.options.max_connections + }; + + let _permits = self.semaphore.acquire(permits_to_acquire).await; while let Some(idle) = self.idle_conns.pop() { let _ = idle.live.raw.close().await;