split Client into (Client, Connection) (#107)

The Connection type is a `Future` that drives all of the IO of the
client connection.

The Client type is separate, and is used to send requests into the
connection.
This commit is contained in:
Sean McArthur
2017-09-28 16:55:12 -07:00
committed by GitHub
parent 510800ef28
commit f8efb053b9
23 changed files with 489 additions and 262 deletions

View File

@@ -1,7 +1,7 @@
use codec::{Codec, RecvError};
use frame::{Headers, Pseudo, Settings, StreamId};
use frame::Reason::*;
use proto::{self, Connection, WindowSize};
use proto::{self, WindowSize};
use bytes::{Bytes, IntoBuf};
use futures::{Async, Future, MapErr, Poll};
@@ -21,8 +21,13 @@ pub struct Handshake<T: AsyncRead + AsyncWrite, B: IntoBuf = Bytes> {
}
/// Marker type indicating a client peer
pub struct Client<T, B: IntoBuf> {
connection: Connection<T, Peer, B>,
pub struct Client<B: IntoBuf> {
inner: proto::Streams<B::Buf, Peer>,
pending: Option<proto::StreamKey>,
}
pub struct Connection<T, B: IntoBuf> {
inner: proto::Connection<T, Peer, B>,
}
#[derive(Debug)]
@@ -45,10 +50,9 @@ pub struct Builder {
#[derive(Debug)]
pub(crate) struct Peer;
impl<T> Client<T, Bytes>
where
T: AsyncRead + AsyncWrite,
{
// ===== impl Client =====
impl Client<Bytes> {
/// Bind an H2 client connection.
///
/// Returns a future which resolves to the connection value once the H2
@@ -56,24 +60,29 @@ where
///
/// It's important to note that this does not **flush** the outbound
/// settings to the wire.
pub fn handshake(io: T) -> Handshake<T, Bytes> {
pub fn handshake<T>(io: T) -> Handshake<T, Bytes>
where
T: AsyncRead + AsyncWrite,
{
Builder::default().handshake(io)
}
}
impl Client<(), Bytes> {
impl Client<Bytes> {
/// Creates a Client Builder to customize a Client before binding.
pub fn builder() -> Builder {
Builder::default()
}
}
impl<T, B> Client<T, B>
impl<B> Client<B>
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
fn handshake2(io: T, builder: Builder) -> Handshake<T, B> {
fn handshake2<T>(io: T, builder: Builder) -> Handshake<T, B>
where
T: AsyncRead + AsyncWrite,
{
use tokio_io::io;
debug!("binding client connection");
@@ -91,7 +100,9 @@ where
/// Returns `Ready` when the connection can initialize a new HTTP 2.0
/// stream.
pub fn poll_ready(&mut self) -> Poll<(), ::Error> {
self.connection.poll_send_request_ready()
try_ready!(self.inner.poll_pending_open(self.pending.as_ref()));
self.pending = None;
Ok(().into())
}
/// Send a request on a new HTTP 2.0 stream
@@ -100,10 +111,13 @@ where
request: Request<()>,
end_of_stream: bool,
) -> Result<Stream<B>, ::Error> {
self.connection
.send_request(request, end_of_stream)
self.inner
.send_request(request, end_of_stream, self.pending.as_ref())
.map_err(Into::into)
.map(|stream| {
if stream.is_pending_open() {
self.pending = Some(stream.key());
}
Stream {
inner: stream,
}
@@ -111,37 +125,30 @@ where
}
}
impl<T, B> Future for Client<T, B>
impl<B> fmt::Debug for Client<B>
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
type Item = ();
type Error = ::Error;
fn poll(&mut self) -> Poll<(), ::Error> {
self.connection.poll().map_err(Into::into)
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Client").finish()
}
}
impl<T, B> fmt::Debug for Client<T, B>
impl<B> Clone for Client<B>
where
T: AsyncRead + AsyncWrite,
T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug,
B: IntoBuf,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Client")
.field("connection", &self.connection)
.finish()
fn clone(&self) -> Self {
Client {
inner: self.inner.clone(),
pending: None,
}
}
}
#[cfg(feature = "unstable")]
impl<T, B> Client<T, B>
impl<B> Client<B>
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
/// Returns the number of active streams.
@@ -149,7 +156,7 @@ where
/// An active stream is a stream that has not yet transitioned to a closed
/// state.
pub fn num_active_streams(&self) -> usize {
self.connection.num_active_streams()
self.inner.num_active_streams()
}
/// Returns the number of streams that are held in memory.
@@ -158,7 +165,7 @@ where
/// stay in memory for some reason. For example, there are still outstanding
/// userspace handles pointing to the slot.
pub fn num_wired_streams(&self) -> usize {
self.connection.num_wired_streams()
self.inner.num_wired_streams()
}
}
@@ -219,13 +226,40 @@ impl Default for Builder {
}
}
// ===== impl Connection =====
impl<T, B> Future for Connection<T, B>
where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
type Item = ();
type Error = ::Error;
fn poll(&mut self) -> Poll<(), ::Error> {
self.inner.poll().map_err(Into::into)
}
}
impl<T, B> fmt::Debug for Connection<T, B>
where
T: AsyncRead + AsyncWrite,
T: fmt::Debug,
B: fmt::Debug + IntoBuf,
B::Buf: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.inner, fmt)
}
}
// ===== impl Handshake =====
impl<T, B: IntoBuf> Future for Handshake<T, B>
where
T: AsyncRead + AsyncWrite,
{
type Item = Client<T, B>;
type Item = (Client<B>, Connection<T, B>);
type Error = ::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
@@ -245,10 +279,16 @@ where
.buffer(self.builder.settings.clone().into())
.expect("invalid SETTINGS frame");
let connection = Connection::new(codec, &self.builder.settings, self.builder.stream_id);
Ok(Async::Ready(Client {
connection,
}))
let connection =
proto::Connection::new(codec, &self.builder.settings, self.builder.stream_id);
let client = Client {
inner: connection.streams().clone(),
pending: None,
};
let conn = Connection {
inner: connection,
};
Ok(Async::Ready((client, conn)))
}
}

