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:
Carl Lerche
2017-08-21 13:52:58 -07:00
committed by GitHub
parent 41b25a4a56
commit a623ab68b5
13 changed files with 715 additions and 736 deletions

View File

@@ -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;
}
}