Progress towards allowing large writes
This commit is contained in:
@@ -8,7 +8,8 @@ mod store;
|
||||
mod stream;
|
||||
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::flow_control::FlowControl;
|
||||
|
||||
@@ -22,6 +22,17 @@ pub(super) struct Prioritize<B> {
|
||||
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>
|
||||
where B: Buf,
|
||||
{
|
||||
@@ -61,40 +72,56 @@ impl<B> Prioritize<B>
|
||||
pub fn queue_frame(&mut self,
|
||||
frame: Frame<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();
|
||||
|
||||
// queue the frame in the buffer
|
||||
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
|
||||
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,
|
||||
store: &mut Store<B>,
|
||||
dst: &mut Codec<T, B>)
|
||||
dst: &mut Codec<T, Prioritized<B>>)
|
||||
-> Poll<(), ConnectionError>
|
||||
where T: AsyncWrite,
|
||||
{
|
||||
// Track the task
|
||||
self.conn_task = Some(task::current());
|
||||
|
||||
// Ensure codec is ready
|
||||
try_ready!(dst.poll_ready());
|
||||
|
||||
// Reclaim any frame that has previously been written
|
||||
self.reclaim_frame(store, dst);
|
||||
|
||||
trace!("poll_complete");
|
||||
loop {
|
||||
// Ensure codec is ready
|
||||
try_ready!(dst.poll_ready());
|
||||
|
||||
match self.pop_frame(store) {
|
||||
Some(frame) => {
|
||||
trace!("writing frame={:?}", frame);
|
||||
@@ -106,15 +133,31 @@ impl<B> Prioritize<B>
|
||||
// We already verified that `dst` is ready to accept the
|
||||
// write
|
||||
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<B>> {
|
||||
fn pop_frame(&mut self, store: &mut Store<B>) -> Option<Frame<Prioritized<B>>> {
|
||||
loop {
|
||||
match self.pop_sender(store) {
|
||||
Some(mut stream) => {
|
||||
@@ -124,11 +167,7 @@ impl<B> Prioritize<B>
|
||||
|
||||
if len > self.flow_control.effective_window_size() as usize {
|
||||
// TODO: This could be smarter...
|
||||
stream.pending_send.push_front(&mut self.buffer, frame.into());
|
||||
|
||||
// Push the stream onto the list of streams
|
||||
// waiting for connection capacity
|
||||
push_sender(&mut self.pending_capacity, &mut stream);
|
||||
self.push_back_frame(frame.into(), &mut stream);
|
||||
|
||||
// Try again w/ the next stream
|
||||
continue;
|
||||
@@ -143,6 +182,14 @@ impl<B> Prioritize<B>
|
||||
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);
|
||||
}
|
||||
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>) {
|
||||
debug_assert!(!stream.is_pending_send);
|
||||
/// Push the stream onto the `pending_send` list. Returns true if the sender was
|
||||
/// 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);
|
||||
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.
|
||||
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>
|
||||
where T: AsyncWrite,
|
||||
{
|
||||
|
||||
@@ -146,7 +146,7 @@ impl<B> Send<B> where B: Buf {
|
||||
|
||||
pub fn poll_complete<T>(&mut self,
|
||||
store: &mut Store<B>,
|
||||
dst: &mut Codec<T, B>)
|
||||
dst: &mut Codec<T, Prioritized<B>>)
|
||||
-> Poll<(), ConnectionError>
|
||||
where T: AsyncWrite,
|
||||
{
|
||||
@@ -316,6 +316,8 @@ impl<B> Send<B> where B: Buf {
|
||||
} else {
|
||||
stream.unadvertised_send_window -= dec;
|
||||
}
|
||||
|
||||
unimplemented!();
|
||||
}
|
||||
});
|
||||
} 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
|
||||
// values.
|
||||
#[derive(Debug)]
|
||||
pub struct Streams<B> {
|
||||
pub(crate) struct Streams<B> {
|
||||
inner: Arc<Mutex<Inner<B>>>,
|
||||
}
|
||||
|
||||
/// Reference to the stream state
|
||||
#[derive(Debug)]
|
||||
pub struct StreamRef<B> {
|
||||
pub(crate) struct StreamRef<B> {
|
||||
inner: Arc<Mutex<Inner<B>>>,
|
||||
key: store::Key,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Chunk<B>
|
||||
pub(crate) struct Chunk<B>
|
||||
where B: Buf,
|
||||
{
|
||||
inner: Arc<Mutex<Inner<B>>>,
|
||||
@@ -231,7 +231,7 @@ impl<B> Streams<B>
|
||||
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>
|
||||
where T: AsyncWrite,
|
||||
{
|
||||
@@ -240,7 +240,7 @@ impl<B> Streams<B>
|
||||
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>
|
||||
where T: AsyncWrite,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user