refactor(client): clean up pool Checkout::poll function
This commit is contained in:
@@ -42,7 +42,7 @@ struct PoolInner<T> {
|
||||
timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
impl<T: Clone> Pool<T> {
|
||||
impl<T: Clone + Ready> Pool<T> {
|
||||
pub fn new(enabled: bool, timeout: Option<Duration>) -> Pool<T> {
|
||||
Pool {
|
||||
inner: Rc::new(RefCell::new(PoolInner {
|
||||
@@ -65,7 +65,6 @@ impl<T: Clone> Pool<T> {
|
||||
fn put(&mut self, key: Rc<String>, entry: Entry<T>) {
|
||||
trace!("Pool::put {:?}", key);
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
//let inner = &mut *inner;
|
||||
let mut remove_parked = false;
|
||||
let mut entry = Some(entry);
|
||||
if let Some(parked) = inner.parked.get_mut(&key) {
|
||||
@@ -103,6 +102,42 @@ impl<T: Clone> Pool<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn take(&self, key: &Rc<String>) -> Option<Pooled<T>> {
|
||||
let entry = {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let expiration = Expiration::new(inner.timeout);
|
||||
let mut should_remove = false;
|
||||
let entry = inner.idle.get_mut(key).and_then(|list| {
|
||||
trace!("take; url = {:?}, expiration = {:?}", key, expiration.0);
|
||||
while let Some(mut entry) = list.pop() {
|
||||
match entry.status.get() {
|
||||
TimedKA::Idle(idle_at) if !expiration.expires(idle_at) => {
|
||||
if let Ok(Async::Ready(())) = entry.value.poll_ready() {
|
||||
should_remove = list.is_empty();
|
||||
return Some(entry);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
trace!("removing unacceptable pooled {:?}", key);
|
||||
// every other case the Entry should just be dropped
|
||||
// 1. Idle but expired
|
||||
// 2. Busy (something else somehow took it?)
|
||||
// 3. Disabled don't reuse of course
|
||||
}
|
||||
should_remove = true;
|
||||
None
|
||||
});
|
||||
|
||||
if should_remove {
|
||||
inner.idle.remove(key);
|
||||
}
|
||||
entry
|
||||
};
|
||||
|
||||
entry.map(|e| self.reuse(key, e))
|
||||
}
|
||||
|
||||
|
||||
pub fn pooled(&self, key: Rc<String>, value: T) -> Pooled<T> {
|
||||
Pooled {
|
||||
@@ -120,13 +155,13 @@ impl<T: Clone> Pool<T> {
|
||||
self.inner.borrow().enabled
|
||||
}
|
||||
|
||||
fn reuse(&self, key: Rc<String>, mut entry: Entry<T>) -> Pooled<T> {
|
||||
trace!("reuse {:?}", key);
|
||||
fn reuse(&self, key: &Rc<String>, mut entry: Entry<T>) -> Pooled<T> {
|
||||
debug!("reuse idle connection for {:?}", key);
|
||||
entry.is_reused = true;
|
||||
entry.status.set(TimedKA::Busy);
|
||||
Pooled {
|
||||
entry: entry,
|
||||
key: key,
|
||||
key: key.clone(),
|
||||
pool: Rc::downgrade(&self.inner),
|
||||
}
|
||||
}
|
||||
@@ -141,8 +176,11 @@ impl<T: Clone> Pool<T> {
|
||||
}
|
||||
|
||||
impl<T> Pool<T> {
|
||||
/// Any `FutureResponse`s that were created will have made a `Checkout`,
|
||||
/// 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
|
||||
/// those parked senders.
|
||||
fn clean_parked(&mut self, key: &Rc<String>) {
|
||||
trace!("clean_parked {:?}", key);
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
|
||||
let mut remove_parked = false;
|
||||
@@ -186,7 +224,7 @@ impl<T> DerefMut for Pooled<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> KeepAlive for Pooled<T> {
|
||||
impl<T: Clone + Ready> KeepAlive for Pooled<T> {
|
||||
fn busy(&mut self) {
|
||||
self.entry.status.set(TimedKA::Busy);
|
||||
}
|
||||
@@ -237,7 +275,7 @@ impl<T> fmt::Debug for Pooled<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> BitAndAssign<bool> for Pooled<T> {
|
||||
impl<T: Clone + Ready> BitAndAssign<bool> for Pooled<T> {
|
||||
fn bitand_assign(&mut self, enabled: bool) {
|
||||
if !enabled {
|
||||
self.disable();
|
||||
@@ -265,67 +303,56 @@ pub struct Checkout<T> {
|
||||
parked: Option<relay::Receiver<Entry<T>>>,
|
||||
}
|
||||
|
||||
impl<T: Ready + Clone> Future for Checkout<T> {
|
||||
type Item = Pooled<T>;
|
||||
type Error = io::Error;
|
||||
struct NotParked;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
trace!("Checkout::poll");
|
||||
impl<T: Clone + Ready> Checkout<T> {
|
||||
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() {
|
||||
Ok(Async::Ready(entry)) => {
|
||||
trace!("Checkout::poll found client in relay for {:?}", self.key);
|
||||
return Ok(Async::Ready(self.pool.reuse(self.key.clone(), entry)));
|
||||
Ok(Async::Ready(mut entry)) => {
|
||||
if let Ok(Async::Ready(())) = entry.value.poll_ready() {
|
||||
return Ok(Async::Ready(self.pool.reuse(&self.key, entry)));
|
||||
}
|
||||
drop_parked = true;
|
||||
},
|
||||
Ok(Async::NotReady) => (),
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Err(_canceled) => drop_parked = true,
|
||||
}
|
||||
}
|
||||
if drop_parked {
|
||||
self.parked.take();
|
||||
}
|
||||
let expiration = Expiration::new(self.pool.inner.borrow().timeout);
|
||||
let key = &self.key;
|
||||
trace!("Checkout::poll url = {:?}, expiration = {:?}", key, expiration.0);
|
||||
let mut should_remove = false;
|
||||
let entry = self.pool.inner.borrow_mut().idle.get_mut(key).and_then(|list| {
|
||||
trace!("Checkout::poll key found {:?}", key);
|
||||
while let Some(mut entry) = list.pop() {
|
||||
match entry.status.get() {
|
||||
TimedKA::Idle(idle_at) if !expiration.expires(idle_at) => {
|
||||
if let Ok(Async::Ready(())) = entry.value.poll_ready() {
|
||||
debug!("found idle connection for {:?}", key);
|
||||
should_remove = list.is_empty();
|
||||
return Some(entry);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
trace!("Checkout::poll removing unacceptable pooled {:?}", key);
|
||||
// every other case the Entry should just be dropped
|
||||
// 1. Idle but expired
|
||||
// 2. Busy (something else somehow took it?)
|
||||
// 3. Disabled don't reuse of course
|
||||
}
|
||||
should_remove = true;
|
||||
None
|
||||
});
|
||||
Err(NotParked)
|
||||
}
|
||||
|
||||
if should_remove {
|
||||
self.pool.inner.borrow_mut().idle.remove(key);
|
||||
fn park(&mut self) {
|
||||
if self.parked.is_none() {
|
||||
let (tx, mut rx) = relay::channel();
|
||||
let _ = rx.poll(); // park this task
|
||||
self.pool.park(self.key.clone(), tx);
|
||||
self.parked = Some(rx);
|
||||
}
|
||||
match entry {
|
||||
Some(entry) => Ok(Async::Ready(self.pool.reuse(self.key.clone(), entry))),
|
||||
None => {
|
||||
if self.parked.is_none() {
|
||||
let (tx, mut rx) = relay::channel();
|
||||
let _ = rx.poll(); // park this task
|
||||
self.pool.park(self.key.clone(), tx);
|
||||
self.parked = Some(rx);
|
||||
}
|
||||
Ok(Async::NotReady)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + Ready> Future for Checkout<T> {
|
||||
type Item = Pooled<T>;
|
||||
type Error = io::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
match self.poll_parked() {
|
||||
Ok(async) => return Ok(async),
|
||||
Err(_not_parked) => (),
|
||||
}
|
||||
|
||||
let entry = self.pool.take(&self.key);
|
||||
|
||||
if let Some(pooled) = entry {
|
||||
Ok(Async::Ready(pooled))
|
||||
} else {
|
||||
self.park();
|
||||
Ok(Async::NotReady)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user