View File

@@ -1,5 +1,5 @@
use {client, frame, proto, server};
use codec::{RecvError, SendError};
use codec::RecvError;
use frame::Reason;
use frame::DEFAULT_INITIAL_WINDOW_SIZE;
@@ -7,7 +7,6 @@ use proto::*;
use bytes::{Bytes, IntoBuf};
use futures::Stream;
use http::Request;
use tokio_io::{AsyncRead, AsyncWrite};
use std::marker::PhantomData;
@@ -249,18 +248,8 @@ where
T: AsyncRead + AsyncWrite,
B: IntoBuf,
{
/// Returns `Ready` when new the connection is able to support a new request stream.
pub fn poll_send_request_ready(&mut self) -> Poll<(), ::Error> {
self.streams.poll_send_request_ready()
}
/// Initialize a new HTTP/2.0 stream and send the message.
pub fn send_request(
&mut self,
request: Request<()>,
end_of_stream: bool,
) -> Result<StreamRef<B::Buf, client::Peer>, SendError> {
self.streams.send_request(request, end_of_stream)
pub(crate) fn streams(&self) -> &Streams<B::Buf, client::Peer> {
&self.streams
}
}
@@ -273,19 +262,3 @@ where
self.streams.next_incoming()
}
}
#[cfg(feature = "unstable")]
impl<T, P, B> Connection<T, P, B>
where
T: AsyncRead + AsyncWrite,
P: Peer,
B: IntoBuf,
{
pub fn num_active_streams(&self) -> usize {
self.streams.num_active_streams()
}
pub fn num_wired_streams(&self) -> usize {
self.streams.num_wired_streams()
}
}

View File

@@ -8,7 +8,7 @@ mod streams;
pub(crate) use self::connection::Connection;
pub(crate) use self::error::Error;
pub(crate) use self::peer::Peer;
pub(crate) use self::streams::{StreamRef, Streams};
pub(crate) use self::streams::{Key as StreamKey, StreamRef, Streams};
use codec::Codec;

View File

