Optimize the creation of the Data structure.

This commit is contained in:
Sergio Benitez 2017-04-24 01:33:00 -07:00
parent 423acdd32a
commit 40d11929d7
3 changed files with 35 additions and 30 deletions

View File

@ -18,10 +18,10 @@ pub type HyperBodyReader<'a, 'b> =
self::HttpReader<&'a mut hyper::buffer::BufReader<&'b mut NetworkStream>>; self::HttpReader<&'a mut hyper::buffer::BufReader<&'b mut NetworkStream>>;
// |---- from hyper ----| // |---- from hyper ----|
pub type BodyReader = HttpReader<Chain<Take<Cursor<Vec<u8>>>, BufReader<NetStream>>>; pub type BodyReader = HttpReader<Chain<Cursor<Vec<u8>>, NetStream>>;
/// The number of bytes to read into the "peek" buffer. /// The number of bytes to read into the "peek" buffer.
const PEEK_BYTES: usize = 4096; const PEEK_BYTES: usize = 512;
/// Type representing the data in the body of an incoming request. /// Type representing the data in the body of an incoming request.
/// ///
@ -48,7 +48,7 @@ const PEEK_BYTES: usize = 4096;
/// object ensures that holding a `Data` object means that all of the data is /// object ensures that holding a `Data` object means that all of the data is
/// available for reading. /// available for reading.
/// ///
/// The `peek` method returns a slice containing at most 4096 bytes of buffered /// The `peek` method returns a slice containing at most 512 bytes of buffered
/// body data. This enables partially or fully reading from a `Data` object /// body data. This enables partially or fully reading from a `Data` object
/// without consuming the `Data` object. /// without consuming the `Data` object.
pub struct Data { pub struct Data {
@ -66,9 +66,12 @@ impl Data {
/// the data in a request. /// the data in a request.
pub fn open(mut self) -> DataStream { pub fn open(mut self) -> DataStream {
let buffer = ::std::mem::replace(&mut self.buffer, vec![]); let buffer = ::std::mem::replace(&mut self.buffer, vec![]);
let empty_stream = Cursor::new(vec![]).take(0) let empty_stream = Cursor::new(vec![])
.chain(BufReader::new(NetStream::Local(Cursor::new(vec![])))); .chain(NetStream::Local(Cursor::new(vec![])));
// FIXME: Insert a `BufReader` in front of the `NetStream` with capacity
// 4096. We need the new `Chain` methods to get the inner reader to
// actually do this, however.
let empty_http_stream = HttpReader::SizedReader(empty_stream, 0); let empty_http_stream = HttpReader::SizedReader(empty_stream, 0);
let stream = ::std::mem::replace(&mut self.stream, empty_http_stream); let stream = ::std::mem::replace(&mut self.stream, empty_http_stream);
DataStream(Cursor::new(buffer).chain(stream)) DataStream(Cursor::new(buffer).chain(stream))
@ -77,10 +80,12 @@ impl Data {
// FIXME: This is absolutely terrible (downcasting!), thanks to Hyper. // FIXME: This is absolutely terrible (downcasting!), thanks to Hyper.
pub(crate) fn from_hyp(mut body: HyperBodyReader) -> Result<Data, &'static str> { pub(crate) fn from_hyp(mut body: HyperBodyReader) -> Result<Data, &'static str> {
// Steal the internal, undecoded data buffer and net stream from Hyper. // Steal the internal, undecoded data buffer and net stream from Hyper.
let (hyper_buf, pos, cap) = body.get_mut().take_buf(); let (mut hyper_buf, pos, cap) = body.get_mut().take_buf();
unsafe { hyper_buf.set_len(cap); }
let hyper_net_stream = body.get_ref().get_ref(); let hyper_net_stream = body.get_ref().get_ref();
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
#[inline(always)]
fn concrete_stream(stream: &&mut NetworkStream) -> Option<NetStream> { fn concrete_stream(stream: &&mut NetworkStream) -> Option<NetStream> {
stream.downcast_ref::<HttpsStream>() stream.downcast_ref::<HttpsStream>()
.map(|s| NetStream::Https(s.clone())) .map(|s| NetStream::Https(s.clone()))
@ -91,6 +96,7 @@ impl Data {
} }
#[cfg(not(feature = "tls"))] #[cfg(not(feature = "tls"))]
#[inline(always)]
fn concrete_stream(stream: &&mut NetworkStream) -> Option<NetStream> { fn concrete_stream(stream: &&mut NetworkStream) -> Option<NetStream> {
stream.downcast_ref::<HttpStream>() stream.downcast_ref::<HttpStream>()
.map(|s| NetStream::Http(s.clone())) .map(|s| NetStream::Http(s.clone()))
@ -107,11 +113,10 @@ impl Data {
// TODO: Explain this. // TODO: Explain this.
trace_!("Hyper buffer: [{}..{}] ({} bytes).", pos, cap, cap - pos); trace_!("Hyper buffer: [{}..{}] ({} bytes).", pos, cap, cap - pos);
let (start, remaining) = (pos as u64, (cap - pos) as u64);
let mut cursor = Cursor::new(hyper_buf); let mut cursor = Cursor::new(hyper_buf);
cursor.set_position(start); cursor.set_position(pos as u64);
let inner_data = cursor.take(remaining) let inner_data = cursor.chain(net_stream);
.chain(BufReader::new(net_stream.clone()));
// Create an HTTP reader from the stream. // Create an HTTP reader from the stream.
let http_stream = match body { let http_stream = match body {
@ -132,8 +137,12 @@ impl Data {
/// buffer contains _all_ of the data in the body of the request. /// buffer contains _all_ of the data in the body of the request.
#[inline(always)] #[inline(always)]
pub fn peek(&self) -> &[u8] { pub fn peek(&self) -> &[u8] {
if self.buffer.len() > PEEK_BYTES {
&self.buffer[..PEEK_BYTES]
} else {
&self.buffer &self.buffer
} }
}
/// Returns true if the `peek` buffer contains all of the data in the body /// Returns true if the `peek` buffer contains all of the data in the body
/// of the request. Returns `false` if it does not or if it is not known if /// of the request. Returns `false` if it does not or if it is not known if
@ -165,6 +174,7 @@ impl Data {
// in the buffer is at `pos` and the buffer has `cap` valid bytes. Thus, the // in the buffer is at `pos` and the buffer has `cap` valid bytes. Thus, the
// bytes `vec[pos..cap]` are buffered and unread. The remainder of the data // bytes `vec[pos..cap]` are buffered and unread. The remainder of the data
// bytes can be read from `stream`. // bytes can be read from `stream`.
#[inline(always)]
pub(crate) fn new(mut stream: BodyReader) -> Data { pub(crate) fn new(mut stream: BodyReader) -> Data {
trace_!("Date::new({:?})", stream); trace_!("Date::new({:?})", stream);
let mut peek_buf = vec![0; PEEK_BYTES]; let mut peek_buf = vec![0; PEEK_BYTES];
@ -196,22 +206,13 @@ impl Data {
/// This creates a `data` object from a local data source `data`. /// This creates a `data` object from a local data source `data`.
pub(crate) fn local(mut data: Vec<u8>) -> Data { pub(crate) fn local(mut data: Vec<u8>) -> Data {
// Emulate peek buffering. let empty_stream = Cursor::new(vec![])
let (buf, rest) = if data.len() <= PEEK_BYTES { .chain(NetStream::Local(Cursor::new(vec![])));
(data, vec![])
} else {
let rest = data.split_off(PEEK_BYTES);
(data, rest)
};
let stream_len = rest.len() as u64;
let stream = Cursor::new(vec![]).take(0)
.chain(BufReader::new(NetStream::Local(Cursor::new(rest))));
Data { Data {
buffer: buf, buffer: data,
stream: HttpReader::SizedReader(stream, stream_len), stream: HttpReader::SizedReader(empty_stream, 0),
is_complete: stream_len == 0, is_complete: true,
} }
} }
} }

View File

@ -116,6 +116,7 @@ impl Rocket {
} }
} }
#[inline]
fn write_response(&self, mut response: Response, fn write_response(&self, mut response: Response,
mut hyp_res: hyper::FreshResponse) -> io::Result<()> mut hyp_res: hyper::FreshResponse) -> io::Result<()>
{ {

View File

@ -11,7 +11,8 @@ pub trait Collider<T: ?Sized = Self> {
fn collides_with(&self, other: &T) -> bool; fn collides_with(&self, other: &T) -> bool;
} }
pub fn index_match_until(break_c: char, #[inline(always)]
fn index_match_until(break_c: char,
a: &str, a: &str,
b: &str, b: &str,
dir: bool) dir: bool)
@ -39,11 +40,13 @@ pub fn index_match_until(break_c: char,
Some((i, j)) Some((i, j))
} }
#[inline(always)]
fn do_match_until(break_c: char, a: &str, b: &str, dir: bool) -> bool { fn do_match_until(break_c: char, a: &str, b: &str, dir: bool) -> bool {
index_match_until(break_c, a, b, dir).is_some() index_match_until(break_c, a, b, dir).is_some()
} }
impl<'a> Collider<str> for &'a str { impl<'a> Collider<str> for &'a str {
#[inline(always)]
fn collides_with(&self, other: &str) -> bool { fn collides_with(&self, other: &str) -> bool {
let (a, b) = (self, other); let (a, b) = (self, other);
do_match_until('<', a, b, true) && do_match_until('>', a, b, false) do_match_until('<', a, b, true) && do_match_until('>', a, b, false)
@ -72,6 +75,7 @@ impl<'a, 'b> Collider<URI<'b>> for URI<'a> {
} }
impl Collider for MediaType { impl Collider for MediaType {
#[inline(always)]
fn collides_with(&self, other: &MediaType) -> bool { fn collides_with(&self, other: &MediaType) -> bool {
let collide = |a, b| a == "*" || b == "*" || a == b; let collide = |a, b| a == "*" || b == "*" || a == b;
collide(self.top(), other.top()) && collide(self.sub(), other.sub()) collide(self.top(), other.top()) && collide(self.sub(), other.sub())
@ -113,10 +117,9 @@ impl<'r> Collider<Request<'r>> for Route {
self.method == req.method() self.method == req.method()
&& self.path.collides_with(req.uri()) && self.path.collides_with(req.uri())
&& self.path.query().map_or(true, |_| req.uri().query().is_some()) && self.path.query().map_or(true, |_| req.uri().query().is_some())
// FIXME: Avoid calling `format` is `self.format` == None. && match self.format {
&& match self.format.as_ref() { Some(ref mt_a) => match req.format() {
Some(mt_a) => match req.format().as_ref() { Some(ref mt_b) => mt_a.collides_with(mt_b),
Some(mt_b) => mt_a.collides_with(mt_b),
None => false None => false
}, },
None => true None => true