perf(h1): remove book keeping on final body writes
This commit is contained in:
34
src/common/buf.rs
Normal file
34
src/common/buf.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use bytes::Buf;
|
||||
use iovec::IoVec;
|
||||
|
||||
/// A `Buf` wrapping a static byte slice.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StaticBuf(pub(crate) &'static [u8]);
|
||||
|
||||
impl Buf for StaticBuf {
|
||||
#[inline]
|
||||
fn remaining(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bytes(&self) -> &[u8] {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.0 = &self.0[cnt..];
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
|
||||
if dst.is_empty() {
|
||||
return 0;
|
||||
} else {
|
||||
dst[0] = self.0.into();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
mod buf;
|
||||
mod exec;
|
||||
mod never;
|
||||
|
||||
pub(crate) use self::buf::StaticBuf;
|
||||
pub(crate) use self::exec::Exec;
|
||||
pub use self::never::Never;
|
||||
|
||||
@@ -482,20 +482,13 @@ where I: AsyncRead + AsyncWrite,
|
||||
debug_assert!(chunk.remaining() != 0);
|
||||
|
||||
let state = match self.state.writing {
|
||||
Writing::Body(ref mut encoder) => {
|
||||
self.io.buffer(encoder.encode(chunk));
|
||||
match encoder.end() {
|
||||
Ok(end) => {
|
||||
if let Some(end) = end {
|
||||
self.io.buffer(end);
|
||||
}
|
||||
if encoder.is_last() {
|
||||
Writing::Closed
|
||||
} else {
|
||||
Writing::KeepAlive
|
||||
}
|
||||
},
|
||||
Err(_not_eof) => Writing::Closed,
|
||||
Writing::Body(ref encoder) => {
|
||||
let (encoded, can_keep_alive) = encoder.encode_and_end(chunk);
|
||||
self.io.buffer(encoded);
|
||||
if can_keep_alive {
|
||||
Writing::KeepAlive
|
||||
} else {
|
||||
Writing::Closed
|
||||
}
|
||||
},
|
||||
_ => unreachable!("write_body invalid state: {:?}", self.state.writing),
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
//use std::cmp;
|
||||
use std::fmt;
|
||||
|
||||
use bytes::{Buf, IntoBuf};
|
||||
use bytes::buf::{Chain, Take};
|
||||
use iovec::IoVec;
|
||||
|
||||
use common::StaticBuf;
|
||||
|
||||
/// Encoders to handle different Transfer-Encodings.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Encoder {
|
||||
@@ -39,8 +40,8 @@ enum Kind {
|
||||
enum BufKind<B> {
|
||||
Exact(B),
|
||||
Limited(Take<B>),
|
||||
Chunked(Chain<ChunkSize, Chain<B, CrLf>>),
|
||||
ChunkedEnd(CrLf),
|
||||
Chunked(Chain<Chain<ChunkSize, B>, StaticBuf>),
|
||||
ChunkedEnd(StaticBuf),
|
||||
}
|
||||
|
||||
impl Encoder {
|
||||
@@ -81,7 +82,7 @@ impl Encoder {
|
||||
match self.kind {
|
||||
Kind::Length(0) => Ok(None),
|
||||
Kind::Chunked => Ok(Some(EncodedBuf {
|
||||
kind: BufKind::ChunkedEnd(CrLf(b"0\r\n\r\n")),
|
||||
kind: BufKind::ChunkedEnd(StaticBuf(b"0\r\n\r\n")),
|
||||
})),
|
||||
_ => Err(NotEof),
|
||||
}
|
||||
@@ -93,13 +94,15 @@ impl Encoder {
|
||||
{
|
||||
let msg = msg.into_buf();
|
||||
let len = msg.remaining();
|
||||
assert!(len > 0, "encode() called with empty buf");
|
||||
debug_assert!(len > 0, "encode() called with empty buf");
|
||||
|
||||
let buf = match self.kind {
|
||||
let kind = match self.kind {
|
||||
Kind::Chunked => {
|
||||
trace!("encoding chunked {}B", len);
|
||||
BufKind::Chunked(ChunkSize::new(len)
|
||||
.chain(msg.chain(CrLf(b"\r\n"))))
|
||||
let buf = ChunkSize::new(len)
|
||||
.chain(msg)
|
||||
.chain(StaticBuf(b"\r\n"));
|
||||
BufKind::Chunked(buf)
|
||||
},
|
||||
Kind::Length(ref mut remaining) => {
|
||||
trace!("sized write, len = {}", len);
|
||||
@@ -118,9 +121,52 @@ impl Encoder {
|
||||
}
|
||||
};
|
||||
EncodedBuf {
|
||||
kind: buf,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode_and_end<B>(&self, msg: B) -> (EncodedBuf<B::Buf>, bool)
|
||||
where
|
||||
B: IntoBuf,
|
||||
{
|
||||
let msg = msg.into_buf();
|
||||
let len = msg.remaining();
|
||||
debug_assert!(len > 0, "encode() called with empty buf");
|
||||
|
||||
let (kind, eof) = match self.kind {
|
||||
Kind::Chunked => {
|
||||
trace!("encoding chunked {}B", len);
|
||||
let buf = ChunkSize::new(len)
|
||||
.chain(msg)
|
||||
.chain(StaticBuf(b"\r\n0\r\n\r\n"));
|
||||
(BufKind::Chunked(buf), !self.is_last)
|
||||
},
|
||||
Kind::Length(remaining) => {
|
||||
use std::cmp::Ordering;
|
||||
|
||||
trace!("sized write, len = {}", len);
|
||||
match (len as u64).cmp(&remaining) {
|
||||
Ordering::Greater => {
|
||||
(BufKind::Limited(msg.take(remaining as usize)), !self.is_last)
|
||||
},
|
||||
Ordering::Equal => {
|
||||
(BufKind::Exact(msg), !self.is_last)
|
||||
},
|
||||
Ordering::Less => {
|
||||
(BufKind::Exact(msg), false)
|
||||
}
|
||||
}
|
||||
},
|
||||
Kind::CloseDelimited => {
|
||||
trace!("close delimited write {}B", len);
|
||||
(BufKind::Exact(msg), false)
|
||||
}
|
||||
};
|
||||
|
||||
(EncodedBuf {
|
||||
kind,
|
||||
}, eof)
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> Buf for EncodedBuf<B>
|
||||
@@ -236,36 +282,6 @@ impl fmt::Write for ChunkSize {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CrLf(&'static [u8]);
|
||||
|
||||
impl Buf for CrLf {
|
||||
#[inline]
|
||||
fn remaining(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bytes(&self) -> &[u8] {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn advance(&mut self, cnt: usize) {
|
||||
self.0 = &self.0[cnt..];
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn bytes_vec<'t>(&'t self, dst: &mut [&'t IoVec]) -> usize {
|
||||
if dst.is_empty() {
|
||||
return 0;
|
||||
} else {
|
||||
dst[0] = self.0.into();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bytes::{BufMut};
|
||||
|
||||
Reference in New Issue
Block a user