New send flow control (#25)
Restructure send flow control such that sending data is always accepted by `Stream`. Data frames will be buffered until there is available window to send them. Producers can monitor the available window capacity to decide if data should be produced.
This commit is contained in:
		| @@ -8,11 +8,28 @@ pub(super) struct Stream<B> { | ||||
|     /// Current state of the stream | ||||
|     pub state: State, | ||||
|  | ||||
|     /// Frames pending for this stream to read | ||||
|     pub pending_recv: buffer::Deque<Bytes>, | ||||
|     /// Next node in the `Stream` linked list. | ||||
|     /// | ||||
|     /// This field is used in different linked lists depending on the stream | ||||
|     /// state. First, it is used as part of the linked list of streams waiting | ||||
|     /// to be accepted (either by a server or by a client as a push promise). | ||||
|     /// Once the stream is accepted, this is used for the linked list of streams | ||||
|     /// waiting to flush prioritized frames to the socket. | ||||
|     pub next: Option<store::Key>, | ||||
|  | ||||
|     /// Task tracking receiving frames | ||||
|     pub recv_task: Option<task::Task>, | ||||
|     /// Set to true when the stream is queued | ||||
|     pub is_queued: bool, | ||||
|  | ||||
|     // ===== Fields related to sending ===== | ||||
|  | ||||
|     /// Send data flow control | ||||
|     pub send_flow: FlowControl, | ||||
|  | ||||
|     /// Amount of send capacity that has been requested, but not yet allocated. | ||||
|     pub requested_send_capacity: WindowSize, | ||||
|  | ||||
|     /// Amount of data buffered at the prioritization layer. | ||||
|     pub buffered_send_data: WindowSize, | ||||
|  | ||||
|     /// Task tracking additional send capacity (i.e. window updates). | ||||
|     pub send_task: Option<task::Task>, | ||||
| @@ -20,63 +37,75 @@ pub(super) struct Stream<B> { | ||||
|     /// Frames pending for this stream being sent to the socket | ||||
|     pub pending_send: buffer::Deque<B>, | ||||
|  | ||||
|     /// Next node in the `Stream` linked list. | ||||
|     /// | ||||
|     /// This field is used in different linked lists depending on the stream | ||||
|     /// state. | ||||
|     pub next: Option<store::Key>, | ||||
|  | ||||
|     /// Next node in the linked list of streams waiting for additional | ||||
|     /// connection level capacity. | ||||
|     pub next_capacity: Option<store::Key>, | ||||
|     pub next_pending_send_capacity: Option<store::Key>, | ||||
|  | ||||
|     /// True if the stream is waiting for outbound connection capacity | ||||
|     pub is_pending_send_capacity: bool, | ||||
|  | ||||
|     /// Set to true when the send capacity has been incremented | ||||
|     pub send_capacity_inc: bool, | ||||
|  | ||||
|     // ===== Fields related to receiving ===== | ||||
|  | ||||
|     /// Receive data flow control | ||||
|     pub recv_flow: FlowControl, | ||||
|  | ||||
|     /// Frames pending for this stream to read | ||||
|     pub pending_recv: buffer::Deque<Bytes>, | ||||
|  | ||||
|     /// Task tracking receiving frames | ||||
|     pub recv_task: Option<task::Task>, | ||||
|  | ||||
|     /// The stream's pending push promises | ||||
|     pub pending_push_promises: store::List<B>, | ||||
|  | ||||
|     /// True if the stream is currently pending send | ||||
|     pub is_pending_send: bool, | ||||
|  | ||||
|     /// A stream's capacity is never advertised past the connection's capacity. | ||||
|     /// This value represents the amount of the stream window that has been | ||||
|     /// temporarily withheld. | ||||
|     pub unadvertised_send_window: WindowSize, | ||||
|     pub pending_push_promises: store::Queue<B, Next>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub(super) struct Next; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub(super) struct NextCapacity; | ||||
| pub(super) struct NextSendCapacity; | ||||
|  | ||||
| impl<B> Stream<B> { | ||||
|     pub fn new(id: StreamId) -> Stream<B> { | ||||
|     pub fn new(id: StreamId) -> Stream<B> | ||||
|     { | ||||
|         Stream { | ||||
|             id, | ||||
|             state: State::default(), | ||||
|             pending_recv: buffer::Deque::new(), | ||||
|             recv_task: None, | ||||
|             next: None, | ||||
|             is_queued: false, | ||||
|  | ||||
|             // ===== Fields related to sending ===== | ||||
|  | ||||
|             send_flow: FlowControl::new(), | ||||
|             requested_send_capacity: 0, | ||||
|             buffered_send_data: 0, | ||||
|             send_task: None, | ||||
|             pending_send: buffer::Deque::new(), | ||||
|             next: None, | ||||
|             next_capacity: None, | ||||
|             is_pending_send_capacity: false, | ||||
|             pending_push_promises: store::List::new(), | ||||
|             is_pending_send: false, | ||||
|             unadvertised_send_window: 0, | ||||
|             next_pending_send_capacity: None, | ||||
|             send_capacity_inc: false, | ||||
|  | ||||
|             // ===== Fields related to receiving ===== | ||||
|  | ||||
|             recv_flow: FlowControl::new(), | ||||
|             pending_recv: buffer::Deque::new(), | ||||
|             recv_task: None, | ||||
|             pending_push_promises: store::Queue::new(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // TODO: remove? | ||||
|     pub fn send_flow_control(&mut self) -> Option<&mut FlowControl> { | ||||
|         self.state.send_flow_control() | ||||
|     } | ||||
|     pub fn assign_capacity(&mut self, capacity: WindowSize) { | ||||
|         debug_assert!(capacity > 0); | ||||
|         self.send_capacity_inc = true; | ||||
|         self.send_flow.assign_capacity(capacity); | ||||
|  | ||||
|     // TODO: remove? | ||||
|     pub fn recv_flow_control(&mut self) -> Option<&mut FlowControl> { | ||||
|         self.state.recv_flow_control() | ||||
|         // Only notify if the capacity exceeds the amount of buffered data | ||||
|         if self.send_flow.available() > self.buffered_send_data { | ||||
|             self.notify_send(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn notify_send(&mut self) { | ||||
| @@ -104,18 +133,34 @@ impl store::Next for Next { | ||||
|     fn take_next<B>(stream: &mut Stream<B>) -> Option<store::Key> { | ||||
|         stream.next.take() | ||||
|     } | ||||
|  | ||||
|     fn is_queued<B>(stream: &Stream<B>) -> bool { | ||||
|         stream.is_queued | ||||
|     } | ||||
|  | ||||
|     fn set_queued<B>(stream: &mut Stream<B>, val: bool) { | ||||
|         stream.is_queued = val; | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl store::Next for NextCapacity { | ||||
| impl store::Next for NextSendCapacity { | ||||
|     fn next<B>(stream: &Stream<B>) -> Option<store::Key> { | ||||
|         stream.next_capacity | ||||
|         stream.next_pending_send_capacity | ||||
|     } | ||||
|  | ||||
|     fn set_next<B>(stream: &mut Stream<B>, key: Option<store::Key>) { | ||||
|         stream.next_capacity = key; | ||||
|         stream.next_pending_send_capacity = key; | ||||
|     } | ||||
|  | ||||
|     fn take_next<B>(stream: &mut Stream<B>) -> Option<store::Key> { | ||||
|         stream.next_capacity.take() | ||||
|         stream.next_pending_send_capacity.take() | ||||
|     } | ||||
|  | ||||
|     fn is_queued<B>(stream: &Stream<B>) -> bool { | ||||
|         stream.is_pending_send_capacity | ||||
|     } | ||||
|  | ||||
|     fn set_queued<B>(stream: &mut Stream<B>, val: bool) { | ||||
|         stream.is_pending_send_capacity = val; | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user