refactor(client): notify idle interval when pool drops
This commit is contained in:
		| @@ -38,12 +38,9 @@ struct PoolInner<T> { | ||||
|     // connection. | ||||
|     parked: HashMap<Arc<String>, VecDeque<oneshot::Sender<T>>>, | ||||
|     timeout: Option<Duration>, | ||||
|     // Used to prevent multiple intervals from being spawned to clear | ||||
|     // expired connections. | ||||
|     // | ||||
|     // TODO(0.12): Remove the need for this when Client::schedule_pool_timer | ||||
|     // can be done in Client::new. | ||||
|     expired_timer_spawned: bool, | ||||
|     // A oneshot channel is used to allow the interval to be notified when | ||||
|     // the Pool completely drops. That way, the interval can cancel immediately. | ||||
|     idle_interval_ref: Option<oneshot::Sender<Never>>, | ||||
| } | ||||
|  | ||||
| impl<T> Pool<T> { | ||||
| @@ -52,9 +49,9 @@ impl<T> Pool<T> { | ||||
|             inner: Arc::new(Mutex::new(PoolInner { | ||||
|                 enabled: enabled, | ||||
|                 idle: HashMap::new(), | ||||
|                 idle_interval_ref: None, | ||||
|                 parked: HashMap::new(), | ||||
|                 timeout: timeout, | ||||
|                 expired_timer_spawned: false, | ||||
|             })) | ||||
|         } | ||||
|     } | ||||
| @@ -222,20 +219,21 @@ impl<T: Closed> PoolInner<T> { | ||||
|  | ||||
| impl<T: Closed + Send + 'static> Pool<T> { | ||||
|     fn spawn_expired_interval(&mut self, cx: &mut task::Context) -> Result<(), ::Error> { | ||||
|         let dur = { | ||||
|         let (dur, rx) = { | ||||
|             let mut inner = self.inner.lock().unwrap(); | ||||
|  | ||||
|             if !inner.enabled { | ||||
|                 return Ok(()); | ||||
|             } | ||||
|  | ||||
|             if inner.expired_timer_spawned { | ||||
|             if inner.idle_interval_ref.is_some() { | ||||
|                 return Ok(()); | ||||
|             } | ||||
|             inner.expired_timer_spawned = true; | ||||
|  | ||||
|             if let Some(dur) = inner.timeout { | ||||
|                 dur | ||||
|                 let (tx, rx) = oneshot::channel(); | ||||
|                 inner.idle_interval_ref = Some(tx); | ||||
|                 (dur, rx) | ||||
|             } else { | ||||
|                 return Ok(()); | ||||
|             } | ||||
| @@ -245,6 +243,7 @@ impl<T: Closed + Send + 'static> Pool<T> { | ||||
|         super::execute(IdleInterval { | ||||
|             interval: interval, | ||||
|             pool: Arc::downgrade(&self.inner), | ||||
|             pool_drop_notifier: rx, | ||||
|         }, cx) | ||||
|     } | ||||
| } | ||||
| @@ -411,6 +410,10 @@ impl Expiration { | ||||
| struct IdleInterval<T> { | ||||
|     interval: Interval, | ||||
|     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> { | ||||
| @@ -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> { | ||||
|         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"))); | ||||
|  | ||||
|             if let Some(inner) = self.pool.upgrade() { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user