Progress towards allowing large writes
This commit is contained in:
		| @@ -78,6 +78,9 @@ pub enum User { | |||||||
|     /// transmit a Data frame to the remote. |     /// transmit a Data frame to the remote. | ||||||
|     FlowControlViolation, |     FlowControlViolation, | ||||||
|  |  | ||||||
|  |     /// The payload size is too big | ||||||
|  |     PayloadTooBig, | ||||||
|  |  | ||||||
|     /// The connection state is corrupt and the connection should be dropped. |     /// The connection state is corrupt and the connection should be dropped. | ||||||
|     Corrupt, |     Corrupt, | ||||||
|  |  | ||||||
| @@ -128,6 +131,7 @@ macro_rules! user_desc { | |||||||
|             StreamReset(_) => concat!($prefix, "frame sent on reset stream"), |             StreamReset(_) => concat!($prefix, "frame sent on reset stream"), | ||||||
|             Corrupt => concat!($prefix, "connection state corrupt"), |             Corrupt => concat!($prefix, "connection state corrupt"), | ||||||
|             Rejected => concat!($prefix, "stream would exceed remote max concurrency"), |             Rejected => concat!($prefix, "stream would exceed remote max concurrency"), | ||||||
|  |             PayloadTooBig => concat!($prefix, "payload too big"), | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -52,9 +52,24 @@ impl<T> Data<T> { | |||||||
|         &self.data |         &self.data | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn payload_mut(&mut self) -> &mut T { | ||||||
|  |         &mut self.data | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn into_payload(self) -> T { |     pub fn into_payload(self) -> T { | ||||||
|         self.data |         self.data | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn map<F, U>(self, f: F) -> Data<U> | ||||||
|  |         where F: FnOnce(T) -> U, | ||||||
|  |     { | ||||||
|  |         Data { | ||||||
|  |             stream_id: self.stream_id, | ||||||
|  |             data: f(self.data), | ||||||
|  |             flags: self.flags, | ||||||
|  |             pad_len: self.pad_len, | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: Buf> Data<T> { | impl<T: Buf> Data<T> { | ||||||
|   | |||||||
| @@ -80,6 +80,24 @@ impl<T> Frame<T> { | |||||||
|             _ => false, |             _ => false, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn map<F, U>(self, f: F) -> Frame<U> | ||||||
|  |         where F: FnOnce(T) -> U | ||||||
|  |     { | ||||||
|  |         use self::Frame::*; | ||||||
|  |  | ||||||
|  |         match self { | ||||||
|  |             Data(frame) => frame.map(f).into(), | ||||||
|  |             Headers(frame) => frame.into(), | ||||||
|  |             Priority(frame) => frame.into(), | ||||||
|  |             PushPromise(frame) => frame.into(), | ||||||
|  |             Settings(frame) => frame.into(), | ||||||
|  |             Ping(frame) => frame.into(), | ||||||
|  |             GoAway(frame) => frame.into(), | ||||||
|  |             WindowUpdate(frame) => frame.into(), | ||||||
|  |             Reset(frame) => frame.into(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T: Buf> Frame<T> { | impl<T: Buf> Frame<T> { | ||||||
|   | |||||||
| @@ -12,6 +12,15 @@ impl<T, B> Codec<T, B> { | |||||||
|         self.framed_write().apply_remote_settings(frame); |         self.framed_write().apply_remote_settings(frame); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Takes the data payload value that was fully written to the socket | ||||||
|  |     pub(crate) fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> { | ||||||
|  |         self.framed_write().take_last_data_frame() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn max_send_frame_size(&self) -> usize { | ||||||
|  |         self.inner.get_ref().max_frame_size() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     fn framed_read(&mut self) -> &mut FramedRead<FramedWrite<T, B>> { |     fn framed_read(&mut self) -> &mut FramedRead<FramedWrite<T, B>> { | ||||||
|         &mut self.inner |         &mut self.inner | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -12,15 +12,12 @@ use std::marker::PhantomData; | |||||||
|  |  | ||||||
| /// An H2 connection | /// An H2 connection | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Connection<T, P, B: IntoBuf = Bytes> { | pub(crate) struct Connection<T, P, B: IntoBuf = Bytes> { | ||||||
|     // Codec |     // Codec | ||||||
|     codec: Codec<T, B::Buf>, |     codec: Codec<T, Prioritized<B::Buf>>, | ||||||
|  |     ping_pong: PingPong<Prioritized<B::Buf>>, | ||||||
|     // TODO: Remove <B> |  | ||||||
|     ping_pong: PingPong<B::Buf>, |  | ||||||
|     settings: Settings, |     settings: Settings, | ||||||
|     streams: Streams<B::Buf>, |     streams: Streams<B::Buf>, | ||||||
|  |  | ||||||
|     _phantom: PhantomData<P>, |     _phantom: PhantomData<P>, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -29,7 +26,7 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|           P: Peer, |           P: Peer, | ||||||
|           B: IntoBuf, |           B: IntoBuf, | ||||||
| { | { | ||||||
|     pub fn new(codec: Codec<T, B::Buf>) -> Connection<T, P, B> { |     pub fn new(codec: Codec<T, Prioritized<B::Buf>>) -> Connection<T, P, B> { | ||||||
|         // TODO: Actually configure |         // TODO: Actually configure | ||||||
|         let streams = Streams::new::<P>(streams::Config { |         let streams = Streams::new::<P>(streams::Config { | ||||||
|             max_remote_initiated: None, |             max_remote_initiated: None, | ||||||
| @@ -49,10 +46,11 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|  |  | ||||||
|     /// Returns `Ready` when the connection is ready to receive a frame. |     /// Returns `Ready` when the connection is ready to receive a frame. | ||||||
|     pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> { |     pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||||
|         try_ready!(self.poll_send_ready()); |         // The order of these calls don't really matter too much as only one | ||||||
|  |         // should have pending work. | ||||||
|         // TODO: Once there is write buffering, this shouldn't be needed |         try_ready!(self.ping_pong.send_pending_pong(&mut self.codec)); | ||||||
|         try_ready!(self.codec.poll_ready()); |         try_ready!(self.settings.send_pending_ack(&mut self.codec, &mut self.streams)); | ||||||
|  |         try_ready!(self.streams.send_pending_refusal(&mut self.codec)); | ||||||
|  |  | ||||||
|         Ok(().into()) |         Ok(().into()) | ||||||
|     } |     } | ||||||
| @@ -74,7 +72,7 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|  |  | ||||||
|         loop { |         loop { | ||||||
|             // First, ensure that the `Connection` is able to receive a frame |             // First, ensure that the `Connection` is able to receive a frame | ||||||
|             try_ready!(self.poll_recv_ready()); |             try_ready!(self.poll_ready()); | ||||||
|  |  | ||||||
|             trace!("polling codec"); |             trace!("polling codec"); | ||||||
|  |  | ||||||
| @@ -137,38 +135,11 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ===== Private ===== |  | ||||||
|  |  | ||||||
|     /// Returns `Ready` when the `Connection` is ready to receive a frame from |  | ||||||
|     /// the socket. |  | ||||||
|     fn poll_recv_ready(&mut self) -> Poll<(), ConnectionError> { |  | ||||||
|         // The order of these calls don't really matter too much as only one |  | ||||||
|         // should have pending work. |  | ||||||
|         try_ready!(self.ping_pong.send_pending_pong(&mut self.codec)); |  | ||||||
|         try_ready!(self.settings.send_pending_ack(&mut self.codec, &mut self.streams)); |  | ||||||
|         try_ready!(self.streams.send_pending_refusal(&mut self.codec)); |  | ||||||
|  |  | ||||||
|         Ok(().into()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// Returns `Ready` when the `Connection` is ready to accept a frame from |  | ||||||
|     /// the user |  | ||||||
|     /// |  | ||||||
|     /// This function is currently used by poll_complete, but at some point it |  | ||||||
|     /// will probably not be required. |  | ||||||
|     fn poll_send_ready(&mut self) -> Poll<(), ConnectionError> { |  | ||||||
|         // TODO: Is this function needed? |  | ||||||
|         try_ready!(self.poll_recv_ready()); |  | ||||||
|  |  | ||||||
|         Ok(().into()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { |     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||||
|         try_ready!(self.poll_send_ready()); |         try_ready!(self.poll_ready()); | ||||||
|  |  | ||||||
|         // Ensure all window updates have been sent. |         // Ensure all window updates have been sent. | ||||||
|         try_ready!(self.streams.poll_complete(&mut self.codec)); |         try_ready!(self.streams.poll_complete(&mut self.codec)); | ||||||
|         try_ready!(self.codec.poll_complete()); |  | ||||||
|  |  | ||||||
|         Ok(().into()) |         Ok(().into()) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -147,6 +147,10 @@ impl<T> FramedRead<T> { | |||||||
|         Ok(Some(frame)) |         Ok(Some(frame)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn get_ref(&self) -> &T { | ||||||
|  |         self.inner.get_ref() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn get_mut(&mut self) -> &mut T { |     pub fn get_mut(&mut self) -> &mut T { | ||||||
|         self.inner.get_mut() |         self.inner.get_mut() | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| use {hpack, ConnectionError, FrameSize}; | use {hpack, ConnectionError, FrameSize}; | ||||||
|  | use error::User::*; | ||||||
| use frame::{self, Frame}; | use frame::{self, Frame}; | ||||||
|  |  | ||||||
| use futures::*; | use futures::*; | ||||||
| @@ -17,24 +18,23 @@ pub struct FramedWrite<T, B> { | |||||||
|     hpack: hpack::Encoder, |     hpack: hpack::Encoder, | ||||||
|  |  | ||||||
|     /// Write buffer |     /// Write buffer | ||||||
|  |     /// | ||||||
|  |     /// TODO: Should this be a ring buffer? | ||||||
|     buf: Cursor<BytesMut>, |     buf: Cursor<BytesMut>, | ||||||
|  |  | ||||||
|     /// Next frame to encode |     /// Next frame to encode | ||||||
|     next: Option<Next<B>>, |     next: Option<Next<B>>, | ||||||
|  |  | ||||||
|  |     /// Last data frame | ||||||
|  |     last_data_frame: Option<frame::Data<B>>, | ||||||
|  |  | ||||||
|     /// Max frame size, this is specified by the peer |     /// Max frame size, this is specified by the peer | ||||||
|     max_frame_size: FrameSize, |     max_frame_size: FrameSize, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| enum Next<B> { | enum Next<B> { | ||||||
|     Data { |     Data(frame::Data<B>), | ||||||
|         /// Length of the current frame being written |  | ||||||
|         frame_len: usize, |  | ||||||
|  |  | ||||||
|         /// Data frame to encode |  | ||||||
|         data: frame::Data<B>, |  | ||||||
|     }, |  | ||||||
|     Continuation(frame::Continuation), |     Continuation(frame::Continuation), | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -60,6 +60,7 @@ impl<T, B> FramedWrite<T, B> | |||||||
|             hpack: hpack::Encoder::default(), |             hpack: hpack::Encoder::default(), | ||||||
|             buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)), |             buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)), | ||||||
|             next: None, |             next: None, | ||||||
|  |             last_data_frame: None, | ||||||
|             max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, |             max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -82,20 +83,27 @@ impl<T, B> FramedWrite<T, B> | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn is_empty(&self) -> bool { |     fn is_empty(&self) -> bool { | ||||||
|         self.next.is_none() && !self.buf.has_remaining() |         match self.next { | ||||||
|  |             Some(Next::Data(ref frame)) => !frame.payload().has_remaining(), | ||||||
|  |             _ => !self.buf.has_remaining(), | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     fn frame_len(&self, data: &frame::Data<B>) -> usize { |  | ||||||
|         cmp::min(self.max_frame_size as usize, data.payload().remaining()) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T, B> FramedWrite<T, B> { | impl<T, B> FramedWrite<T, B> { | ||||||
|  |     pub fn max_frame_size(&self) -> usize { | ||||||
|  |         self.max_frame_size as usize | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn apply_remote_settings(&mut self, settings: &frame::Settings) { |     pub fn apply_remote_settings(&mut self, settings: &frame::Settings) { | ||||||
|         if let Some(val) = settings.max_frame_size() { |         if let Some(val) = settings.max_frame_size() { | ||||||
|             self.max_frame_size = val; |             self.max_frame_size = val; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn take_last_data_frame(&mut self) -> Option<frame::Data<B>> { | ||||||
|  |         self.last_data_frame.take() | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T, B> Sink for FramedWrite<T, B> | impl<T, B> Sink for FramedWrite<T, B> | ||||||
| @@ -116,24 +124,30 @@ impl<T, B> Sink for FramedWrite<T, B> | |||||||
|  |  | ||||||
|         match item { |         match item { | ||||||
|             Frame::Data(mut v) => { |             Frame::Data(mut v) => { | ||||||
|                 if v.payload().remaining() >= CHAIN_THRESHOLD { |                 // Ensure that the payload is not greater than the max frame. | ||||||
|  |                 let len = v.payload().remaining(); | ||||||
|  |  | ||||||
|  |                 if len > self.max_frame_size() { | ||||||
|  |                     return Err(PayloadTooBig.into()); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if len >= CHAIN_THRESHOLD { | ||||||
|                     let head = v.head(); |                     let head = v.head(); | ||||||
|                     let len = self.frame_len(&v); |  | ||||||
|  |  | ||||||
|                     // Encode the frame head to the buffer |                     // Encode the frame head to the buffer | ||||||
|                     head.encode(len, self.buf.get_mut()); |                     head.encode(len, self.buf.get_mut()); | ||||||
|  |  | ||||||
|                     // Save the data frame |                     // Save the data frame | ||||||
|                     self.next = Some(Next::Data { |                     self.next = Some(Next::Data(v)); | ||||||
|                         frame_len: len, |  | ||||||
|                         data: v, |  | ||||||
|                     }); |  | ||||||
|                 } else { |                 } else { | ||||||
|                     v.encode_chunk(self.buf.get_mut()); |                     v.encode_chunk(self.buf.get_mut()); | ||||||
|  |  | ||||||
|                     // The chunk has been fully encoded, so there is no need to |                     // The chunk has been fully encoded, so there is no need to | ||||||
|                     // keep it around |                     // keep it around | ||||||
|                     assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded"); |                     assert_eq!(v.payload().remaining(), 0, "chunk not fully encoded"); | ||||||
|  |  | ||||||
|  |                     // Save off the last frame... | ||||||
|  |                     self.last_data_frame = Some(v); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             Frame::Headers(v) => { |             Frame::Headers(v) => { | ||||||
| @@ -179,16 +193,27 @@ impl<T, B> Sink for FramedWrite<T, B> | |||||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { |     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||||
|         trace!("poll_complete"); |         trace!("poll_complete"); | ||||||
|  |  | ||||||
|         // TODO: implement |         while !self.is_empty() { | ||||||
|             match self.next { |             match self.next { | ||||||
|             Some(Next::Data { .. }) => unimplemented!(), |                 Some(Next::Data(ref mut frame)) => { | ||||||
|             _ => {} |                     let mut buf = self.buf.by_ref().chain(frame.payload_mut()); | ||||||
|  |                     try_ready!(self.inner.write_buf(&mut buf)); | ||||||
|  |                 } | ||||||
|  |                 _ => { | ||||||
|  |                     try_ready!(self.inner.write_buf(&mut self.buf)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // As long as there is data to write, try to write it! |         // The data frame has been written, so unset it | ||||||
|         while !self.is_empty() { |         match self.next.take() { | ||||||
|             trace!("writing {}", self.buf.remaining()); |             Some(Next::Data(frame)) => { | ||||||
|             try_ready!(self.inner.write_buf(&mut self.buf)); |                 self.last_data_frame = Some(frame); | ||||||
|  |             } | ||||||
|  |             Some(Next::Continuation(frame)) => { | ||||||
|  |                 unimplemented!(); | ||||||
|  |             } | ||||||
|  |             None => {} | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         trace!("flushing buffer"); |         trace!("flushing buffer"); | ||||||
|   | |||||||
| @@ -6,14 +6,15 @@ mod ping_pong; | |||||||
| mod settings; | mod settings; | ||||||
| mod streams; | mod streams; | ||||||
|  |  | ||||||
| pub use self::connection::Connection; | pub(crate) use self::connection::Connection; | ||||||
| pub use self::streams::{Streams, StreamRef, Chunk}; | pub(crate) use self::streams::{Streams, StreamRef, Chunk}; | ||||||
|  |  | ||||||
| use self::codec::Codec; | use self::codec::Codec; | ||||||
| use self::framed_read::FramedRead; | use self::framed_read::FramedRead; | ||||||
| use self::framed_write::FramedWrite; | use self::framed_write::FramedWrite; | ||||||
| use self::ping_pong::PingPong; | use self::ping_pong::PingPong; | ||||||
| use self::settings::Settings; | use self::settings::Settings; | ||||||
|  | use self::streams::Prioritized; | ||||||
|  |  | ||||||
| use {StreamId, ConnectionError}; | use {StreamId, ConnectionError}; | ||||||
| use error::Reason; | use error::Reason; | ||||||
| @@ -63,7 +64,7 @@ pub const MAX_WINDOW_SIZE: WindowSize = ::std::u32::MAX; | |||||||
| /// When the server is performing the handshake, it is able to only send | /// When the server is performing the handshake, it is able to only send | ||||||
| /// `Settings` frames and is expected to receive the client preface as a byte | /// `Settings` frames and is expected to receive the client preface as a byte | ||||||
| /// stream. To represent this, `Settings<FramedWrite<T>>` is returned. | /// stream. To represent this, `Settings<FramedWrite<T>>` is returned. | ||||||
| pub fn framed_write<T, B>(io: T) -> FramedWrite<T, B> | pub(crate) fn framed_write<T, B>(io: T) -> FramedWrite<T, B> | ||||||
|     where T: AsyncRead + AsyncWrite, |     where T: AsyncRead + AsyncWrite, | ||||||
|           B: Buf, |           B: Buf, | ||||||
| { | { | ||||||
| @@ -71,7 +72,7 @@ pub fn framed_write<T, B>(io: T) -> FramedWrite<T, B> | |||||||
| } | } | ||||||
|  |  | ||||||
| /// Create a full H2 transport from the server handshaker | /// Create a full H2 transport from the server handshaker | ||||||
| pub fn from_framed_write<T, P, B>(framed_write: FramedWrite<T, B::Buf>) | pub(crate) fn from_framed_write<T, P, B>(framed_write: FramedWrite<T, Prioritized<B::Buf>>) | ||||||
|     -> Connection<T, P, B> |     -> Connection<T, P, B> | ||||||
|     where T: AsyncRead + AsyncWrite, |     where T: AsyncRead + AsyncWrite, | ||||||
|           P: Peer, |           P: Peer, | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ use {frame, ConnectionError}; | |||||||
| use proto::*; | use proto::*; | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Settings { | pub(crate) struct Settings { | ||||||
|     /// Received SETTINGS frame pending processing. The ACK must be written to |     /// Received SETTINGS frame pending processing. The ACK must be written to | ||||||
|     /// the socket first then the settings applied **before** receiving any |     /// the socket first then the settings applied **before** receiving any | ||||||
|     /// further frames. |     /// further frames. | ||||||
| @@ -26,12 +26,13 @@ impl Settings { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn send_pending_ack<T, B>(&mut self, |     pub fn send_pending_ack<T, B, C>(&mut self, | ||||||
|                                      dst: &mut Codec<T, B>, |                                      dst: &mut Codec<T, B>, | ||||||
|                                   streams: &mut Streams<B>) |                                      streams: &mut Streams<C>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|               B: Buf, |               B: Buf, | ||||||
|  |               C: Buf, | ||||||
|     { |     { | ||||||
|         if let Some(ref settings) = self.pending { |         if let Some(ref settings) = self.pending { | ||||||
|             let frame = frame::Settings::ack(); |             let frame = frame::Settings::ack(); | ||||||
|   | |||||||
| @@ -8,7 +8,8 @@ mod store; | |||||||
| mod stream; | mod stream; | ||||||
| mod streams; | mod streams; | ||||||
|  |  | ||||||
| pub use self::streams::{Streams, StreamRef, Chunk}; | pub(crate) use self::streams::{Streams, StreamRef, Chunk}; | ||||||
|  | pub(crate) use self::prioritize::Prioritized; | ||||||
|  |  | ||||||
| use self::buffer::Buffer; | use self::buffer::Buffer; | ||||||
| use self::flow_control::FlowControl; | use self::flow_control::FlowControl; | ||||||
|   | |||||||
| @@ -22,6 +22,17 @@ pub(super) struct Prioritize<B> { | |||||||
|     conn_task: Option<task::Task>, |     conn_task: Option<task::Task>, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub(crate) struct Prioritized<B> { | ||||||
|  |     // The buffer | ||||||
|  |     inner: B, | ||||||
|  |  | ||||||
|  |     // The stream that this is associated with | ||||||
|  |     stream: store::Key, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Prioritize ===== | ||||||
|  |  | ||||||
| impl<B> Prioritize<B> | impl<B> Prioritize<B> | ||||||
|     where B: Buf, |     where B: Buf, | ||||||
| { | { | ||||||
| @@ -61,40 +72,56 @@ impl<B> Prioritize<B> | |||||||
|     pub fn queue_frame(&mut self, |     pub fn queue_frame(&mut self, | ||||||
|                        frame: Frame<B>, |                        frame: Frame<B>, | ||||||
|                        stream: &mut store::Ptr<B>) |                        stream: &mut store::Ptr<B>) | ||||||
|  |     { | ||||||
|  |         if self.queue_frame2(frame, stream) { | ||||||
|  |             // Notification required | ||||||
|  |             if let Some(ref task) = self.conn_task { | ||||||
|  |                 task.notify(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Queue frame without actually notifying. Returns ture if the queue was | ||||||
|  |     /// succesfful. | ||||||
|  |     fn queue_frame2(&mut self, frame: Frame<B>, stream: &mut store::Ptr<B>) | ||||||
|  |         -> bool | ||||||
|     { |     { | ||||||
|         self.buffered_data += frame.flow_len(); |         self.buffered_data += frame.flow_len(); | ||||||
|  |  | ||||||
|         // queue the frame in the buffer |         // queue the frame in the buffer | ||||||
|         stream.pending_send.push_back(&mut self.buffer, frame); |         stream.pending_send.push_back(&mut self.buffer, frame); | ||||||
|  |  | ||||||
|         if stream.is_pending_send { |  | ||||||
|             debug_assert!(!self.pending_send.is_empty()); |  | ||||||
|  |  | ||||||
|             // Already queued to have frame processed. |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Queue the stream |         // Queue the stream | ||||||
|         push_sender(&mut self.pending_send, stream); |         !push_sender(&mut self.pending_send, stream) | ||||||
|  |  | ||||||
|         if let Some(ref task) = self.conn_task { |  | ||||||
|             task.notify(); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Push the frame to the front of the stream's deque, scheduling the | ||||||
|  |     /// steream if needed. | ||||||
|  |     fn push_back_frame(&mut self, frame: Frame<B>, stream: &mut store::Ptr<B>) { | ||||||
|  |         // Push the frame to the front of the stream's deque | ||||||
|  |         stream.pending_send.push_front(&mut self.buffer, frame); | ||||||
|  |  | ||||||
|  |         // If needed, schedule the sender | ||||||
|  |         push_sender(&mut self.pending_capacity, stream); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn poll_complete<T>(&mut self, |     pub fn poll_complete<T>(&mut self, | ||||||
|                             store: &mut Store<B>, |                             store: &mut Store<B>, | ||||||
|                             dst: &mut Codec<T, B>) |                             dst: &mut Codec<T, Prioritized<B>>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|     { |     { | ||||||
|  |         // Track the task | ||||||
|         self.conn_task = Some(task::current()); |         self.conn_task = Some(task::current()); | ||||||
|  |  | ||||||
|         trace!("poll_complete"); |  | ||||||
|         loop { |  | ||||||
|         // Ensure codec is ready |         // Ensure codec is ready | ||||||
|         try_ready!(dst.poll_ready()); |         try_ready!(dst.poll_ready()); | ||||||
|  |  | ||||||
|  |         // Reclaim any frame that has previously been written | ||||||
|  |         self.reclaim_frame(store, dst); | ||||||
|  |  | ||||||
|  |         trace!("poll_complete"); | ||||||
|  |         loop { | ||||||
|             match self.pop_frame(store) { |             match self.pop_frame(store) { | ||||||
|                 Some(frame) => { |                 Some(frame) => { | ||||||
|                     trace!("writing frame={:?}", frame); |                     trace!("writing frame={:?}", frame); | ||||||
| @@ -106,15 +133,31 @@ impl<B> Prioritize<B> | |||||||
|                     // We already verified that `dst` is ready to accept the |                     // We already verified that `dst` is ready to accept the | ||||||
|                     // write |                     // write | ||||||
|                     assert!(res.is_ready()); |                     assert!(res.is_ready()); | ||||||
|  |  | ||||||
|  |                     // Ensure the codec is ready to try the loop again. | ||||||
|  |                     try_ready!(dst.poll_ready()); | ||||||
|  |  | ||||||
|  |                     // Because, always try to reclaim... | ||||||
|  |                     self.reclaim_frame(store, dst); | ||||||
|  |  | ||||||
|  |                 } | ||||||
|  |                 None => { | ||||||
|  |                     // Try to flush the codec. | ||||||
|  |                     try_ready!(dst.poll_complete()); | ||||||
|  |  | ||||||
|  |                     // This might release a data frame... | ||||||
|  |                     if !self.reclaim_frame(store, dst) { | ||||||
|  |                         return Ok(().into()); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     // No need to poll ready as poll_complete() does this for | ||||||
|  |                     // us... | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|                 None => break, |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         Ok(().into()) |     fn pop_frame(&mut self, store: &mut Store<B>) -> Option<Frame<Prioritized<B>>> { | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn pop_frame(&mut self, store: &mut Store<B>) -> Option<Frame<B>> { |  | ||||||
|         loop { |         loop { | ||||||
|             match self.pop_sender(store) { |             match self.pop_sender(store) { | ||||||
|                 Some(mut stream) => { |                 Some(mut stream) => { | ||||||
| @@ -124,11 +167,7 @@ impl<B> Prioritize<B> | |||||||
|  |  | ||||||
|                             if len > self.flow_control.effective_window_size() as usize { |                             if len > self.flow_control.effective_window_size() as usize { | ||||||
|                                 // TODO: This could be smarter... |                                 // TODO: This could be smarter... | ||||||
|                                 stream.pending_send.push_front(&mut self.buffer, frame.into()); |                                 self.push_back_frame(frame.into(), &mut stream); | ||||||
|  |  | ||||||
|                                 // Push the stream onto the list of streams |  | ||||||
|                                 // waiting for connection capacity |  | ||||||
|                                 push_sender(&mut self.pending_capacity, &mut stream); |  | ||||||
|  |  | ||||||
|                                 // Try again w/ the next stream |                                 // Try again w/ the next stream | ||||||
|                                 continue; |                                 continue; | ||||||
| @@ -143,6 +182,14 @@ impl<B> Prioritize<B> | |||||||
|                         push_sender(&mut self.pending_send, &mut stream); |                         push_sender(&mut self.pending_send, &mut stream); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  |                     // Add prioritization logic | ||||||
|  |                     let frame = frame.map(|buf| { | ||||||
|  |                         Prioritized { | ||||||
|  |                             inner: buf, | ||||||
|  |                             stream: stream.key(), | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |  | ||||||
|                     return Some(frame); |                     return Some(frame); | ||||||
|                 } |                 } | ||||||
|                 None => return None, |                 None => return None, | ||||||
| @@ -174,10 +221,58 @@ impl<B> Prioritize<B> | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fn reclaim_frame<T>(&mut self, | ||||||
|  |                         store: &mut Store<B>, | ||||||
|  |                         dst: &mut Codec<T, Prioritized<B>>) -> bool | ||||||
|  |     { | ||||||
|  |         // First check if there are any data chunks to take back | ||||||
|  |         if let Some(frame) = dst.take_last_data_frame() { | ||||||
|  |             let mut stream = store.resolve(frame.payload().stream); | ||||||
|  |  | ||||||
|  |             let frame = frame.map(|prioritized| { | ||||||
|  |                 // TODO: Ensure fully written | ||||||
|  |                 prioritized.inner | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             self.push_back_frame(frame.into(), &mut stream); | ||||||
|  |  | ||||||
|  |             true | ||||||
|  |         } else { | ||||||
|  |             false | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fn push_sender<B>(list: &mut store::List<B>, stream: &mut store::Ptr<B>) { | /// Push the stream onto the `pending_send` list. Returns true if the sender was | ||||||
|     debug_assert!(!stream.is_pending_send); | /// not already queued. | ||||||
|  | fn push_sender<B>(list: &mut store::List<B>, stream: &mut store::Ptr<B>) | ||||||
|  |     -> bool | ||||||
|  | { | ||||||
|  |     if stream.is_pending_send { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     list.push::<stream::Next>(stream); |     list.push::<stream::Next>(stream); | ||||||
|     stream.is_pending_send = true; |     stream.is_pending_send = true; | ||||||
|  |  | ||||||
|  |     true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Prioritized ===== | ||||||
|  |  | ||||||
|  | impl<B> Buf for Prioritized<B> | ||||||
|  |     where B: Buf, | ||||||
|  | { | ||||||
|  |     fn remaining(&self) -> usize { | ||||||
|  |         self.inner.remaining() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn bytes(&self) -> &[u8] { | ||||||
|  |         self.inner.bytes() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn advance(&mut self, cnt: usize) { | ||||||
|  |         self.inner.advance(cnt) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -353,7 +353,7 @@ impl<B> Recv<B> where B: Buf { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Send any pending refusals. |     /// Send any pending refusals. | ||||||
|     pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, B>) |     pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -146,7 +146,7 @@ impl<B> Send<B> where B: Buf { | |||||||
|  |  | ||||||
|     pub fn poll_complete<T>(&mut self, |     pub fn poll_complete<T>(&mut self, | ||||||
|                             store: &mut Store<B>, |                             store: &mut Store<B>, | ||||||
|                             dst: &mut Codec<T, B>) |                             dst: &mut Codec<T, Prioritized<B>>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|     { |     { | ||||||
| @@ -316,6 +316,8 @@ impl<B> Send<B> where B: Buf { | |||||||
|                         } else { |                         } else { | ||||||
|                             stream.unadvertised_send_window -= dec; |                             stream.unadvertised_send_window -= dec; | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|  |                         unimplemented!(); | ||||||
|                     } |                     } | ||||||
|                 }); |                 }); | ||||||
|             } else if val > old_val { |             } else if val > old_val { | ||||||
|   | |||||||
| @@ -8,19 +8,19 @@ use std::sync::{Arc, Mutex}; | |||||||
| // TODO: All the VecDeques should become linked lists using the State | // TODO: All the VecDeques should become linked lists using the State | ||||||
| // values. | // values. | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Streams<B> { | pub(crate) struct Streams<B> { | ||||||
|     inner: Arc<Mutex<Inner<B>>>, |     inner: Arc<Mutex<Inner<B>>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Reference to the stream state | /// Reference to the stream state | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct StreamRef<B> { | pub(crate) struct StreamRef<B> { | ||||||
|     inner: Arc<Mutex<Inner<B>>>, |     inner: Arc<Mutex<Inner<B>>>, | ||||||
|     key: store::Key, |     key: store::Key, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Chunk<B> | pub(crate) struct Chunk<B> | ||||||
|     where B: Buf, |     where B: Buf, | ||||||
| { | { | ||||||
|     inner: Arc<Mutex<Inner<B>>>, |     inner: Arc<Mutex<Inner<B>>>, | ||||||
| @@ -231,7 +231,7 @@ impl<B> Streams<B> | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, B>) |     pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|     { |     { | ||||||
| @@ -240,7 +240,7 @@ impl<B> Streams<B> | |||||||
|         me.actions.recv.send_pending_refusal(dst) |         me.actions.recv.send_pending_refusal(dst) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn poll_complete<T>(&mut self, dst: &mut Codec<T, B>) |     pub fn poll_complete<T>(&mut self, dst: &mut Codec<T, Prioritized<B>>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|     { |     { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user