Start working on prioritization
This commit is contained in:
		| @@ -296,8 +296,8 @@ impl Headers { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<Headers> for Frame { | ||||
|     fn from(src: Headers) -> Frame { | ||||
| impl<T> From<Headers> for Frame<T> { | ||||
|     fn from(src: Headers) -> Self { | ||||
|         Frame::Headers(src) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| mod buffer; | ||||
| mod flow_control; | ||||
| mod prioritize; | ||||
| mod recv; | ||||
| mod send; | ||||
| mod state; | ||||
| @@ -11,6 +12,7 @@ pub use self::streams::{Streams, StreamRef}; | ||||
|  | ||||
| use self::buffer::Buffer; | ||||
| use self::flow_control::FlowControl; | ||||
| use self::prioritize::Prioritize; | ||||
| use self::recv::Recv; | ||||
| use self::send::Send; | ||||
| 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, | ||||
|     { | ||||
|         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()); | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -30,8 +30,7 @@ pub(super) struct Send<P, B> { | ||||
|     // XXX It would be cool if this didn't exist. | ||||
|     pending_window_updates: VecDeque<StreamId>, | ||||
|  | ||||
|     /// Holds frames that are waiting to be written to the socket | ||||
|     buffer: Buffer<B>, | ||||
|     prioritize: Prioritize<B>, | ||||
|  | ||||
|     /// 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, | ||||
| @@ -58,8 +57,8 @@ impl<P, B> Send<P, B> | ||||
|             next_stream_id: next_stream_id.into(), | ||||
|             init_window_sz: config.init_local_window_sz, | ||||
|             flow_control: FlowControl::new(config.init_local_window_sz), | ||||
|             prioritize: Prioritize::new(), | ||||
|             pending_window_updates: VecDeque::new(), | ||||
|             buffer: Buffer::new(), | ||||
|             blocked: None, | ||||
|             _p: PhantomData, | ||||
|         } | ||||
| @@ -86,12 +85,17 @@ impl<P, B> Send<P, B> | ||||
|         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> | ||||
|     { | ||||
|         // Update the state | ||||
|         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(()) | ||||
|     } | ||||
|  | ||||
| @@ -161,7 +165,7 @@ impl<P, B> Send<P, B> | ||||
|         // TODO this should probably account for stream priority? | ||||
|         let update = self.pending_window_updates.pop_front() | ||||
|             .and_then(|id| { | ||||
|                 streams.get_mut(&id) | ||||
|                 streams.find_mut(&id) | ||||
|                     .and_then(|stream| stream.send_flow_control()) | ||||
|                     .and_then(|flow| flow.apply_window_update()) | ||||
|                     .map(|incr| WindowUpdate::new(id, incr)) | ||||
|   | ||||
| @@ -2,6 +2,7 @@ use super::*; | ||||
|  | ||||
| use slab; | ||||
|  | ||||
| use std::ops; | ||||
| use std::collections::{HashMap, hash_map}; | ||||
|  | ||||
| /// Storage for streams | ||||
| @@ -11,6 +12,16 @@ pub(super) struct Store<B> { | ||||
|     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> { | ||||
|     Occupied(OccupiedEntry<'a, B>), | ||||
|     Vacant(VacantEntry<'a, B>), | ||||
| @@ -26,6 +37,8 @@ pub(super) struct VacantEntry<'a, B: 'a> { | ||||
|     slab: &'a mut slab::Slab<Stream<B>>, | ||||
| } | ||||
|  | ||||
| // ===== impl Store ===== | ||||
|  | ||||
| impl<B> Store<B> { | ||||
|     pub fn new() -> Self { | ||||
|         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) { | ||||
|             Some(&mut self.slab[*handle]) | ||||
|         } else { | ||||
| @@ -42,12 +55,17 @@ impl<B> Store<B> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn insert(&mut self, id: StreamId, val: Stream<B>) { | ||||
|         let handle = self.slab.insert(val); | ||||
|         assert!(self.ids.insert(id, handle).is_none()); | ||||
|     pub fn insert(&mut self, id: StreamId, val: Stream<B>) -> Ptr<B> { | ||||
|         let key = self.slab.insert(val); | ||||
|         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::*; | ||||
|  | ||||
|         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> { | ||||
|     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> { | ||||
|         &mut self.slab[*self.ids.get()] | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ===== impl VacantEntry ===== | ||||
| // | ||||
| impl<'a, B> VacantEntry<'a, B> { | ||||
|     pub fn insert(self, value: Stream<B>) -> &'a mut Stream<B> { | ||||
|         // 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 | ||||
|     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> { | ||||
| @@ -14,6 +20,8 @@ impl<B> Stream<B> { | ||||
|         Stream { | ||||
|             state: State::default(), | ||||
|             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 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::Vacant(e) => { | ||||
|                 // 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 me = &mut *me; | ||||
|  | ||||
|         let stream = match me.store.get_mut(&id) { | ||||
|         let stream = match me.store.find_mut(&id) { | ||||
|             Some(stream) => stream, | ||||
|             None => return Err(ProtocolError.into()), | ||||
|         }; | ||||
| @@ -136,7 +136,7 @@ impl<P, B> Streams<P, B> | ||||
|         } else { | ||||
|             // The remote may send window updates for streams that the local now | ||||
|             // 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)); | ||||
|             } | ||||
|         } | ||||
| @@ -191,7 +191,7 @@ impl<P, B> Streams<P, B> | ||||
|         let mut me = self.inner.lock().unwrap(); | ||||
|         let me = &mut *me; | ||||
|  | ||||
|         let stream = match me.store.get_mut(&id) { | ||||
|         let stream = match me.store.find_mut(&id) { | ||||
|             Some(stream) => stream, | ||||
|             None => return Err(UnexpectedFrameType.into()), | ||||
|         }; | ||||
| @@ -224,7 +224,7 @@ impl<P, B> Streams<P, B> | ||||
|         if id.is_zero() { | ||||
|             try!(me.actions.recv.expand_connection_window(sz)); | ||||
|         } 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)); | ||||
|             } | ||||
|         } | ||||
| @@ -271,15 +271,14 @@ impl<B> Streams<client::Peer, B> | ||||
|             let headers = client::Peer::convert_send_message( | ||||
|                 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 | ||||
|             // closed state. | ||||
|             debug_assert!(!stream.state.is_closed()); | ||||
|  | ||||
|             // Store the state | ||||
|             me.store.insert(id, stream); | ||||
|  | ||||
|             id | ||||
|         }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user