@@ -1,5 +1,4 @@
use super::*;
use client;
use std::marker::PhantomData;
use std::usize;
@@ -10,20 +9,17 @@ where
P: Peer,
{
/// Maximum number of locally initiated streams
max_send_streams: Option<usize>,
max_send_streams: usize,
/// Current number of remote initiated streams
num_send_streams: usize,
/// Maximum number of remote initiated streams
max_recv_streams: Option<usize>,
max_recv_streams: usize,
/// Current number of locally initiated streams
num_recv_streams: usize,
/// Task awaiting notification to open a new stream.
blocked_open: Option<task::Task>,
_p: PhantomData<P>,
}
@@ -34,22 +30,17 @@ where
/// Create a new `Counts` using the provided configuration values.
pub fn new(config: &Config) -> Self {
Counts {
max_send_streams: config.local_max_initiated,
max_send_streams: config.local_max_initiated.unwrap_or(usize::MAX),
num_send_streams: 0,
max_recv_streams: config.remote_max_initiated,
max_recv_streams: config.remote_max_initiated.unwrap_or(usize::MAX),
num_recv_streams: 0,
blocked_open: None,
_p: PhantomData,
}
}
/// Returns true if the receive stream concurrency can be incremented
pub fn can_inc_num_recv_streams(&self) -> bool {
if let Some(max) = self.max_recv_streams {
max > self.num_recv_streams
} else {
true
}
self.max_recv_streams > self.num_recv_streams
}
/// Increments the number of concurrent receive streams.
@@ -66,11 +57,7 @@ where
/// Returns true if the send stream concurrency can be incremented
pub fn can_inc_num_send_streams(&self) -> bool {
if let Some(max) = self.max_send_streams {
max > self.num_send_streams
} else {
true
}
self.max_send_streams > self.num_send_streams
}
/// Increments the number of concurrent send streams.
@@ -87,7 +74,7 @@ where
pub fn apply_remote_settings(&mut self, settings: &frame::Settings) {
if let Some(val) = settings.max_concurrent_streams() {
self.max_send_streams = Some(val as usize);
self.max_send_streams = val as usize;
}
}
@@ -99,7 +86,7 @@ where
where
F: FnOnce(&mut Self, &mut store::Ptr<B, P>) -> U,
{
let is_counted = stream.state.is_counted();
let is_counted = stream.is_counted();
// Run the action
let ret = f(self, &mut stream);
@@ -127,29 +114,10 @@ where
}
fn dec_num_streams(&mut self, id: StreamId) {
use std::usize;
if P::is_local_init(id) {
self.num_send_streams -= 1;
if self.num_send_streams < self.max_send_streams.unwrap_or(usize::MAX) {
if let Some(task) = self.blocked_open.take() {
task.notify();
}
}
} else {
self.num_recv_streams -= 1;
}
}
}
impl Counts<client::Peer> {
pub fn poll_open_ready(&mut self) -> Async<()> {
if !self.can_inc_num_send_streams() {
self.blocked_open = Some(task::current());
return Async::NotReady;
}
return Async::Ready(());
}
}

View File

@@ -10,6 +10,7 @@ mod stream;
mod streams;
pub(crate) use self::prioritize::Prioritized;
pub(crate) use self::store::Key;
pub(crate) use self::streams::{StreamRef, Streams};
use self::buffer::Buffer;

View File

