connection_reuse: drop dead connections. (#178)

Currently, connection substreams are added to
`connection_reuse::Shared::active_connections`, but never removed. This
is not least because the `StreamMuxer` trait defines its inbound and
outbound substream futures to always yield a substream and contains no
provision to signal that no more substreams can be created, which would
allow client code (e.g. `ConnectionReuse`) to detect this and purge its
caches.

This PR defines the `StreamMuxer` trait to optionally yield
inbound/outbound substreams and changes `libp2p-mplex` to handle
stream EOFs by marking the underlying resource as closed.
`ConnectionReuse` will remove stream muxers from its active connections
cache if a `None` substream is returned.
This commit is contained in:
Toralf Wittner
2018-05-14 14:49:29 +02:00
committed by Pierre Krieger
parent 11f655dd6a
commit 4382adcbde
8 changed files with 204 additions and 96 deletions

View File

@ -172,7 +172,7 @@ pub struct InboundFuture<T, Buf: Array> {
}
impl<T: AsyncRead, Buf: Array<Item = u8>> Future for InboundFuture<T, Buf> {
type Item = Substream<T, Buf>;
type Item = Option<Substream<T, Buf>>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
@ -181,6 +181,10 @@ impl<T: AsyncRead, Buf: Array<Item = u8>> Future for InboundFuture<T, Buf> {
Async::NotReady => return Ok(Async::NotReady),
};
if lock.is_closed() {
return Ok(Async::Ready(None));
}
// Attempt to make progress, but don't block if we can't
match read_stream(&mut lock, None) {
Ok(_) => {}
@ -200,12 +204,12 @@ impl<T: AsyncRead, Buf: Array<Item = u8>> Future for InboundFuture<T, Buf> {
lock.open_stream(id);
Ok(Async::Ready(Substream::new(
Ok(Async::Ready(Some(Substream::new(
id,
self.end,
name,
Arc::clone(&self.state),
)))
))))
}
}
@ -230,7 +234,7 @@ fn nonce_to_id(id: usize, end: Endpoint) -> u32 {
}
impl<T: AsyncWrite, Buf: Array> Future for OutboundFuture<T, Buf> {
type Item = Substream<T, Buf>;
type Item = Option<Substream<T, Buf>>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
@ -239,6 +243,10 @@ impl<T: AsyncWrite, Buf: Array> Future for OutboundFuture<T, Buf> {
Async::NotReady => return Ok(Async::NotReady),
};
if lock.is_closed() {
return Ok(Async::Ready(None));
}
loop {
let (mut id_str, id) = self.current_id.take().unwrap_or_else(|| {
let next = nonce_to_id(
@ -260,12 +268,12 @@ impl<T: AsyncWrite, Buf: Array> Future for OutboundFuture<T, Buf> {
debug_assert!(id_str.position() <= id_str.get_ref().len() as u64);
if id_str.position() == id_str.get_ref().len() as u64 {
if lock.open_stream(id) {
return Ok(Async::Ready(Substream::new(
return Ok(Async::Ready(Some(Substream::new(
id,
self.meta.end,
Bytes::from(&id_str.get_ref()[..]),
Arc::clone(&self.state),
)));
))));
}
} else {
self.current_id = Some((id_str, id));
@ -393,7 +401,12 @@ mod tests {
let mplex = Multiplex::dial(stream);
let mut substream = mplex.clone().outbound().wait().unwrap();
let mut substream = mplex
.clone()
.outbound()
.wait()
.unwrap()
.expect("outbound substream");
assert!(tokio::write_all(&mut substream, message).wait().is_ok());
@ -410,7 +423,7 @@ mod tests {
let mplex = Multiplex::listen(stream);
let mut substream = mplex.inbound().wait().unwrap();
let mut substream = mplex.inbound().wait().unwrap().expect("inbound substream");
assert_eq!(id, substream.id());
assert_eq!(
@ -435,7 +448,14 @@ mod tests {
let mut outbound: Vec<Substream<_>> = vec![];
for _ in 0..5 {
outbound.push(mplex.clone().outbound().wait().unwrap());
outbound.push(
mplex
.clone()
.outbound()
.wait()
.unwrap()
.expect("outbound substream"),
);
}
outbound.sort_by_key(|a| a.id());
@ -455,7 +475,14 @@ mod tests {
let mut inbound: Vec<Substream<_>> = vec![];
for _ in 0..5 {
inbound.push(mplex.clone().inbound().wait().unwrap());
inbound.push(
mplex
.clone()
.inbound()
.wait()
.unwrap()
.expect("inbound substream"),
);
}
inbound.sort_by_key(|a| a.id());
@ -515,7 +542,7 @@ mod tests {
let mplex = Multiplex::listen(io::Cursor::new(input));
let mut substream = mplex.inbound().wait().unwrap();
let mut substream = mplex.inbound().wait().unwrap().expect("inbound substream");
assert_eq!(substream.id(), 0);
assert_eq!(substream.name(), None);
@ -567,7 +594,7 @@ mod tests {
let mplex = Multiplex::listen(io::Cursor::new(input));
let mut substream = mplex.inbound().wait().unwrap();
let mut substream = mplex.inbound().wait().unwrap().expect("inbound substream");
assert_eq!(substream.id(), 0);
assert_eq!(substream.name(), None);
@ -615,7 +642,7 @@ mod tests {
let mplex = Multiplex::listen(io::Cursor::new(data));
let mut substream = mplex.inbound().wait().unwrap();
let mut substream = mplex.inbound().wait().unwrap().expect("inbound substream");
assert_eq!(substream.id(), 1);
@ -650,7 +677,14 @@ mod tests {
let mut outbound: Vec<Substream<_, Buffer>> = vec![];
for _ in 0..5 {
outbound.push(mplex.clone().outbound().wait().unwrap());
outbound.push(
mplex
.clone()
.outbound()
.wait()
.unwrap()
.expect("outbound substream"),
);
}
outbound.sort_by_key(|a| a.id());
@ -670,7 +704,12 @@ mod tests {
let mut inbound: Vec<Substream<_, Buffer>> = vec![];
for _ in 0..5 {
let inb: Substream<_, Buffer> = mplex.clone().inbound().wait().unwrap();
let inb: Substream<_, Buffer> = mplex
.clone()
.inbound()
.wait()
.unwrap()
.expect("inbound substream");
inbound.push(inb);
}