Start working on prioritization
This commit is contained in:
@@ -296,8 +296,8 @@ impl Headers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Headers> for Frame {
|
impl<T> From<Headers> for Frame<T> {
|
||||||
fn from(src: Headers) -> Frame {
|
fn from(src: Headers) -> Self {
|
||||||
Frame::Headers(src)
|
Frame::Headers(src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
mod buffer;
|
mod buffer;
|
||||||
mod flow_control;
|
mod flow_control;
|
||||||
|
mod prioritize;
|
||||||
mod recv;
|
mod recv;
|
||||||
mod send;
|
mod send;
|
||||||
mod state;
|
mod state;
|
||||||
@@ -11,6 +12,7 @@ pub use self::streams::{Streams, StreamRef};
|
|||||||
|
|
||||||
use self::buffer::Buffer;
|
use self::buffer::Buffer;
|
||||||
use self::flow_control::FlowControl;
|
use self::flow_control::FlowControl;
|
||||||
|
use self::prioritize::Prioritize;
|
||||||
use self::recv::Recv;
|
use self::recv::Recv;
|
||||||
use self::send::Send;
|
use self::send::Send;
|
||||||
use self::state::State;
|
use self::state::State;
|
||||||
|
|||||||
61
src/proto/streams/prioritize.rs
Normal file
61
src/proto/streams/prioritize.rs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct Prioritize<B> {
|
||||||
|
pending_send: Option<Indices>,
|
||||||
|
|
||||||
|
/// Holds frames that are waiting to be written to the socket
|
||||||
|
buffer: Buffer<B>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Indices {
|
||||||
|
head: store::Key,
|
||||||
|
tail: store::Key,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> Prioritize<B> {
|
||||||
|
pub fn new() -> Prioritize<B> {
|
||||||
|
Prioritize {
|
||||||
|
pending_send: None,
|
||||||
|
buffer: Buffer::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queue_frame(&mut self,
|
||||||
|
frame: Frame<B>,
|
||||||
|
stream: &mut store::Ptr<B>)
|
||||||
|
{
|
||||||
|
// 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_some());
|
||||||
|
|
||||||
|
// Already queued to have frame processed.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The next pointer shouldn't be set
|
||||||
|
debug_assert!(stream.next_pending_send.is_none());
|
||||||
|
|
||||||
|
// Queue the stream
|
||||||
|
match self.pending_send {
|
||||||
|
Some(ref mut idxs) => {
|
||||||
|
// Update the current tail node to point to `stream`
|
||||||
|
stream.resolve(idxs.tail).next_pending_send = Some(stream.key());
|
||||||
|
|
||||||
|
// Update the tail pointer
|
||||||
|
idxs.tail = stream.key();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
self.pending_send = Some(Indices {
|
||||||
|
head: stream.key(),
|
||||||
|
tail: stream.key(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.is_pending_send = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -208,7 +208,7 @@ impl<P, B> Recv<P, B>
|
|||||||
where T: AsyncWrite,
|
where T: AsyncWrite,
|
||||||
{
|
{
|
||||||
while let Some(id) = self.pending_window_updates.pop_front() {
|
while let Some(id) = self.pending_window_updates.pop_front() {
|
||||||
let flow = streams.get_mut(&id)
|
let flow = streams.find_mut(&id)
|
||||||
.and_then(|stream| stream.recv_flow_control());
|
.and_then(|stream| stream.recv_flow_control());
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ pub(super) struct Send<P, B> {
|
|||||||
// XXX It would be cool if this didn't exist.
|
// XXX It would be cool if this didn't exist.
|
||||||
pending_window_updates: VecDeque<StreamId>,
|
pending_window_updates: VecDeque<StreamId>,
|
||||||
|
|
||||||
/// Holds frames that are waiting to be written to the socket
|
prioritize: Prioritize<B>,
|
||||||
buffer: Buffer<B>,
|
|
||||||
|
|
||||||
/// When `poll_window_update` is not ready, then the calling task is saved to
|
/// When `poll_window_update` is not ready, then the calling task is saved to
|
||||||
/// be notified later. Access to poll_window_update must not be shared across tasks,
|
/// be notified later. Access to poll_window_update must not be shared across tasks,
|
||||||
@@ -58,8 +57,8 @@ impl<P, B> Send<P, B>
|
|||||||
next_stream_id: next_stream_id.into(),
|
next_stream_id: next_stream_id.into(),
|
||||||
init_window_sz: config.init_local_window_sz,
|
init_window_sz: config.init_local_window_sz,
|
||||||
flow_control: FlowControl::new(config.init_local_window_sz),
|
flow_control: FlowControl::new(config.init_local_window_sz),
|
||||||
|
prioritize: Prioritize::new(),
|
||||||
pending_window_updates: VecDeque::new(),
|
pending_window_updates: VecDeque::new(),
|
||||||
buffer: Buffer::new(),
|
|
||||||
blocked: None,
|
blocked: None,
|
||||||
_p: PhantomData,
|
_p: PhantomData,
|
||||||
}
|
}
|
||||||
@@ -86,12 +85,17 @@ impl<P, B> Send<P, B>
|
|||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_headers(&mut self, stream: &mut Stream<B>, frame: frame::Headers)
|
pub fn send_headers(&mut self,
|
||||||
|
frame: frame::Headers,
|
||||||
|
stream: &mut store::Ptr<B>)
|
||||||
-> Result<(), ConnectionError>
|
-> Result<(), ConnectionError>
|
||||||
{
|
{
|
||||||
// Update the state
|
// Update the state
|
||||||
stream.state.send_open(self.init_window_sz, frame.is_end_stream())?;
|
stream.state.send_open(self.init_window_sz, frame.is_end_stream())?;
|
||||||
// stream.send_buf.headers = Some(frame);
|
|
||||||
|
// Queue the frame for sending
|
||||||
|
self.prioritize.queue_frame(frame.into(), stream);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +165,7 @@ impl<P, B> Send<P, B>
|
|||||||
// TODO this should probably account for stream priority?
|
// TODO this should probably account for stream priority?
|
||||||
let update = self.pending_window_updates.pop_front()
|
let update = self.pending_window_updates.pop_front()
|
||||||
.and_then(|id| {
|
.and_then(|id| {
|
||||||
streams.get_mut(&id)
|
streams.find_mut(&id)
|
||||||
.and_then(|stream| stream.send_flow_control())
|
.and_then(|stream| stream.send_flow_control())
|
||||||
.and_then(|flow| flow.apply_window_update())
|
.and_then(|flow| flow.apply_window_update())
|
||||||
.map(|incr| WindowUpdate::new(id, incr))
|
.map(|incr| WindowUpdate::new(id, incr))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use super::*;
|
|||||||
|
|
||||||
use slab;
|
use slab;
|
||||||
|
|
||||||
|
use std::ops;
|
||||||
use std::collections::{HashMap, hash_map};
|
use std::collections::{HashMap, hash_map};
|
||||||
|
|
||||||
/// Storage for streams
|
/// Storage for streams
|
||||||
@@ -11,6 +12,16 @@ pub(super) struct Store<B> {
|
|||||||
ids: HashMap<StreamId, usize>,
|
ids: HashMap<StreamId, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// "Pointer" to an entry in the store
|
||||||
|
pub(super) struct Ptr<'a, B: 'a> {
|
||||||
|
key: Key,
|
||||||
|
store: &'a mut Store<B>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// References an entry in the store.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(super) struct Key(usize);
|
||||||
|
|
||||||
pub(super) enum Entry<'a, B: 'a> {
|
pub(super) enum Entry<'a, B: 'a> {
|
||||||
Occupied(OccupiedEntry<'a, B>),
|
Occupied(OccupiedEntry<'a, B>),
|
||||||
Vacant(VacantEntry<'a, B>),
|
Vacant(VacantEntry<'a, B>),
|
||||||
@@ -26,6 +37,8 @@ pub(super) struct VacantEntry<'a, B: 'a> {
|
|||||||
slab: &'a mut slab::Slab<Stream<B>>,
|
slab: &'a mut slab::Slab<Stream<B>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== impl Store =====
|
||||||
|
|
||||||
impl<B> Store<B> {
|
impl<B> Store<B> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Store {
|
Store {
|
||||||
@@ -34,7 +47,7 @@ impl<B> Store<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(&mut self, id: &StreamId) -> Option<&mut Stream<B>> {
|
pub fn find_mut(&mut self, id: &StreamId) -> Option<&mut Stream<B>> {
|
||||||
if let Some(handle) = self.ids.get(id) {
|
if let Some(handle) = self.ids.get(id) {
|
||||||
Some(&mut self.slab[*handle])
|
Some(&mut self.slab[*handle])
|
||||||
} else {
|
} else {
|
||||||
@@ -42,12 +55,17 @@ impl<B> Store<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, id: StreamId, val: Stream<B>) {
|
pub fn insert(&mut self, id: StreamId, val: Stream<B>) -> Ptr<B> {
|
||||||
let handle = self.slab.insert(val);
|
let key = self.slab.insert(val);
|
||||||
assert!(self.ids.insert(id, handle).is_none());
|
assert!(self.ids.insert(id, key).is_none());
|
||||||
|
|
||||||
|
Ptr {
|
||||||
|
key: Key(key),
|
||||||
|
store: self,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entry(&mut self, id: StreamId) -> Entry<B> {
|
pub fn find_entry(&mut self, id: StreamId) -> Entry<B> {
|
||||||
use self::hash_map::Entry::*;
|
use self::hash_map::Entry::*;
|
||||||
|
|
||||||
match self.ids.entry(id) {
|
match self.ids.entry(id) {
|
||||||
@@ -67,12 +85,53 @@ impl<B> Store<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== impl Ptr =====
|
||||||
|
|
||||||
|
impl<'a, B: 'a> Ptr<'a, B> {
|
||||||
|
pub fn key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve(&mut self, key: Key) -> Ptr<B> {
|
||||||
|
Ptr {
|
||||||
|
key: key,
|
||||||
|
store: self.store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, B: 'a> ops::Deref for Ptr<'a, B> {
|
||||||
|
type Target = Stream<B>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Stream<B> {
|
||||||
|
&self.store.slab[self.key.0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, B: 'a> ops::DerefMut for Ptr<'a, B> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Stream<B> {
|
||||||
|
&mut self.store.slab[self.key.0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== impl OccupiedEntry =====
|
||||||
|
|
||||||
impl<'a, B> OccupiedEntry<'a, B> {
|
impl<'a, B> OccupiedEntry<'a, B> {
|
||||||
|
pub fn get(&self) -> &Stream<B> {
|
||||||
|
&self.slab[*self.ids.get()]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self) -> &mut Stream<B> {
|
||||||
|
&mut self.slab[*self.ids.get()]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn into_mut(self) -> &'a mut Stream<B> {
|
pub fn into_mut(self) -> &'a mut Stream<B> {
|
||||||
&mut self.slab[*self.ids.get()]
|
&mut self.slab[*self.ids.get()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== impl VacantEntry =====
|
||||||
|
//
|
||||||
impl<'a, B> VacantEntry<'a, B> {
|
impl<'a, B> VacantEntry<'a, B> {
|
||||||
pub fn insert(self, value: Stream<B>) -> &'a mut Stream<B> {
|
pub fn insert(self, value: Stream<B>) -> &'a mut Stream<B> {
|
||||||
// Insert the value in the slab
|
// Insert the value in the slab
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ pub(super) struct Stream<B> {
|
|||||||
|
|
||||||
/// Frames pending for this stream being sent to the socket
|
/// Frames pending for this stream being sent to the socket
|
||||||
pub pending_send: buffer::Deque<B>,
|
pub pending_send: buffer::Deque<B>,
|
||||||
|
|
||||||
|
/// Next stream pending send
|
||||||
|
pub next_pending_send: Option<store::Key>,
|
||||||
|
|
||||||
|
/// True if the stream is currently pending send
|
||||||
|
pub is_pending_send: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Stream<B> {
|
impl<B> Stream<B> {
|
||||||
@@ -14,6 +20,8 @@ impl<B> Stream<B> {
|
|||||||
Stream {
|
Stream {
|
||||||
state: State::default(),
|
state: State::default(),
|
||||||
pending_send: buffer::Deque::new(),
|
pending_send: buffer::Deque::new(),
|
||||||
|
next_pending_send: None,
|
||||||
|
is_pending_send: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ impl<P, B> Streams<P, B>
|
|||||||
let mut me = self.inner.lock().unwrap();
|
let mut me = self.inner.lock().unwrap();
|
||||||
let me = &mut *me;
|
let me = &mut *me;
|
||||||
|
|
||||||
let stream = match me.store.entry(id) {
|
let stream = match me.store.find_entry(id) {
|
||||||
Entry::Occupied(e) => e.into_mut(),
|
Entry::Occupied(e) => e.into_mut(),
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
// Trailers cannot open a stream. Trailers are header frames
|
// Trailers cannot open a stream. Trailers are header frames
|
||||||
@@ -103,7 +103,7 @@ impl<P, B> Streams<P, B>
|
|||||||
let mut me = self.inner.lock().unwrap();
|
let mut me = self.inner.lock().unwrap();
|
||||||
let me = &mut *me;
|
let me = &mut *me;
|
||||||
|
|
||||||
let stream = match me.store.get_mut(&id) {
|
let stream = match me.store.find_mut(&id) {
|
||||||
Some(stream) => stream,
|
Some(stream) => stream,
|
||||||
None => return Err(ProtocolError.into()),
|
None => return Err(ProtocolError.into()),
|
||||||
};
|
};
|
||||||
@@ -136,7 +136,7 @@ impl<P, B> Streams<P, B>
|
|||||||
} else {
|
} else {
|
||||||
// The remote may send window updates for streams that the local now
|
// The remote may send window updates for streams that the local now
|
||||||
// considers closed. It's ok...
|
// considers closed. It's ok...
|
||||||
if let Some(state) = me.store.get_mut(&id) {
|
if let Some(state) = me.store.find_mut(&id) {
|
||||||
try!(me.actions.send.recv_stream_window_update(frame, state));
|
try!(me.actions.send.recv_stream_window_update(frame, state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,7 +191,7 @@ impl<P, B> Streams<P, B>
|
|||||||
let mut me = self.inner.lock().unwrap();
|
let mut me = self.inner.lock().unwrap();
|
||||||
let me = &mut *me;
|
let me = &mut *me;
|
||||||
|
|
||||||
let stream = match me.store.get_mut(&id) {
|
let stream = match me.store.find_mut(&id) {
|
||||||
Some(stream) => stream,
|
Some(stream) => stream,
|
||||||
None => return Err(UnexpectedFrameType.into()),
|
None => return Err(UnexpectedFrameType.into()),
|
||||||
};
|
};
|
||||||
@@ -224,7 +224,7 @@ impl<P, B> Streams<P, B>
|
|||||||
if id.is_zero() {
|
if id.is_zero() {
|
||||||
try!(me.actions.recv.expand_connection_window(sz));
|
try!(me.actions.recv.expand_connection_window(sz));
|
||||||
} else {
|
} else {
|
||||||
if let Some(state) = me.store.get_mut(&id) {
|
if let Some(state) = me.store.find_mut(&id) {
|
||||||
try!(me.actions.recv.expand_stream_window(id, sz, state));
|
try!(me.actions.recv.expand_stream_window(id, sz, state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,15 +271,14 @@ impl<B> Streams<client::Peer, B>
|
|||||||
let headers = client::Peer::convert_send_message(
|
let headers = client::Peer::convert_send_message(
|
||||||
id, request, end_of_stream);
|
id, request, end_of_stream);
|
||||||
|
|
||||||
me.actions.send.send_headers(&mut stream, headers)?;
|
let mut stream = me.store.insert(id, stream);
|
||||||
|
|
||||||
|
me.actions.send.send_headers(headers, &mut stream)?;
|
||||||
|
|
||||||
// Given that the stream has been initialized, it should not be in the
|
// Given that the stream has been initialized, it should not be in the
|
||||||
// closed state.
|
// closed state.
|
||||||
debug_assert!(!stream.state.is_closed());
|
debug_assert!(!stream.state.is_closed());
|
||||||
|
|
||||||
// Store the state
|
|
||||||
me.store.insert(id, stream);
|
|
||||||
|
|
||||||
id
|
id
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user