@@ -22,6 +22,9 @@ where
/// Queue of streams waiting for window capacity to produce data.
pending_capacity: store::Queue<B, stream::NextSendCapacity, P>,
/// Streams waiting for capacity due to max concurrency
pending_open: store::Queue<B, stream::NextOpen, P>,
/// Connection level flow control governing sent data
flow: FlowControl,
@@ -60,6 +63,7 @@ where
Prioritize {
pending_send: store::Queue::new(),
pending_capacity: store::Queue::new(),
pending_open: store::Queue::new(),
flow: flow,
buffer: Buffer::new(),
}
@@ -75,15 +79,22 @@ where
// Queue the frame in the buffer
stream.pending_send.push_back(&mut self.buffer, frame);
// Queue the stream
self.pending_send.push(stream);
// If the stream is waiting to be opened, nothing more to do.
if !stream.is_pending_open {
// Queue the stream
self.pending_send.push(stream);
// Notify the connection.
if let Some(task) = task.take() {
task.notify();
// Notify the connection.
if let Some(task) = task.take() {
task.notify();
}
}
}
pub fn queue_open(&mut self, stream: &mut store::Ptr<B, P>) {
self.pending_open.push(stream);
}
/// Send a data frame
pub fn send_data(
&mut self,
@@ -371,6 +382,7 @@ where
trace!("poll_complete");
loop {
self.schedule_pending_open(store, counts);
match self.pop_frame(store, max_frame_len, counts) {
Some(frame) => {
trace!("writing frame={:?}", frame);
@@ -482,7 +494,7 @@ where
trace!("pop_frame; stream={:?}", stream.id);
debug_assert!(!stream.pending_send.is_empty());
let is_counted = stream.state.is_counted();
let is_counted = stream.is_counted();
let frame = match stream.pending_send.pop_front(&mut self.buffer).unwrap() {
Frame::Data(mut frame) => {
@@ -594,6 +606,23 @@ where
}
}
}
fn schedule_pending_open(&mut self, store: &mut Store<B, P>, counts: &mut Counts<P>) {
trace!("schedule_pending_open");
// check for any pending open streams
while counts.can_inc_num_send_streams() {
if let Some(mut stream) = self.pending_open.pop(store) {
trace!("schedule_pending_open; stream={:?}", stream.id);
counts.inc_num_send_streams();
self.pending_send.push(&mut stream);
if let Some(task) = stream.open_task.take() {
task.notify();
}
} else {
return;
}
}
}
}
// ===== impl Prioritized =====

View File

@@ -43,20 +43,9 @@ where
self.init_window_sz
}
/// Update state reflecting a new, locally opened stream
///
/// Returns the stream state if successful. `None` if refused
pub fn open(&mut self, counts: &mut Counts<P>) -> Result<StreamId, UserError> {
if !counts.can_inc_num_send_streams() {
return Err(Rejected.into());
}
pub fn open(&mut self) -> Result<StreamId, UserError> {
let stream_id = self.try_open()?;
// Increment the number of locally initiated streams
counts.inc_num_send_streams();
self.next_stream_id = stream_id.next_id();
Ok(stream_id)
}
@@ -64,6 +53,7 @@ where
&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
counts: &mut Counts<P>,
task: &mut Option<Task>,
) -> Result<(), UserError> {
trace!(
@@ -77,6 +67,14 @@ where
// Update the state
stream.state.send_open(end_stream)?;
if P::is_local_init(frame.stream_id()) {
if counts.can_inc_num_send_streams() {
counts.inc_num_send_streams();
} else {
self.prioritize.queue_open(stream);
}
}
// Queue the frame for sending
self.prioritize.queue_frame(frame.into(), stream, task);

View File

@@ -251,9 +251,8 @@ impl State {
}
}
/// Returns true if a stream with the current state counts against the
/// concurrency limit.
pub fn is_counted(&self) -> bool {
/// Returns true if a stream is open or half-closed.
pub fn is_at_least_half_open(&self) -> bool {
match self.inner {
Open {
..

View File

@@ -13,8 +13,9 @@ pub(super) struct Store<B, P>
where
P: Peer,
{
slab: slab::Slab<Stream<B, P>>,
ids: OrderMap<StreamId, usize>,
slab: slab::Slab<(StoreId, Stream<B, P>)>,
ids: OrderMap<StreamId, (usize, StoreId)>,
counter: StoreId,
}
/// "Pointer" to an entry in the store
@@ -28,7 +29,12 @@ where
/// References an entry in the store.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct Key(usize);
pub(crate) struct Key {
index: usize,
store_id: StoreId,
}
type StoreId = usize;
#[derive(Debug)]
pub(super) struct Queue<B, N, P>
@@ -64,15 +70,16 @@ pub(super) enum Entry<'a, B: 'a, P: Peer + 'a> {
}
pub(super) struct OccupiedEntry<'a> {
ids: ordermap::OccupiedEntry<'a, StreamId, usize>,
ids: ordermap::OccupiedEntry<'a, StreamId, (usize, StoreId)>,
}
pub(super) struct VacantEntry<'a, B: 'a, P>
where
P: Peer + 'a,
{
ids: ordermap::VacantEntry<'a, StreamId, usize>,
slab: &'a mut slab::Slab<Stream<B, P>>,
ids: ordermap::VacantEntry<'a, StreamId, (usize, StoreId)>,
slab: &'a mut slab::Slab<(StoreId, Stream<B, P>)>,
counter: &'a mut usize,
}
pub(super) trait Resolve<B, P>
@@ -92,6 +99,7 @@ where
Store {
slab: slab::Slab::new(),
ids: OrderMap::new(),
counter: 0,
}
}
@@ -106,17 +114,25 @@ where
};
Some(Ptr {
key: Key(key),
key: Key {
index: key.0,
store_id: key.1,
},
store: self,
})
}
pub fn insert(&mut self, id: StreamId, val: Stream<B, P>) -> Ptr<B, P> {
let key = self.slab.insert(val);
assert!(self.ids.insert(id, key).is_none());
let store_id = self.counter;
self.counter = self.counter.wrapping_add(1);
let key = self.slab.insert((store_id, val));
assert!(self.ids.insert(id, (key, store_id)).is_none());
Ptr {
key: Key(key),
key: Key {
index: key,
store_id,
},
store: self,
}
}
@@ -131,6 +147,7 @@ where
Vacant(e) => Entry::Vacant(VacantEntry {
ids: e,
slab: &mut self.slab,
counter: &mut self.counter,
}),
}
}
@@ -147,7 +164,10 @@ where
let key = *self.ids.get_index(i).unwrap().1;
f(Ptr {
key: Key(key),
key: Key {
index: key.0,
store_id: key.1,
},
store: self,
})?;
@@ -185,7 +205,9 @@ where
type Output = Stream<B, P>;
fn index(&self, key: Key) -> &Self::Output {
self.slab.index(key.0)
let slot = self.slab.index(key.index);
assert_eq!(slot.0, key.store_id);
&slot.1
}
}
@@ -194,7 +216,9 @@ where
P: Peer,
{
fn index_mut(&mut self, key: Key) -> &mut Self::Output {
self.slab.index_mut(key.0)
let slot = self.slab.index_mut(key.index);
assert_eq!(slot.0, key.store_id);
&mut slot.1
}
}
@@ -319,7 +343,7 @@ where
debug_assert!(!self.store.ids.contains_key(&self.id));
// Remove the stream state
self.store.slab.remove(self.key.0).id
self.store.slab.remove(self.key.index).1.id
}
/// Remove the StreamId -> stream state association.
@@ -351,7 +375,7 @@ where
type Target = Stream<B, P>;
fn deref(&self) -> &Stream<B, P> {
&self.store.slab[self.key.0]
&self.store.slab[self.key.index].1
}
}
@@ -360,7 +384,7 @@ where
P: Peer,
{
fn deref_mut(&mut self) -> &mut Stream<B, P> {
&mut self.store.slab[self.key.0]
&mut self.store.slab[self.key.index].1
}
}
@@ -368,7 +392,11 @@ where
impl<'a> OccupiedEntry<'a> {
pub fn key(&self) -> Key {
Key(*self.ids.get())
let tup = self.ids.get();
Key {
index: tup.0,
store_id: tup.1,
}
}
}
@@ -380,11 +408,16 @@ where
{
pub fn insert(self, value: Stream<B, P>) -> Key {
// Insert the value in the slab
let key = self.slab.insert(value);
let store_id = *self.counter;
*self.counter = store_id.wrapping_add(1);
let index = self.slab.insert((store_id, value));
// Insert the handle in the ID map
self.ids.insert(key);
self.ids.insert((index, store_id));
Key(key)
Key {
index,
store_id,
}
}
}

