//! A cache of services //! //! The cache is a single list of cached services, bundled with a `MakeService`. //! Calling the cache returns either an existing service, or makes a new one. //! The returned `impl Service` can be used to send requests, and when dropped, //! it will try to be returned back to the cache.
// For now, nothing else in this module is nameable. We can always make things // more public, but we can't change type shapes (generics) once things are // public. mod internal { use std::fmt; use std::future::Future; use std::pin::Pin; use std::sync::{Arc, Mutex, Weak}; use std::task::{self, ready, Poll};
use futures_util::future; use tokio::sync::oneshot; use tower_service::Service;
usesuper::events;
/// Start a builder to construct a `Cache` pool. pubfn builder() -> Builder<events::Ignore> {
Builder {
events: events::Ignore,
}
}
/// A cache pool of services from the inner make service. /// /// Created with [`builder()`]. /// /// # Unnameable /// /// This type is normally unnameable, forbidding naming of the type within /// code. The type is exposed in the documentation to show which methods /// can be publicly called. #[derive(Debug)] pubstruct Cache<M, Dst, Ev> where
M: Service<Dst>,
{
connector: M,
shared: Arc<Mutex<Shared<M::Response>>>,
events: Ev,
}
/// A builder to configure a `Cache`. /// /// # Unnameable /// /// This type is normally unnameable, forbidding naming of the type within /// code. The type is exposed in the documentation to show which methods /// can be publicly called. #[derive(Debug)] pubstruct Builder<Ev> {
events: Ev,
}
/// A cached service returned from a [`Cache`]. /// /// Implements `Service` by delegating to the inner service. Once dropped, /// tries to reinsert into the `Cache`. /// /// # Unnameable /// /// This type is normally unnameable, forbidding naming of the type within /// code. The type is exposed in the documentation to show which methods /// can be publicly called. pubstruct Cached<S> {
is_closed: bool,
inner: Option<S>,
shared: Weak<Mutex<Shared<S>>>, // todo: on_idle
}
pubenum CacheFuture<M, Dst, Ev> where
M: Service<Dst>,
{
Racing {
shared: Arc<Mutex<Shared<M::Response>>>,
select: future::Select<oneshot::Receiver<M::Response>, M::Future>,
events: Ev,
},
Connecting { // TODO: could be Weak even here...
shared: Arc<Mutex<Shared<M::Response>>>,
future: M::Future,
},
Cached {
svc: Option<Cached<M::Response>>,
},
}
impl<Ev> Builder<Ev> { /// Provide a `Future` executor to be used by the `Cache`. /// /// The executor is used handle some optional background tasks that /// can improve the behavior of the cache, such as reducing connection /// thrashing when a race is won. If not configured with an executor, /// the default behavior is to ignore any of these optional background /// tasks. /// /// The executor should implmenent [`hyper::rt::Executor`]. /// /// # Example /// /// ```rust /// # #[cfg(feature = "tokio")] /// # fn run() { /// let builder = hyper_util::client::pool::cache::builder() /// .executor(hyper_util::rt::TokioExecutor::new()); /// # } /// ``` pubfn executor<E>(self, exec: E) -> Builder<events::WithExecutor<E>> {
Builder {
events: events::WithExecutor(exec),
}
}
/// Build a `Cache` pool around the `connector`. pubfn build<M, Dst>(self, connector: M) -> Cache<M, Dst, Ev> where
M: Service<Dst>,
{
Cache {
connector,
events: self.events,
shared: Arc::new(Mutex::new(Shared {
services: Vec::new(),
waiters: Vec::new(),
})),
}
}
}
// impl Cache
impl<M, Dst, Ev> Cache<M, Dst, Ev> where
M: Service<Dst>,
{ /// Retain all cached services indicated by the predicate. pubfn retain<F>(&mutself, predicate: F) where
F: FnMut(&mut M::Response) -> bool,
{ self.shared.lock().unwrap().services.retain_mut(predicate);
}
/// Check whether this cache has no cached services. pubfn is_empty(&self) -> bool { self.shared.lock().unwrap().services.is_empty()
}
}
impl<M, Dst, Ev> Service<Dst> for Cache<M, Dst, Ev> where
M: Service<Dst>,
M::Future: Unpin,
M::Response: Unpin,
Ev: events::Events<BackgroundConnect<M::Future, M::Response>> + Clone + Unpin,
{ type Response = Cached<M::Response>; type Error = M::Error; type Future = CacheFuture<M, Dst, Ev>;
let (tx, rx) = oneshot::channel();
locked.waiters.push(tx);
rx
};
// 2. Otherwise, we start a new connect, and also listen for // any newly idle.
CacheFuture::Racing {
shared: self.shared.clone(),
select: future::select(waiter, self.connector.call(target)),
events: self.events.clone(),
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.