refactor(client): notify idle interval when pool drops
This commit is contained in:
@@ -38,12 +38,9 @@ struct PoolInner<T> {
|
|||||||
// connection.
|
// connection.
|
||||||
parked: HashMap<Arc<String>, VecDeque<oneshot::Sender<T>>>,
|
parked: HashMap<Arc<String>, VecDeque<oneshot::Sender<T>>>,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
// Used to prevent multiple intervals from being spawned to clear
|
// A oneshot channel is used to allow the interval to be notified when
|
||||||
// expired connections.
|
// the Pool completely drops. That way, the interval can cancel immediately.
|
||||||
//
|
idle_interval_ref: Option<oneshot::Sender<Never>>,
|
||||||
// TODO(0.12): Remove the need for this when Client::schedule_pool_timer
|
|
||||||
// can be done in Client::new.
|
|
||||||
expired_timer_spawned: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Pool<T> {
|
impl<T> Pool<T> {
|
||||||
@@ -52,9 +49,9 @@ impl<T> Pool<T> {
|
|||||||
inner: Arc::new(Mutex::new(PoolInner {
|
inner: Arc::new(Mutex::new(PoolInner {
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
idle: HashMap::new(),
|
idle: HashMap::new(),
|
||||||
|
idle_interval_ref: None,
|
||||||
parked: HashMap::new(),
|
parked: HashMap::new(),
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
expired_timer_spawned: false,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,20 +219,21 @@ impl<T: Closed> PoolInner<T> {
|
|||||||
|
|
||||||
impl<T: Closed + Send + 'static> Pool<T> {
|
impl<T: Closed + Send + 'static> Pool<T> {
|
||||||
fn spawn_expired_interval(&mut self, cx: &mut task::Context) -> Result<(), ::Error> {
|
fn spawn_expired_interval(&mut self, cx: &mut task::Context) -> Result<(), ::Error> {
|
||||||
let dur = {
|
let (dur, rx) = {
|
||||||
let mut inner = self.inner.lock().unwrap();
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
|
||||||
if !inner.enabled {
|
if !inner.enabled {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if inner.expired_timer_spawned {
|
if inner.idle_interval_ref.is_some() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
inner.expired_timer_spawned = true;
|
|
||||||
|
|
||||||
if let Some(dur) = inner.timeout {
|
if let Some(dur) = inner.timeout {
|
||||||
dur
|
let (tx, rx) = oneshot::channel();
|
||||||
|
inner.idle_interval_ref = Some(tx);
|
||||||
|
(dur, rx)
|
||||||
} else {
|
} else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -245,6 +243,7 @@ impl<T: Closed + Send + 'static> Pool<T> {
|
|||||||
super::execute(IdleInterval {
|
super::execute(IdleInterval {
|
||||||
interval: interval,
|
interval: interval,
|
||||||
pool: Arc::downgrade(&self.inner),
|
pool: Arc::downgrade(&self.inner),
|
||||||
|
pool_drop_notifier: rx,
|
||||||
}, cx)
|
}, cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -411,6 +410,10 @@ impl Expiration {
|
|||||||
struct IdleInterval<T> {
|
struct IdleInterval<T> {
|
||||||
interval: Interval,
|
interval: Interval,
|
||||||
pool: Weak<Mutex<PoolInner<T>>>,
|
pool: Weak<Mutex<PoolInner<T>>>,
|
||||||
|
// This allows the IdleInterval to be notified as soon as the entire
|
||||||
|
// Pool is fully dropped, and shutdown. This channel is never sent on,
|
||||||
|
// but Err(Canceled) will be received when the Pool is dropped.
|
||||||
|
pool_drop_notifier: oneshot::Receiver<Never>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Closed + 'static> Future for IdleInterval<T> {
|
impl<T: Closed + 'static> Future for IdleInterval<T> {
|
||||||
@@ -419,6 +422,15 @@ impl<T: Closed + 'static> Future for IdleInterval<T> {
|
|||||||
|
|
||||||
fn poll(&mut self, cx: &mut task::Context) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self, cx: &mut task::Context) -> Poll<Self::Item, Self::Error> {
|
||||||
loop {
|
loop {
|
||||||
|
match self.pool_drop_notifier.poll(cx) {
|
||||||
|
Ok(Async::Ready(n)) => match n {},
|
||||||
|
Ok(Async::Pending) => (),
|
||||||
|
Err(_canceled) => {
|
||||||
|
trace!("pool closed, canceling idle interval");
|
||||||
|
return Ok(Async::Ready(()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try_ready!(self.interval.poll_next(cx).map_err(|_| unreachable!("interval cannot error")));
|
try_ready!(self.interval.poll_next(cx).map_err(|_| unreachable!("interval cannot error")));
|
||||||
|
|
||||||
if let Some(inner) = self.pool.upgrade() {
|
if let Some(inner) = self.pool.upgrade() {
|
||||||
|
|||||||
Reference in New Issue
Block a user