View File

@@ -60,6 +60,15 @@ where
/// Set to true when the send capacity has been incremented
pub send_capacity_inc: bool,
/// Next node in the open linked list
pub next_open: Option<store::Key>,
/// Set to true when the stream is pending to be opened
pub is_pending_open: bool,
/// Task tracking when stream can be "opened", or initially sent to socket.
pub open_task: Option<task::Task>,
// ===== Fields related to receiving =====
/// Next node in the accept linked list
pub next_pending_accept: Option<store::Key>,
@@ -111,6 +120,9 @@ pub(super) struct NextSendCapacity;
#[derive(Debug)]
pub(super) struct NextWindowUpdate;
#[derive(Debug)]
pub(super) struct NextOpen;
impl<B, P> Stream<B, P>
where
P: Peer,
@@ -150,6 +162,9 @@ where
is_pending_send_capacity: false,
next_pending_send_capacity: None,
send_capacity_inc: false,
is_pending_open: false,
next_open: None,
open_task: None,
// ===== Fields related to receiving =====
next_pending_accept: None,
@@ -177,6 +192,12 @@ where
self.ref_count -= 1;
}
/// Returns true if a stream with the current state counts against the
/// concurrency limit.
pub fn is_counted(&self) -> bool {
!self.is_pending_open && self.state.is_at_least_half_open()
}
/// Returns true if the stream is closed
pub fn is_closed(&self) -> bool {
// The state has fully transitioned to closed.
@@ -337,6 +358,28 @@ impl store::Next for NextWindowUpdate {
}
}
impl store::Next for NextOpen {
fn next<B, P: Peer>(stream: &Stream<B, P>) -> Option<store::Key> {
stream.next_open
}
fn set_next<B, P: Peer>(stream: &mut Stream<B, P>, key: Option<store::Key>) {
stream.next_open = key;
}
fn take_next<B, P: Peer>(stream: &mut Stream<B, P>) -> Option<store::Key> {
stream.next_open.take()
}
fn is_queued<B, P: Peer>(stream: &Stream<B, P>) -> bool {
stream.is_pending_open
}
fn set_queued<B, P: Peer>(stream: &mut Stream<B, P>, val: bool) {
stream.is_pending_open = val;
}
}
// ===== impl ContentLength =====
impl ContentLength {

View File

@@ -323,6 +323,7 @@ where
&mut self,
request: Request<()>,
end_of_stream: bool,
pending: Option<&store::Key>,
) -> Result<StreamRef<B, P>, SendError> {
use super::stream::ContentLength;
use http::Method;
@@ -336,8 +337,21 @@ where
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
// Initialize a new stream. This fails if the connection is at capacity.
let stream_id = me.actions.send.open(&mut me.counts)?;
me.actions.send.ensure_next_stream_id()?;
// The `pending` argument is provided by the `Client`, and holds
// a store `Key` of a `Stream` that may have been not been opened
// yet.
//
// If that stream is still pending, the Client isn't allowed to
// queue up another pending stream. They should use `poll_ready`.
if let Some(key) = pending {
if me.store.resolve(*key).is_pending_open {
return Err(UserError::Rejected.into());
}
}
let stream_id = me.actions.send.open()?;
let mut stream = Stream::new(
stream_id,
@@ -354,9 +368,12 @@ where
let mut stream = me.store.insert(stream.id, stream);
me.actions
.send
.send_headers(headers, &mut stream, &mut me.actions.task)?;
me.actions.send.send_headers(
headers,
&mut stream,
&mut me.counts,
&mut me.actions.task,
)?;
// Given that the stream has been initialized, it should not be in the
// closed state.
@@ -403,13 +420,21 @@ impl<B> Streams<B, client::Peer>
where
B: Buf,
{
pub fn poll_send_request_ready(&mut self) -> Poll<(), ::Error> {
pub fn poll_pending_open(&mut self, key: Option<&store::Key>) -> Poll<(), ::Error> {
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
me.actions.send.ensure_next_stream_id()?;
Ok(me.counts.poll_open_ready())
if let Some(key) = key {
let mut stream = me.store.resolve(*key);
trace!("poll_pending_open; stream = {:?}", stream.is_pending_open);
if stream.is_pending_open {
stream.send_task = Some(task::current());
return Ok(Async::NotReady);
}
}
Ok(().into())
}
}
@@ -430,6 +455,19 @@ where
}
}
// no derive because we don't need B and P to be Clone.
impl<B, P> Clone for Streams<B, P>
where
B: Buf,
P: Peer,
{
fn clone(&self) -> Self {
Streams {
inner: self.inner.clone(),
}
}
}
// ===== impl StreamRef =====
impl<B, P> StreamRef<B, P>
@@ -493,10 +531,12 @@ where
let stream = me.store.resolve(self.key);
let actions = &mut me.actions;
me.counts.transition(stream, |_, stream| {
me.counts.transition(stream, |counts, stream| {
let frame = server::Peer::convert_send_message(stream.id, response, end_of_stream);
actions.send.send_headers(frame, stream, &mut actions.task)
actions
.send
.send_headers(frame, stream, counts, &mut actions.task)
})
}
@@ -569,6 +609,10 @@ where
me.actions.send.poll_capacity(&mut stream)
}
pub(crate) fn key(&self) -> store::Key {
self.key
}
}
impl<B> StreamRef<B, server::Peer>
@@ -603,6 +647,12 @@ where
me.actions.recv.poll_response(&mut stream)
}
pub fn is_pending_open(&self) -> bool {
let mut me = self.inner.lock().unwrap();
me.store.resolve(self.key).is_pending_open
}
}
impl<B, P> Clone for StreamRef<B, P>
@@ -625,7 +675,15 @@ where
P: Peer,
{
fn drop(&mut self) {
let mut me = self.inner.lock().unwrap();
let mut me = match self.inner.lock() {
Ok(inner) => inner,
Err(_) => if ::std::thread::panicking() {
trace!("StreamRef::drop; mutex poisoned");
return;
} else {
panic!("StreamRef::drop; mutex poisoned");
},
};
let me = &mut *me;