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:
		
							
								
								
									
										120
									
								
								src/client.rs
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								src/client.rs
									
									
									
									
									
								
							| @@ -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))) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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(()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 ===== | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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 { | ||||
|                 .. | ||||
|   | ||||
| @@ -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, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user