From 3ca713ea715bd139a1d6141ddc9b27ab90a1d747 Mon Sep 17 00:00:00 2001 From: amv-dev Date: Sat, 3 Apr 2021 22:09:58 +0500 Subject: [PATCH 1/2] refactor: `Arc` usage optimization in Pool Arc usage inside `Pool` reduced from 4 variables to a single variable. --- src/conn/pool.rs | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/conn/pool.rs b/src/conn/pool.rs index adbd942e..510fca08 100644 --- a/src/conn/pool.rs +++ b/src/conn/pool.rs @@ -55,6 +55,13 @@ impl InnerPool { } } +struct ArcedPool { + inner: (Mutex, Condvar), + min: AtomicUsize, + max: AtomicUsize, + count: AtomicUsize, +} + /// `Pool` serves to provide you with a [`PooledConn`](struct.PooledConn.html)'s. /// However you can prepare statements directly on `Pool` without /// invoking [`Pool::get_conn`](struct.Pool.html#method.get_conn). @@ -92,10 +99,7 @@ impl InnerPool { /// [`PooledConn`](struct.PooledConn.html) documentation. #[derive(Clone)] pub struct Pool { - inner: Arc<(Mutex, Condvar)>, - min: Arc, - max: Arc, - count: Arc, + arced_pool: Arc, check_health: bool, use_cache: bool, } @@ -118,7 +122,7 @@ impl Pool { None }; - let &(ref inner_pool, ref condvar) = &*self.inner; + let &(ref inner_pool, ref condvar) = &self.arced_pool.inner; let conn = if self.use_cache { if let Some(query) = stmt { @@ -146,9 +150,9 @@ impl Pool { if let Some(conn) = pool.pool.pop_front() { drop(pool); break conn; - } else if self.count.load(Ordering::Relaxed) < self.max.load(Ordering::Relaxed) { + } else if self.arced_pool.count.load(Ordering::Relaxed) < self.arced_pool.max.load(Ordering::Relaxed) { pool.new_conn()?; - self.count.fetch_add(1, Ordering::SeqCst); + self.arced_pool.count.fetch_add(1, Ordering::SeqCst); } else { pool = if let Some((start, timeout)) = times { if start.elapsed() > timeout { @@ -164,7 +168,7 @@ impl Pool { if call_ping && self.check_health && !conn.ping() { if let Err(err) = conn.reset() { - self.count.fetch_sub(1, Ordering::SeqCst); + self.arced_pool.count.fetch_sub(1, Ordering::SeqCst); return Err(err); } } @@ -184,10 +188,12 @@ impl Pool { pub fn new_manual>(min: usize, max: usize, opts: T) -> Result { let pool = InnerPool::new(min, max, opts.into())?; Ok(Pool { - inner: Arc::new((Mutex::new(pool), Condvar::new())), - min: Arc::new(AtomicUsize::new(min)), - max: Arc::new(AtomicUsize::new(max)), - count: Arc::new(AtomicUsize::new(min)), + arced_pool: Arc::new(ArcedPool { + inner: (Mutex::new(pool), Condvar::new()), + min: AtomicUsize::new(min), + max: AtomicUsize::new(max), + count: AtomicUsize::new(min), + }), use_cache: true, check_health: true, }) @@ -243,9 +249,9 @@ impl fmt::Debug for Pool { write!( f, "Pool {{ min: {}, max: {}, count: {} }}", - self.min.load(Ordering::Relaxed), - self.max.load(Ordering::Relaxed), - self.count.load(Ordering::Relaxed) + self.arced_pool.min.load(Ordering::Relaxed), + self.arced_pool.max.load(Ordering::Relaxed), + self.arced_pool.count.load(Ordering::Relaxed) ) } } @@ -298,16 +304,16 @@ impl Deref for PooledConn { impl Drop for PooledConn { fn drop(&mut self) { - if self.pool.count.load(Ordering::Relaxed) > self.pool.max.load(Ordering::Relaxed) + if self.pool.arced_pool.count.load(Ordering::Relaxed) > self.pool.arced_pool.max.load(Ordering::Relaxed) || self.conn.is_none() { - self.pool.count.fetch_sub(1, Ordering::SeqCst); + self.pool.arced_pool.count.fetch_sub(1, Ordering::SeqCst); } else { self.conn.as_mut().unwrap().set_local_infile_handler(None); - let mut pool = (self.pool.inner).0.lock().unwrap(); + let mut pool = (self.pool.arced_pool.inner).0.lock().unwrap(); pool.pool.push_back(self.conn.take().unwrap()); drop(pool); - (self.pool.inner).1.notify_one(); + (self.pool.arced_pool.inner).1.notify_one(); } } } From 6f5e46c03a5c7e75d0179e0ecb481c001640b262 Mon Sep 17 00:00:00 2001 From: amv-dev Date: Sat, 3 Apr 2021 22:30:44 +0500 Subject: [PATCH 2/2] refactor: reduced atomics usage in Pool There is no reason to `min` and `max` properties of Pool to be an atomic type, because they can't be updated since Pool's creation. So we can use regular `usize` instead which will be more performant. --- src/conn/pool.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/conn/pool.rs b/src/conn/pool.rs index 510fca08..3215d4c3 100644 --- a/src/conn/pool.rs +++ b/src/conn/pool.rs @@ -57,8 +57,8 @@ impl InnerPool { struct ArcedPool { inner: (Mutex, Condvar), - min: AtomicUsize, - max: AtomicUsize, + min: usize, + max: usize, count: AtomicUsize, } @@ -150,7 +150,7 @@ impl Pool { if let Some(conn) = pool.pool.pop_front() { drop(pool); break conn; - } else if self.arced_pool.count.load(Ordering::Relaxed) < self.arced_pool.max.load(Ordering::Relaxed) { + } else if self.arced_pool.count.load(Ordering::Relaxed) < self.arced_pool.max { pool.new_conn()?; self.arced_pool.count.fetch_add(1, Ordering::SeqCst); } else { @@ -190,8 +190,8 @@ impl Pool { Ok(Pool { arced_pool: Arc::new(ArcedPool { inner: (Mutex::new(pool), Condvar::new()), - min: AtomicUsize::new(min), - max: AtomicUsize::new(max), + min, + max, count: AtomicUsize::new(min), }), use_cache: true, @@ -249,8 +249,8 @@ impl fmt::Debug for Pool { write!( f, "Pool {{ min: {}, max: {}, count: {} }}", - self.arced_pool.min.load(Ordering::Relaxed), - self.arced_pool.max.load(Ordering::Relaxed), + self.arced_pool.min, + self.arced_pool.max, self.arced_pool.count.load(Ordering::Relaxed) ) } @@ -304,7 +304,7 @@ impl Deref for PooledConn { impl Drop for PooledConn { fn drop(&mut self) { - if self.pool.arced_pool.count.load(Ordering::Relaxed) > self.pool.arced_pool.max.load(Ordering::Relaxed) + if self.pool.arced_pool.count.load(Ordering::Relaxed) > self.pool.arced_pool.max || self.conn.is_none() { self.pool.arced_pool.count.fetch_sub(1, Ordering::SeqCst);