1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-11 01:39:33 +00:00
actix-web/actix-http/src/client/pool.rs

643 lines
18 KiB
Rust
Raw Normal View History

2018-11-12 07:12:54 +00:00
use std::cell::RefCell;
2019-01-27 19:40:26 +00:00
use std::collections::VecDeque;
2018-11-12 07:12:54 +00:00
use std::io;
use std::rc::Rc;
use std::time::{Duration, Instant};
2018-12-11 02:08:33 +00:00
use actix_codec::{AsyncRead, AsyncWrite};
use actix_service::Service;
2019-01-29 04:41:09 +00:00
use bytes::Bytes;
2019-03-14 18:52:52 +00:00
use futures::future::{err, ok, Either, FutureResult};
2018-11-12 07:12:54 +00:00
use futures::task::AtomicTask;
2019-01-27 19:40:26 +00:00
use futures::unsync::oneshot;
2018-11-12 07:12:54 +00:00
use futures::{Async, Future, Poll};
2019-01-29 04:41:09 +00:00
use h2::client::{handshake, Handshake};
2019-01-27 19:40:26 +00:00
use hashbrown::HashMap;
use http::uri::Authority;
2018-11-12 07:12:54 +00:00
use indexmap::IndexSet;
use slab::Slab;
use tokio_timer::{sleep, Delay};
2019-01-29 04:41:09 +00:00
use super::connection::{ConnectionType, IoConnection};
2019-03-13 21:41:40 +00:00
use super::error::ConnectError;
use super::Connect;
2018-11-12 07:12:54 +00:00
2019-01-29 04:41:09 +00:00
#[derive(Clone, Copy, PartialEq)]
2019-04-08 18:09:57 +00:00
/// Protocol version
2019-01-29 04:41:09 +00:00
pub enum Protocol {
Http1,
Http2,
}
2018-11-12 07:12:54 +00:00
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
pub(crate) struct Key {
authority: Authority,
}
impl From<Authority> for Key {
fn from(authority: Authority) -> Key {
Key { authority }
}
}
/// Connections pool
pub(crate) struct ConnectionPool<T, Io: AsyncRead + AsyncWrite + 'static>(
T,
Rc<RefCell<Inner<Io>>>,
);
impl<T, Io> ConnectionPool<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Clone
+ 'static,
2018-11-12 07:12:54 +00:00
{
pub(crate) fn new(
connector: T,
conn_lifetime: Duration,
conn_keep_alive: Duration,
disconnect_timeout: Option<Duration>,
limit: usize,
) -> Self {
ConnectionPool(
connector,
Rc::new(RefCell::new(Inner {
conn_lifetime,
conn_keep_alive,
disconnect_timeout,
limit,
acquired: 0,
waiters: Slab::new(),
waiters_queue: IndexSet::new(),
available: HashMap::new(),
task: None,
2018-11-12 07:12:54 +00:00
})),
)
}
}
impl<T, Io> Clone for ConnectionPool<T, Io>
where
T: Clone,
Io: AsyncRead + AsyncWrite + 'static,
{
fn clone(&self) -> Self {
ConnectionPool(self.0.clone(), self.1.clone())
}
}
impl<T, Io> Service for ConnectionPool<T, Io>
2018-11-12 07:12:54 +00:00
where
Io: AsyncRead + AsyncWrite + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Clone
+ 'static,
2018-11-12 07:12:54 +00:00
{
type Request = Connect;
2018-11-15 19:10:23 +00:00
type Response = IoConnection<Io>;
2019-03-13 21:41:40 +00:00
type Error = ConnectError;
2018-11-12 07:12:54 +00:00
type Future = Either<
2019-03-13 21:41:40 +00:00
FutureResult<Self::Response, Self::Error>,
2018-11-12 07:12:54 +00:00
Either<WaitForConnection<Io>, OpenConnection<T::Future, Io>>,
>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.0.poll_ready()
}
fn call(&mut self, req: Connect) -> Self::Future {
let key = if let Some(authority) = req.uri.authority_part() {
2019-03-14 18:52:52 +00:00
authority.clone().into()
} else {
return Either::A(err(ConnectError::Unresolverd));
};
2018-11-12 07:12:54 +00:00
// acquire connection
match self.1.as_ref().borrow_mut().acquire(&key) {
Acquire::Acquired(io, created) => {
// use existing connection
return Either::A(ok(IoConnection::new(
2018-11-12 07:12:54 +00:00
io,
created,
2019-01-29 04:41:09 +00:00
Some(Acquired(key, Some(self.1.clone()))),
)));
2018-11-12 07:12:54 +00:00
}
Acquire::Available => {
// open new connection
return Either::B(Either::B(OpenConnection::new(
2018-11-12 07:12:54 +00:00
key,
self.1.clone(),
self.0.call(req),
)));
2018-11-12 07:12:54 +00:00
}
_ => (),
2018-11-12 07:12:54 +00:00
}
// connection is not available, wait
let (rx, token, support) = self.1.as_ref().borrow_mut().wait_for(req);
// start support future
if !support {
self.1.as_ref().borrow_mut().task = Some(AtomicTask::new());
tokio_current_thread::spawn(ConnectorPoolSupport {
connector: self.0.clone(),
inner: self.1.clone(),
})
}
Either::B(Either::A(WaitForConnection {
rx,
key,
token,
inner: Some(self.1.clone()),
}))
2018-11-12 07:12:54 +00:00
}
}
#[doc(hidden)]
pub struct WaitForConnection<Io>
where
Io: AsyncRead + AsyncWrite + 'static,
{
key: Key,
token: usize,
2019-03-13 21:41:40 +00:00
rx: oneshot::Receiver<Result<IoConnection<Io>, ConnectError>>,
2018-11-12 07:12:54 +00:00
inner: Option<Rc<RefCell<Inner<Io>>>>,
}
impl<Io> Drop for WaitForConnection<Io>
where
Io: AsyncRead + AsyncWrite + 'static,
{
fn drop(&mut self) {
if let Some(i) = self.inner.take() {
let mut inner = i.as_ref().borrow_mut();
inner.release_waiter(&self.key, self.token);
inner.check_availibility();
}
}
}
impl<Io> Future for WaitForConnection<Io>
where
Io: AsyncRead + AsyncWrite,
{
2018-11-15 19:10:23 +00:00
type Item = IoConnection<Io>;
2019-03-13 21:41:40 +00:00
type Error = ConnectError;
2018-11-12 07:12:54 +00:00
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.rx.poll() {
Ok(Async::Ready(item)) => match item {
Err(err) => Err(err),
Ok(conn) => {
let _ = self.inner.take();
Ok(Async::Ready(conn))
}
},
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(_) => {
let _ = self.inner.take();
2019-03-13 21:41:40 +00:00
Err(ConnectError::Disconnected)
2018-11-12 07:12:54 +00:00
}
}
}
}
#[doc(hidden)]
pub struct OpenConnection<F, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
{
fut: F,
key: Key,
2019-01-29 04:41:09 +00:00
h2: Option<Handshake<Io, Bytes>>,
2018-11-12 07:12:54 +00:00
inner: Option<Rc<RefCell<Inner<Io>>>>,
}
impl<F, Io> OpenConnection<F, Io>
where
2019-03-13 21:41:40 +00:00
F: Future<Item = (Io, Protocol), Error = ConnectError>,
2018-11-12 07:12:54 +00:00
Io: AsyncRead + AsyncWrite + 'static,
{
fn new(key: Key, inner: Rc<RefCell<Inner<Io>>>, fut: F) -> Self {
OpenConnection {
key,
fut,
inner: Some(inner),
2019-01-29 04:41:09 +00:00
h2: None,
2018-11-12 07:12:54 +00:00
}
}
}
impl<F, Io> Drop for OpenConnection<F, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
{
fn drop(&mut self) {
if let Some(inner) = self.inner.take() {
let mut inner = inner.as_ref().borrow_mut();
inner.release();
inner.check_availibility();
}
}
}
impl<F, Io> Future for OpenConnection<F, Io>
where
2019-03-13 21:41:40 +00:00
F: Future<Item = (Io, Protocol), Error = ConnectError>,
2018-11-12 07:12:54 +00:00
Io: AsyncRead + AsyncWrite,
{
2018-11-15 19:10:23 +00:00
type Item = IoConnection<Io>;
2019-03-13 21:41:40 +00:00
type Error = ConnectError;
2018-11-12 07:12:54 +00:00
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
2019-01-29 04:41:09 +00:00
if let Some(ref mut h2) = self.h2 {
return match h2.poll() {
Ok(Async::Ready((snd, connection))) => {
tokio_current_thread::spawn(connection.map_err(|_| ()));
Ok(Async::Ready(IoConnection::new(
ConnectionType::H2(snd),
Instant::now(),
Some(Acquired(self.key.clone(), self.inner.take())),
2019-01-29 04:41:09 +00:00
)))
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(e) => Err(e.into()),
};
2018-11-12 07:12:54 +00:00
}
match self.fut.poll() {
2019-01-29 18:14:00 +00:00
Err(err) => Err(err),
2019-03-13 21:41:40 +00:00
Ok(Async::Ready((io, proto))) => {
2019-01-29 04:41:09 +00:00
if proto == Protocol::Http1 {
Ok(Async::Ready(IoConnection::new(
ConnectionType::H1(io),
2018-11-12 07:12:54 +00:00
Instant::now(),
Some(Acquired(self.key.clone(), self.inner.take())),
2019-01-29 04:41:09 +00:00
)))
} else {
self.h2 = Some(handshake(io));
2019-01-29 18:14:00 +00:00
self.poll()
2018-11-12 07:12:54 +00:00
}
}
Ok(Async::NotReady) => Ok(Async::NotReady),
}
}
}
enum Acquire<T> {
2019-01-29 04:41:09 +00:00
Acquired(ConnectionType<T>, Instant),
2018-11-12 07:12:54 +00:00
Available,
NotAvailable,
}
2019-01-29 04:41:09 +00:00
struct AvailableConnection<Io> {
io: ConnectionType<Io>,
used: Instant,
created: Instant,
}
2018-11-14 06:53:30 +00:00
pub(crate) struct Inner<Io> {
2018-11-12 07:12:54 +00:00
conn_lifetime: Duration,
conn_keep_alive: Duration,
disconnect_timeout: Option<Duration>,
limit: usize,
acquired: usize,
available: HashMap<Key, VecDeque<AvailableConnection<Io>>>,
waiters: Slab<(
Connect,
oneshot::Sender<Result<IoConnection<Io>, ConnectError>>,
)>,
2018-11-12 07:12:54 +00:00
waiters_queue: IndexSet<(Key, usize)>,
task: Option<AtomicTask>,
2018-11-12 07:12:54 +00:00
}
2018-11-14 06:53:30 +00:00
impl<Io> Inner<Io> {
fn reserve(&mut self) {
self.acquired += 1;
}
fn release(&mut self) {
self.acquired -= 1;
}
fn release_waiter(&mut self, key: &Key, token: usize) {
self.waiters.remove(token);
self.waiters_queue.remove(&(key.clone(), token));
}
}
2018-11-12 07:12:54 +00:00
impl<Io> Inner<Io>
where
Io: AsyncRead + AsyncWrite + 'static,
{
/// connection is not available, wait
fn wait_for(
&mut self,
connect: Connect,
2018-11-12 07:12:54 +00:00
) -> (
2019-03-13 21:41:40 +00:00
oneshot::Receiver<Result<IoConnection<Io>, ConnectError>>,
2018-11-12 07:12:54 +00:00
usize,
bool,
2018-11-12 07:12:54 +00:00
) {
let (tx, rx) = oneshot::channel();
let key: Key = connect.uri.authority_part().unwrap().clone().into();
2018-11-12 07:12:54 +00:00
let entry = self.waiters.vacant_entry();
let token = entry.key();
entry.insert((connect, tx));
assert!(self.waiters_queue.insert((key, token)));
(rx, token, self.task.is_some())
2018-11-12 07:12:54 +00:00
}
fn acquire(&mut self, key: &Key) -> Acquire<Io> {
// check limits
if self.limit > 0 && self.acquired >= self.limit {
return Acquire::NotAvailable;
}
self.reserve();
// check if open connection is available
// cleanup stale connections at the same time
if let Some(ref mut connections) = self.available.get_mut(key) {
let now = Instant::now();
while let Some(conn) = connections.pop_back() {
// check if it still usable
if (now - conn.used) > self.conn_keep_alive
|| (now - conn.created) > self.conn_lifetime
{
if let Some(timeout) = self.disconnect_timeout {
2019-01-29 04:41:09 +00:00
if let ConnectionType::H1(io) = conn.io {
tokio_current_thread::spawn(CloseConnection::new(
io, timeout,
))
}
2018-11-12 07:12:54 +00:00
}
} else {
let mut io = conn.io;
let mut buf = [0; 2];
2019-01-29 04:41:09 +00:00
if let ConnectionType::H1(ref mut s) = io {
match s.read(&mut buf) {
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => (),
Ok(n) if n > 0 => {
if let Some(timeout) = self.disconnect_timeout {
if let ConnectionType::H1(io) = io {
tokio_current_thread::spawn(
CloseConnection::new(io, timeout),
)
}
}
continue;
2018-11-12 07:12:54 +00:00
}
2019-01-29 04:41:09 +00:00
Ok(_) | Err(_) => continue,
2018-11-12 07:12:54 +00:00
}
}
return Acquire::Acquired(io, conn.created);
}
}
}
Acquire::Available
}
fn release_conn(&mut self, key: &Key, io: ConnectionType<Io>, created: Instant) {
self.acquired -= 1;
self.available
.entry(key.clone())
.or_insert_with(VecDeque::new)
.push_back(AvailableConnection {
io,
created,
used: Instant::now(),
});
self.check_availibility();
}
2019-01-29 04:41:09 +00:00
fn release_close(&mut self, io: ConnectionType<Io>) {
2018-11-12 07:12:54 +00:00
self.acquired -= 1;
if let Some(timeout) = self.disconnect_timeout {
2019-01-29 04:41:09 +00:00
if let ConnectionType::H1(io) = io {
tokio_current_thread::spawn(CloseConnection::new(io, timeout))
}
2018-11-12 07:12:54 +00:00
}
self.check_availibility();
2018-11-12 07:12:54 +00:00
}
fn check_availibility(&self) {
if !self.waiters_queue.is_empty() && self.acquired < self.limit {
if let Some(t) = self.task.as_ref() {
t.notify()
}
2018-11-12 07:12:54 +00:00
}
}
}
struct CloseConnection<T> {
io: T,
timeout: Delay,
}
impl<T> CloseConnection<T>
where
T: AsyncWrite,
{
fn new(io: T, timeout: Duration) -> Self {
CloseConnection {
io,
timeout: sleep(timeout),
}
}
}
impl<T> Future for CloseConnection<T>
where
T: AsyncWrite,
{
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<(), ()> {
match self.timeout.poll() {
Ok(Async::Ready(_)) | Err(_) => Ok(Async::Ready(())),
Ok(Async::NotReady) => match self.io.shutdown() {
Ok(Async::Ready(_)) | Err(_) => Ok(Async::Ready(())),
Ok(Async::NotReady) => Ok(Async::NotReady),
},
}
}
}
struct ConnectorPoolSupport<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
{
connector: T,
inner: Rc<RefCell<Inner<Io>>>,
}
impl<T, Io> Future for ConnectorPoolSupport<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>,
T::Future: 'static,
{
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut inner = self.inner.as_ref().borrow_mut();
inner.task.as_ref().unwrap().register();
// check waiters
loop {
let (key, token) = {
if let Some((key, token)) = inner.waiters_queue.get_index(0) {
(key.clone(), *token)
} else {
break;
}
};
match inner.acquire(&key) {
Acquire::NotAvailable => break,
Acquire::Acquired(io, created) => {
let (_, tx) = inner.waiters.remove(token);
if let Err(conn) = tx.send(Ok(IoConnection::new(
io,
created,
Some(Acquired(key.clone(), Some(self.inner.clone()))),
))) {
let (io, created) = conn.unwrap().into_inner();
inner.release_conn(&key, io, created);
}
}
Acquire::Available => {
let (connect, tx) = inner.waiters.remove(token);
OpenWaitingConnection::spawn(
key.clone(),
tx,
self.inner.clone(),
self.connector.call(connect),
);
}
}
let _ = inner.waiters_queue.swap_remove_index(0);
}
Ok(Async::NotReady)
}
}
struct OpenWaitingConnection<F, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
{
fut: F,
key: Key,
h2: Option<Handshake<Io, Bytes>>,
rx: Option<oneshot::Sender<Result<IoConnection<Io>, ConnectError>>>,
inner: Option<Rc<RefCell<Inner<Io>>>>,
}
impl<F, Io> OpenWaitingConnection<F, Io>
where
F: Future<Item = (Io, Protocol), Error = ConnectError> + 'static,
Io: AsyncRead + AsyncWrite + 'static,
{
fn spawn(
key: Key,
rx: oneshot::Sender<Result<IoConnection<Io>, ConnectError>>,
inner: Rc<RefCell<Inner<Io>>>,
fut: F,
) {
tokio_current_thread::spawn(OpenWaitingConnection {
key,
fut,
h2: None,
rx: Some(rx),
inner: Some(inner),
})
}
}
impl<F, Io> Drop for OpenWaitingConnection<F, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
{
fn drop(&mut self) {
if let Some(inner) = self.inner.take() {
let mut inner = inner.as_ref().borrow_mut();
inner.release();
inner.check_availibility();
}
}
}
impl<F, Io> Future for OpenWaitingConnection<F, Io>
where
F: Future<Item = (Io, Protocol), Error = ConnectError>,
Io: AsyncRead + AsyncWrite,
{
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.fut.poll() {
Err(err) => {
let _ = self.inner.take();
if let Some(rx) = self.rx.take() {
let _ = rx.send(Err(err));
}
Err(())
}
Ok(Async::Ready((io, proto))) => {
if proto == Protocol::Http1 {
let rx = self.rx.take().unwrap();
let _ = rx.send(Ok(IoConnection::new(
ConnectionType::H1(io),
Instant::now(),
Some(Acquired(self.key.clone(), self.inner.take())),
)));
Ok(Async::Ready(()))
} else {
self.h2 = Some(handshake(io));
self.poll()
}
}
Ok(Async::NotReady) => Ok(Async::NotReady),
}
}
}
2018-11-14 06:53:30 +00:00
pub(crate) struct Acquired<T>(Key, Option<Rc<RefCell<Inner<T>>>>);
2018-11-12 07:12:54 +00:00
impl<T> Acquired<T>
where
T: AsyncRead + AsyncWrite + 'static,
{
2018-11-15 19:10:23 +00:00
pub(crate) fn close(&mut self, conn: IoConnection<T>) {
2018-11-12 07:12:54 +00:00
if let Some(inner) = self.1.take() {
let (io, _) = conn.into_inner();
inner.as_ref().borrow_mut().release_close(io);
}
}
2018-11-15 19:10:23 +00:00
pub(crate) fn release(&mut self, conn: IoConnection<T>) {
2018-11-12 07:12:54 +00:00
if let Some(inner) = self.1.take() {
let (io, created) = conn.into_inner();
inner
.as_ref()
.borrow_mut()
.release_conn(&self.0, io, created);
}
}
}
2018-11-14 06:53:30 +00:00
impl<T> Drop for Acquired<T> {
2018-11-12 07:12:54 +00:00
fn drop(&mut self) {
if let Some(inner) = self.1.take() {
inner.as_ref().borrow_mut().release();
}
}
}