refactor(client): pass internal executor to h2 dispatcher
This commit is contained in:
		| @@ -425,12 +425,10 @@ impl Builder { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* |  | ||||||
|     pub(super) fn exec(&mut self, exec: Exec) -> &mut Builder { |     pub(super) fn exec(&mut self, exec: Exec) -> &mut Builder { | ||||||
|         self.exec = exec; |         self.exec = exec; | ||||||
|         self |         self | ||||||
|     } |     } | ||||||
|     */ |  | ||||||
|  |  | ||||||
|     pub(super) fn h1_writev(&mut self, enabled: bool) -> &mut Builder { |     pub(super) fn h1_writev(&mut self, enabled: bool) -> &mut Builder { | ||||||
|         self.h1_writev = enabled; |         self.h1_writev = enabled; | ||||||
|   | |||||||
| @@ -61,8 +61,8 @@ impl Destination { | |||||||
|     pub fn scheme(&self) -> &str { |     pub fn scheme(&self) -> &str { | ||||||
|         self.uri |         self.uri | ||||||
|             .scheme_part() |             .scheme_part() | ||||||
|             .expect("destination uri has scheme") |             .map(|s| s.as_str()) | ||||||
|             .as_str() |             .unwrap_or("") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get the hostname. |     /// Get the hostname. | ||||||
| @@ -70,7 +70,7 @@ impl Destination { | |||||||
|     pub fn host(&self) -> &str { |     pub fn host(&self) -> &str { | ||||||
|         self.uri |         self.uri | ||||||
|             .host() |             .host() | ||||||
|             .expect("destination uri has host") |             .unwrap_or("") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Get the port, if specified. |     /// Get the port, if specified. | ||||||
| @@ -470,7 +470,6 @@ mod http { | |||||||
|  |  | ||||||
|     #[cfg(test)] |     #[cfg(test)] | ||||||
|     mod tests { |     mod tests { | ||||||
|         #![allow(deprecated)] |  | ||||||
|         use std::io; |         use std::io; | ||||||
|         use futures::Future; |         use futures::Future; | ||||||
|         use super::{Connect, Destination, HttpConnector}; |         use super::{Connect, Destination, HttpConnector}; | ||||||
|   | |||||||
| @@ -198,6 +198,7 @@ where C: Connect + Sync + 'static, | |||||||
|                         .map_err(::Error::new_connect) |                         .map_err(::Error::new_connect) | ||||||
|                         .and_then(move |(io, connected)| { |                         .and_then(move |(io, connected)| { | ||||||
|                             conn::Builder::new() |                             conn::Builder::new() | ||||||
|  |                                 .exec(executor.clone()) | ||||||
|                                 .h1_writev(h1_writev) |                                 .h1_writev(h1_writev) | ||||||
|                                 .h1_title_case_headers(h1_title_case_headers) |                                 .h1_title_case_headers(h1_title_case_headers) | ||||||
|                                 .http2_only(pool_key.1 == Ver::Http2) |                                 .http2_only(pool_key.1 == Ver::Http2) | ||||||
|   | |||||||
| @@ -37,7 +37,6 @@ pub(super) enum Reservation<T> { | |||||||
|     /// This connection could be used multiple times, the first one will be |     /// This connection could be used multiple times, the first one will be | ||||||
|     /// reinserted into the `idle` pool, and the second will be given to |     /// reinserted into the `idle` pool, and the second will be given to | ||||||
|     /// the `Checkout`. |     /// the `Checkout`. | ||||||
|     #[allow(unused)] |  | ||||||
|     Shared(T, T), |     Shared(T, T), | ||||||
|     /// This connection requires unique access. It will be returned after |     /// This connection requires unique access. It will be returned after | ||||||
|     /// use is complete. |     /// use is complete. | ||||||
| @@ -65,7 +64,7 @@ struct PoolInner<T> { | |||||||
|     // this list is checked for any parked Checkouts, and tries to notify |     // this list is checked for any parked Checkouts, and tries to notify | ||||||
|     // them that the Conn could be used instead of waiting for a brand new |     // them that the Conn could be used instead of waiting for a brand new | ||||||
|     // connection. |     // connection. | ||||||
|     parked: HashMap<Key, VecDeque<oneshot::Sender<T>>>, |     waiters: HashMap<Key, VecDeque<oneshot::Sender<T>>>, | ||||||
|     timeout: Option<Duration>, |     timeout: Option<Duration>, | ||||||
|     // A oneshot channel is used to allow the interval to be notified when |     // A oneshot channel is used to allow the interval to be notified when | ||||||
|     // the Pool completely drops. That way, the interval can cancel immediately. |     // the Pool completely drops. That way, the interval can cancel immediately. | ||||||
| @@ -80,7 +79,7 @@ impl<T> Pool<T> { | |||||||
|                 enabled: enabled, |                 enabled: enabled, | ||||||
|                 idle: HashMap::new(), |                 idle: HashMap::new(), | ||||||
|                 idle_interval_ref: None, |                 idle_interval_ref: None, | ||||||
|                 parked: HashMap::new(), |                 waiters: HashMap::new(), | ||||||
|                 timeout: timeout, |                 timeout: timeout, | ||||||
|             })), |             })), | ||||||
|         } |         } | ||||||
| @@ -94,7 +93,7 @@ impl<T: Poolable> Pool<T> { | |||||||
|         Checkout { |         Checkout { | ||||||
|             key, |             key, | ||||||
|             pool: self.clone(), |             pool: self.clone(), | ||||||
|             parked: None, |             waiter: None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -217,10 +216,10 @@ impl<T: Poolable> Pool<T> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn park(&mut self, key: Key, tx: oneshot::Sender<T>) { |     fn waiter(&mut self, key: Key, tx: oneshot::Sender<T>) { | ||||||
|         trace!("checkout waiting for idle connection: {:?}", key); |         trace!("checkout waiting for idle connection: {:?}", key); | ||||||
|         self.inner.lock().unwrap() |         self.inner.lock().unwrap() | ||||||
|             .parked.entry(key) |             .waiters.entry(key) | ||||||
|             .or_insert(VecDeque::new()) |             .or_insert(VecDeque::new()) | ||||||
|             .push_back(tx); |             .push_back(tx); | ||||||
|     } |     } | ||||||
| @@ -285,10 +284,10 @@ impl<T: Poolable> PoolInner<T> { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         trace!("put; add idle connection for {:?}", key); |         trace!("put; add idle connection for {:?}", key); | ||||||
|         let mut remove_parked = false; |         let mut remove_waiters = false; | ||||||
|         let mut value = Some(value); |         let mut value = Some(value); | ||||||
|         if let Some(parked) = self.parked.get_mut(&key) { |         if let Some(waiters) = self.waiters.get_mut(&key) { | ||||||
|             while let Some(tx) = parked.pop_front() { |             while let Some(tx) = waiters.pop_front() { | ||||||
|                 if !tx.is_canceled() { |                 if !tx.is_canceled() { | ||||||
|                     let reserved = value.take().expect("value already sent"); |                     let reserved = value.take().expect("value already sent"); | ||||||
|                     let reserved = match reserved.reserve() { |                     let reserved = match reserved.reserve() { | ||||||
| @@ -314,10 +313,10 @@ impl<T: Poolable> PoolInner<T> { | |||||||
|  |  | ||||||
|                 trace!("put; removing canceled waiter for {:?}", key); |                 trace!("put; removing canceled waiter for {:?}", key); | ||||||
|             } |             } | ||||||
|             remove_parked = parked.is_empty(); |             remove_waiters = waiters.is_empty(); | ||||||
|         } |         } | ||||||
|         if remove_parked { |         if remove_waiters { | ||||||
|             self.parked.remove(&key); |             self.waiters.remove(&key); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         match value { |         match value { | ||||||
| @@ -345,7 +344,7 @@ impl<T: Poolable> PoolInner<T> { | |||||||
|         // cancel any waiters. if there are any, it's because |         // cancel any waiters. if there are any, it's because | ||||||
|         // this Connecting task didn't complete successfully. |         // this Connecting task didn't complete successfully. | ||||||
|         // those waiters would never receive a connection. |         // those waiters would never receive a connection. | ||||||
|         self.parked.remove(key); |         self.waiters.remove(key); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -354,16 +353,16 @@ impl<T> PoolInner<T> { | |||||||
|     /// and possibly inserted into the pool that it is waiting for an idle |     /// and possibly inserted into the pool that it is waiting for an idle | ||||||
|     /// connection. If a user ever dropped that future, we need to clean out |     /// connection. If a user ever dropped that future, we need to clean out | ||||||
|     /// those parked senders. |     /// those parked senders. | ||||||
|     fn clean_parked(&mut self, key: &Key) { |     fn clean_waiters(&mut self, key: &Key) { | ||||||
|         let mut remove_parked = false; |         let mut remove_waiters = false; | ||||||
|         if let Some(parked) = self.parked.get_mut(key) { |         if let Some(waiters) = self.waiters.get_mut(key) { | ||||||
|             parked.retain(|tx| { |             waiters.retain(|tx| { | ||||||
|                 !tx.is_canceled() |                 !tx.is_canceled() | ||||||
|             }); |             }); | ||||||
|             remove_parked = parked.is_empty(); |             remove_waiters = waiters.is_empty(); | ||||||
|         } |         } | ||||||
|         if remove_parked { |         if remove_waiters { | ||||||
|             self.parked.remove(key); |             self.waiters.remove(key); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -511,13 +510,13 @@ struct Idle<T> { | |||||||
| pub(super) struct Checkout<T> { | pub(super) struct Checkout<T> { | ||||||
|     key: Key, |     key: Key, | ||||||
|     pool: Pool<T>, |     pool: Pool<T>, | ||||||
|     parked: Option<oneshot::Receiver<T>>, |     waiter: Option<oneshot::Receiver<T>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: Poolable> Checkout<T> { | impl<T: Poolable> Checkout<T> { | ||||||
|     fn poll_parked(&mut self) -> Poll<Option<Pooled<T>>, ::Error> { |     fn poll_waiter(&mut self) -> Poll<Option<Pooled<T>>, ::Error> { | ||||||
|         static CANCELED: &str = "pool checkout failed"; |         static CANCELED: &str = "pool checkout failed"; | ||||||
|         if let Some(ref mut rx) = self.parked { |         if let Some(mut rx) = self.waiter.take() { | ||||||
|             match rx.poll() { |             match rx.poll() { | ||||||
|                 Ok(Async::Ready(value)) => { |                 Ok(Async::Ready(value)) => { | ||||||
|                     if !value.is_closed() { |                     if !value.is_closed() { | ||||||
| @@ -526,7 +525,10 @@ impl<T: Poolable> Checkout<T> { | |||||||
|                         Err(::Error::new_canceled(Some(CANCELED))) |                         Err(::Error::new_canceled(Some(CANCELED))) | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|                 Ok(Async::NotReady) => Ok(Async::NotReady), |                 Ok(Async::NotReady) => { | ||||||
|  |                     self.waiter = Some(rx); | ||||||
|  |                     Ok(Async::NotReady) | ||||||
|  |                 }, | ||||||
|                 Err(_canceled) => Err(::Error::new_canceled(Some(CANCELED))), |                 Err(_canceled) => Err(::Error::new_canceled(Some(CANCELED))), | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
| @@ -534,12 +536,12 @@ impl<T: Poolable> Checkout<T> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn park(&mut self) { |     fn add_waiter(&mut self) { | ||||||
|         if self.parked.is_none() { |         if self.waiter.is_none() { | ||||||
|             let (tx, mut rx) = oneshot::channel(); |             let (tx, mut rx) = oneshot::channel(); | ||||||
|             let _ = rx.poll(); // park this task |             let _ = rx.poll(); // park this task | ||||||
|             self.pool.park(self.key.clone(), tx); |             self.pool.waiter(self.key.clone(), tx); | ||||||
|             self.parked = Some(rx); |             self.waiter = Some(rx); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -549,7 +551,7 @@ impl<T: Poolable> Future for Checkout<T> { | |||||||
|     type Error = ::Error; |     type Error = ::Error; | ||||||
|  |  | ||||||
|     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { |     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | ||||||
|         if let Some(pooled) = try_ready!(self.poll_parked()) { |         if let Some(pooled) = try_ready!(self.poll_waiter()) { | ||||||
|             return Ok(Async::Ready(pooled)); |             return Ok(Async::Ready(pooled)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -558,7 +560,7 @@ impl<T: Poolable> Future for Checkout<T> { | |||||||
|         if let Some(pooled) = entry { |         if let Some(pooled) = entry { | ||||||
|             Ok(Async::Ready(pooled)) |             Ok(Async::Ready(pooled)) | ||||||
|         } else { |         } else { | ||||||
|             self.park(); |             self.add_waiter(); | ||||||
|             Ok(Async::NotReady) |             Ok(Async::NotReady) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -566,9 +568,10 @@ impl<T: Poolable> Future for Checkout<T> { | |||||||
|  |  | ||||||
| impl<T> Drop for Checkout<T> { | impl<T> Drop for Checkout<T> { | ||||||
|     fn drop(&mut self) { |     fn drop(&mut self) { | ||||||
|         self.parked.take(); |         if self.waiter.take().is_some() { | ||||||
|         if let Ok(mut inner) = self.pool.inner.lock() { |             if let Ok(mut inner) = self.pool.inner.lock() { | ||||||
|             inner.clean_parked(&self.key); |                 inner.clean_waiters(&self.key); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -782,7 +785,7 @@ mod tests { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|     fn test_pool_checkout_drop_cleans_up_parked() { |     fn test_pool_checkout_drop_cleans_up_waiters() { | ||||||
|         future::lazy(|| { |         future::lazy(|| { | ||||||
|             let pool = Pool::<Uniq<i32>>::new(true, Some(Duration::from_secs(10))); |             let pool = Pool::<Uniq<i32>>::new(true, Some(Duration::from_secs(10))); | ||||||
|             let key = (Arc::new("localhost:12345".to_string()), Ver::Http1); |             let key = (Arc::new("localhost:12345".to_string()), Ver::Http1); | ||||||
| @@ -792,16 +795,16 @@ mod tests { | |||||||
|  |  | ||||||
|             // first poll needed to get into Pool's parked |             // first poll needed to get into Pool's parked | ||||||
|             checkout1.poll().unwrap(); |             checkout1.poll().unwrap(); | ||||||
|             assert_eq!(pool.inner.lock().unwrap().parked.get(&key).unwrap().len(), 1); |             assert_eq!(pool.inner.lock().unwrap().waiters.get(&key).unwrap().len(), 1); | ||||||
|             checkout2.poll().unwrap(); |             checkout2.poll().unwrap(); | ||||||
|             assert_eq!(pool.inner.lock().unwrap().parked.get(&key).unwrap().len(), 2); |             assert_eq!(pool.inner.lock().unwrap().waiters.get(&key).unwrap().len(), 2); | ||||||
|  |  | ||||||
|             // on drop, clean up Pool |             // on drop, clean up Pool | ||||||
|             drop(checkout1); |             drop(checkout1); | ||||||
|             assert_eq!(pool.inner.lock().unwrap().parked.get(&key).unwrap().len(), 1); |             assert_eq!(pool.inner.lock().unwrap().waiters.get(&key).unwrap().len(), 1); | ||||||
|  |  | ||||||
|             drop(checkout2); |             drop(checkout2); | ||||||
|             assert!(pool.inner.lock().unwrap().parked.get(&key).is_none()); |             assert!(pool.inner.lock().unwrap().waiters.get(&key).is_none()); | ||||||
|  |  | ||||||
|             ::futures::future::ok::<(), ()>(()) |             ::futures::future::ok::<(), ()>(()) | ||||||
|         }).wait().unwrap(); |         }).wait().unwrap(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user