diff --git a/Cargo.toml b/Cargo.toml index 422eccb5..e80d1506 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,10 @@ readme = "README.md" keywords = ["database", "pool"] edition = "2018" +[features] +default = ["parking_lot"] + [dependencies] log = "0.4" -parking_lot = "0.12" +parking_lot = { version = "0.12", optional = true } scheduled-thread-pool = "0.2" diff --git a/src/lib.rs b/src/lib.rs index 596eb980..25a81df2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,6 @@ use log::error; -use parking_lot::{Condvar, Mutex, MutexGuard}; use std::cmp; use std::error; use std::fmt; @@ -56,10 +55,12 @@ use crate::config::Config; use crate::event::{AcquireEvent, CheckinEvent, CheckoutEvent, ReleaseEvent, TimeoutEvent}; pub use crate::event::{HandleEvent, NopEventHandler}; pub use crate::extensions::Extensions; +use crate::sync::*; mod config; pub mod event; mod extensions; +mod sync; #[cfg(test)] mod test; @@ -395,7 +396,10 @@ where let initial_size = self.0.config.min_idle.unwrap_or(self.0.config.max_size); while internals.num_conns != initial_size { - if self.0.cond.wait_until(&mut internals, end).timed_out() { + let (guard, result) = self.0.cond.wait_until(internals, end); + internals = guard; + + if result.timed_out() { return Err(Error(internals.last_error.take())); } } @@ -435,7 +439,10 @@ where add_connection(&self.0, &mut internals); - if self.0.cond.wait_until(&mut internals, end).timed_out() { + let (guard, result) = self.0.cond.wait_until(internals, end); + internals = guard; + + if result.timed_out() { let event = TimeoutEvent { timeout }; self.0.config.event_handler.handle_timeout(event); diff --git a/src/sync.rs b/src/sync.rs new file mode 100644 index 00000000..36c66fa2 --- /dev/null +++ b/src/sync.rs @@ -0,0 +1,97 @@ +#[cfg(feature = "parking_lot")] +mod parking_lot_mutex { + pub(crate) use parking_lot::{MutexGuard, WaitTimeoutResult}; + use std::time::Instant; + + pub(crate) struct Mutex(parking_lot::Mutex); + + impl Mutex { + #[inline] + pub fn new(t: T) -> Self { + Self(parking_lot::Mutex::new(t)) + } + + #[inline] + pub fn lock(&self) -> MutexGuard { + self.0.lock() + } + } + + pub(crate) struct Condvar(parking_lot::Condvar); + + impl Condvar { + #[inline] + pub fn new() -> Self { + Self(parking_lot::Condvar::new()) + } + + #[inline] + pub fn notify_one(&self) { + self.0.notify_one(); + } + + #[inline] + pub fn wait_until<'a, T>( + &self, + mut mutex_guard: MutexGuard<'a, T>, + timeout: Instant, + ) -> (MutexGuard<'a, T>, WaitTimeoutResult) { + let wait_result = self.0.wait_until(&mut mutex_guard, timeout); + + (mutex_guard, wait_result) + } + } +} +#[cfg(feature = "parking_lot")] +pub(crate) use parking_lot_mutex::*; + +#[cfg(not(feature = "parking_lot"))] +mod std_mutex { + pub(crate) use std::sync::{MutexGuard, WaitTimeoutResult}; + use std::{sync::PoisonError, time::Instant}; + + pub(crate) struct Mutex(std::sync::Mutex); + + impl Mutex { + #[inline] + pub fn new(t: T) -> Self { + Self(std::sync::Mutex::new(t)) + } + + #[inline] + pub fn lock(&self) -> MutexGuard { + self.0.lock().unwrap_or_else(PoisonError::into_inner) + } + } + + pub(crate) struct Condvar(std::sync::Condvar); + + impl Condvar { + #[inline] + pub fn new() -> Self { + Self(std::sync::Condvar::new()) + } + + #[inline] + pub fn notify_one(&self) { + self.0.notify_one() + } + + #[inline] + pub fn wait_until<'a, T>( + &self, + mutex_guard: MutexGuard<'a, T>, + timeout: Instant, + ) -> (MutexGuard<'a, T>, WaitTimeoutResult) { + let timeout = timeout + .checked_duration_since(Instant::now()) + .unwrap_or_default(); + + self.0 + .wait_timeout(mutex_guard, timeout) + .unwrap_or_else(PoisonError::into_inner) + } + } +} +#[cfg(not(feature = "parking_lot"))] +pub(crate) use std_mutex::*;