Revert "refactor(lib): convert to futures 0.2.0-beta (#1470)"
This reverts commit a12f7beed9.
Much sadness 😢.
This commit is contained in:
@@ -4,13 +4,15 @@ use std::ops::{Deref, DerefMut};
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use futures::{Future, Async, Never, Poll, Stream};
|
||||
use futures::channel::oneshot;
|
||||
use futures::task;
|
||||
use futures::{Future, Async, Poll, Stream};
|
||||
use futures::sync::oneshot;
|
||||
use futures_timer::Interval;
|
||||
|
||||
pub(super) struct Pool<T> {
|
||||
inner: Arc<Mutex<PoolInner<T>>>
|
||||
use common::Never;
|
||||
use super::Exec;
|
||||
|
||||
pub struct Pool<T> {
|
||||
inner: Arc<Mutex<PoolInner<T>>>,
|
||||
}
|
||||
|
||||
// Before using a pooled connection, make sure the sender is not dead.
|
||||
@@ -44,7 +46,7 @@ struct PoolInner<T> {
|
||||
}
|
||||
|
||||
impl<T> Pool<T> {
|
||||
pub(super) fn new(enabled: bool, timeout: Option<Duration>) -> Pool<T> {
|
||||
pub fn new(enabled: bool, timeout: Option<Duration>) -> Pool<T> {
|
||||
Pool {
|
||||
inner: Arc::new(Mutex::new(PoolInner {
|
||||
enabled: enabled,
|
||||
@@ -52,7 +54,7 @@ impl<T> Pool<T> {
|
||||
idle_interval_ref: None,
|
||||
parked: HashMap::new(),
|
||||
timeout: timeout,
|
||||
}))
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +65,6 @@ impl<T: Closed> Pool<T> {
|
||||
key: Arc::new(key.to_owned()),
|
||||
pool: self.clone(),
|
||||
parked: None,
|
||||
spawned_expired_interval: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,16 +219,16 @@ impl<T: Closed> PoolInner<T> {
|
||||
|
||||
|
||||
impl<T: Closed + Send + 'static> Pool<T> {
|
||||
fn spawn_expired_interval(&mut self, cx: &mut task::Context) -> Result<(), ::Error> {
|
||||
pub(super) fn spawn_expired_interval(&self, exec: &Exec) {
|
||||
let (dur, rx) = {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
|
||||
if !inner.enabled {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
if inner.idle_interval_ref.is_some() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(dur) = inner.timeout {
|
||||
@@ -235,23 +236,23 @@ impl<T: Closed + Send + 'static> Pool<T> {
|
||||
inner.idle_interval_ref = Some(tx);
|
||||
(dur, rx)
|
||||
} else {
|
||||
return Ok(());
|
||||
return
|
||||
}
|
||||
};
|
||||
|
||||
let interval = Interval::new(dur);
|
||||
super::execute(IdleInterval {
|
||||
exec.execute(IdleInterval {
|
||||
interval: interval,
|
||||
pool: Arc::downgrade(&self.inner),
|
||||
pool_drop_notifier: rx,
|
||||
}, cx)
|
||||
}).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Pool<T> {
|
||||
fn clone(&self) -> Pool<T> {
|
||||
Pool {
|
||||
inner: self.inner.clone()
|
||||
inner: self.inner.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,23 +322,22 @@ pub struct Checkout<T> {
|
||||
key: Arc<String>,
|
||||
pool: Pool<T>,
|
||||
parked: Option<oneshot::Receiver<T>>,
|
||||
spawned_expired_interval: bool
|
||||
}
|
||||
|
||||
struct NotParked;
|
||||
|
||||
impl<T: Closed> Checkout<T> {
|
||||
fn poll_parked(&mut self, cx: &mut task::Context) -> Poll<Pooled<T>, NotParked> {
|
||||
fn poll_parked(&mut self) -> Poll<Pooled<T>, NotParked> {
|
||||
let mut drop_parked = false;
|
||||
if let Some(ref mut rx) = self.parked {
|
||||
match rx.poll(cx) {
|
||||
match rx.poll() {
|
||||
Ok(Async::Ready(value)) => {
|
||||
if !value.is_closed() {
|
||||
return Ok(Async::Ready(self.pool.reuse(&self.key, value)));
|
||||
}
|
||||
drop_parked = true;
|
||||
},
|
||||
Ok(Async::Pending) => return Ok(Async::Pending),
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Err(_canceled) => drop_parked = true,
|
||||
}
|
||||
}
|
||||
@@ -347,27 +347,22 @@ impl<T: Closed> Checkout<T> {
|
||||
Err(NotParked)
|
||||
}
|
||||
|
||||
fn park(&mut self, cx: &mut task::Context) {
|
||||
fn park(&mut self) {
|
||||
if self.parked.is_none() {
|
||||
let (tx, mut rx) = oneshot::channel();
|
||||
let _ = rx.poll(cx); // park this task
|
||||
let _ = rx.poll(); // park this task
|
||||
self.pool.park(self.key.clone(), tx);
|
||||
self.parked = Some(rx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Closed + Send + 'static> Future for Checkout<T> {
|
||||
impl<T: Closed> Future for Checkout<T> {
|
||||
type Item = Pooled<T>;
|
||||
type Error = ::Error;
|
||||
|
||||
fn poll(&mut self, cx: &mut task::Context) -> Poll<Self::Item, Self::Error> {
|
||||
if !self.spawned_expired_interval {
|
||||
self.pool.spawn_expired_interval(cx)?;
|
||||
self.spawned_expired_interval = true;
|
||||
}
|
||||
|
||||
match self.poll_parked(cx) {
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self.poll_parked() {
|
||||
Ok(async) => return Ok(async),
|
||||
Err(_not_parked) => (),
|
||||
}
|
||||
@@ -377,8 +372,8 @@ impl<T: Closed + Send + 'static> Future for Checkout<T> {
|
||||
if let Some(pooled) = entry {
|
||||
Ok(Async::Ready(pooled))
|
||||
} else {
|
||||
self.park(cx);
|
||||
Ok(Async::Pending)
|
||||
self.park();
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,20 +413,20 @@ struct IdleInterval<T> {
|
||||
|
||||
impl<T: Closed + 'static> Future for IdleInterval<T> {
|
||||
type Item = ();
|
||||
type Error = Never;
|
||||
type Error = ();
|
||||
|
||||
fn poll(&mut self, cx: &mut task::Context) -> Poll<Self::Item, Self::Error> {
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
loop {
|
||||
match self.pool_drop_notifier.poll(cx) {
|
||||
match self.pool_drop_notifier.poll() {
|
||||
Ok(Async::Ready(n)) => match n {},
|
||||
Ok(Async::Pending) => (),
|
||||
Ok(Async::NotReady) => (),
|
||||
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().map_err(|_| unreachable!("interval cannot error")));
|
||||
|
||||
if let Some(inner) = self.pool.upgrade() {
|
||||
if let Ok(mut inner) = inner.lock() {
|
||||
@@ -448,10 +443,9 @@ impl<T: Closed + 'static> Future for IdleInterval<T> {
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use futures::{Async, Future, FutureExt};
|
||||
use futures::{Async, Future};
|
||||
use futures::future;
|
||||
use futures::executor::block_on;
|
||||
use super::{Closed, Pool};
|
||||
use super::{Closed, Pool, Exec};
|
||||
|
||||
impl Closed for i32 {
|
||||
fn is_closed(&self) -> bool {
|
||||
@@ -461,37 +455,34 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_pool_checkout_smoke() {
|
||||
block_on(future::lazy(|cx| {
|
||||
let pool = Pool::new(true, Some(Duration::from_secs(5)));
|
||||
let key = Arc::new("foo".to_string());
|
||||
let pooled = pool.pooled(key.clone(), 41);
|
||||
let pool = Pool::new(true, Some(Duration::from_secs(5)));
|
||||
let key = Arc::new("foo".to_string());
|
||||
let pooled = pool.pooled(key.clone(), 41);
|
||||
|
||||
drop(pooled);
|
||||
drop(pooled);
|
||||
|
||||
match pool.checkout(&key).poll(cx).unwrap() {
|
||||
Async::Ready(pooled) => assert_eq!(*pooled, 41),
|
||||
_ => panic!("not ready"),
|
||||
}
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap();
|
||||
match pool.checkout(&key).poll().unwrap() {
|
||||
Async::Ready(pooled) => assert_eq!(*pooled, 41),
|
||||
_ => panic!("not ready"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_checkout_returns_none_if_expired() {
|
||||
block_on(future::lazy(|cx| {
|
||||
future::lazy(|| {
|
||||
let pool = Pool::new(true, Some(Duration::from_millis(100)));
|
||||
let key = Arc::new("foo".to_string());
|
||||
let pooled = pool.pooled(key.clone(), 41);
|
||||
drop(pooled);
|
||||
::std::thread::sleep(pool.inner.lock().unwrap().timeout.unwrap());
|
||||
assert!(pool.checkout(&key).poll(cx).unwrap().is_pending());
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap();
|
||||
assert!(pool.checkout(&key).poll().unwrap().is_not_ready());
|
||||
::futures::future::ok::<(), ()>(())
|
||||
}).wait().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_checkout_removes_expired() {
|
||||
block_on(future::lazy(|cx| {
|
||||
future::lazy(|| {
|
||||
let pool = Pool::new(true, Some(Duration::from_millis(100)));
|
||||
let key = Arc::new("foo".to_string());
|
||||
|
||||
@@ -503,20 +494,20 @@ mod tests {
|
||||
::std::thread::sleep(pool.inner.lock().unwrap().timeout.unwrap());
|
||||
|
||||
// checkout.poll() should clean out the expired
|
||||
pool.checkout(&key).poll(cx).unwrap();
|
||||
pool.checkout(&key).poll().unwrap();
|
||||
assert!(pool.inner.lock().unwrap().idle.get(&key).is_none());
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap();
|
||||
Ok::<(), ()>(())
|
||||
}).wait().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_timer_removes_expired() {
|
||||
let mut pool = Pool::new(true, Some(Duration::from_millis(100)));
|
||||
let runtime = ::tokio::runtime::Runtime::new().unwrap();
|
||||
let pool = Pool::new(true, Some(Duration::from_millis(100)));
|
||||
|
||||
block_on(future::lazy(|cx| {
|
||||
pool.spawn_expired_interval(cx)
|
||||
})).unwrap();
|
||||
let executor = runtime.executor();
|
||||
pool.spawn_expired_interval(&Exec::new(executor));
|
||||
let key = Arc::new("foo".to_string());
|
||||
|
||||
pool.pooled(key.clone(), 41);
|
||||
@@ -525,9 +516,9 @@ mod tests {
|
||||
|
||||
assert_eq!(pool.inner.lock().unwrap().idle.get(&key).map(|entries| entries.len()), Some(3));
|
||||
|
||||
block_on(::futures_timer::Delay::new(
|
||||
::futures_timer::Delay::new(
|
||||
Duration::from_millis(400) // allow for too-good resolution
|
||||
)).unwrap();
|
||||
).wait().unwrap();
|
||||
|
||||
assert!(pool.inner.lock().unwrap().idle.get(&key).is_none());
|
||||
}
|
||||
@@ -538,7 +529,7 @@ mod tests {
|
||||
let key = Arc::new("foo".to_string());
|
||||
let pooled = pool.pooled(key.clone(), 41);
|
||||
|
||||
let checkout = pool.checkout(&key).join(future::lazy(move |_| {
|
||||
let checkout = pool.checkout(&key).join(future::lazy(move || {
|
||||
// the checkout future will park first,
|
||||
// and then this lazy future will be polled, which will insert
|
||||
// the pooled back into the pool
|
||||
@@ -547,12 +538,12 @@ mod tests {
|
||||
drop(pooled);
|
||||
Ok(())
|
||||
})).map(|(entry, _)| entry);
|
||||
assert_eq!(*block_on(checkout).unwrap(), 41);
|
||||
assert_eq!(*checkout.wait().unwrap(), 41);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pool_checkout_drop_cleans_up_parked() {
|
||||
block_on(future::lazy(|cx| {
|
||||
future::lazy(|| {
|
||||
let pool = Pool::<i32>::new(true, Some(Duration::from_secs(10)));
|
||||
let key = Arc::new("localhost:12345".to_string());
|
||||
|
||||
@@ -560,9 +551,9 @@ mod tests {
|
||||
let mut checkout2 = pool.checkout(&key);
|
||||
|
||||
// first poll needed to get into Pool's parked
|
||||
checkout1.poll(cx).unwrap();
|
||||
checkout1.poll().unwrap();
|
||||
assert_eq!(pool.inner.lock().unwrap().parked.get(&key).unwrap().len(), 1);
|
||||
checkout2.poll(cx).unwrap();
|
||||
checkout2.poll().unwrap();
|
||||
assert_eq!(pool.inner.lock().unwrap().parked.get(&key).unwrap().len(), 2);
|
||||
|
||||
// on drop, clean up Pool
|
||||
@@ -572,7 +563,7 @@ mod tests {
|
||||
drop(checkout2);
|
||||
assert!(pool.inner.lock().unwrap().parked.get(&key).is_none());
|
||||
|
||||
Ok::<_, ()>(())
|
||||
})).unwrap();
|
||||
::futures::future::ok::<(), ()>(())
|
||||
}).wait().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user