1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 16:02:59 +01:00

optimize http message serialization

This commit is contained in:
Nikolay Kim 2018-02-19 17:21:04 -08:00
parent 4d81186059
commit 6ee14efbe2
4 changed files with 61 additions and 14 deletions

View File

@ -74,6 +74,7 @@ impl SharedMessagePool {
SharedMessagePool(RefCell::new(VecDeque::with_capacity(128))) SharedMessagePool(RefCell::new(VecDeque::with_capacity(128)))
} }
#[inline]
pub fn get(&self) -> Rc<HttpMessage> { pub fn get(&self) -> Rc<HttpMessage> {
if let Some(msg) = self.0.borrow_mut().pop_front() { if let Some(msg) = self.0.borrow_mut().pop_front() {
msg msg
@ -82,6 +83,7 @@ impl SharedMessagePool {
} }
} }
#[inline]
pub fn release(&self, mut msg: Rc<HttpMessage>) { pub fn release(&self, mut msg: Rc<HttpMessage>) {
let v = &mut self.0.borrow_mut(); let v = &mut self.0.borrow_mut();
if v.len() < 128 { if v.len() < 128 {

View File

@ -21,6 +21,7 @@ struct Inner {
named: HashMap<String, (Pattern, bool)>, named: HashMap<String, (Pattern, bool)>,
patterns: Vec<Pattern>, patterns: Vec<Pattern>,
srv: ServerSettings, srv: ServerSettings,
hasroutes: bool,
} }
impl Router { impl Router {
@ -55,6 +56,7 @@ impl Router {
regset: RegexSet::new(&paths).unwrap(), regset: RegexSet::new(&paths).unwrap(),
named: named, named: named,
patterns: patterns, patterns: patterns,
hasroutes: !paths.is_empty(),
srv: settings })), resources) srv: settings })), resources)
} }
@ -72,6 +74,7 @@ impl Router {
/// Query for matched resource /// Query for matched resource
pub fn recognize<S>(&self, req: &mut HttpRequest<S>) -> Option<usize> { pub fn recognize<S>(&self, req: &mut HttpRequest<S>) -> Option<usize> {
if !self.0.hasroutes { return None }
let mut idx = None; let mut idx = None;
{ {
if self.0.prefix_len > req.path().len() { if self.0.prefix_len > req.path().len() {

View File

@ -1,4 +1,4 @@
use std::io; use std::{io, mem};
use bytes::BufMut; use bytes::BufMut;
use futures::{Async, Poll}; use futures::{Async, Poll};
use tokio_io::AsyncWrite; use tokio_io::AsyncWrite;
@ -135,38 +135,60 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
// status line // status line
helpers::write_status_line(version, msg.status().as_u16(), &mut buffer); helpers::write_status_line(version, msg.status().as_u16(), &mut buffer);
buffer.extend_from_slice(msg.reason().as_bytes()); SharedBytes::extend_from_slice_(buffer, msg.reason().as_bytes());
match body { match body {
Body::Empty => Body::Empty =>
if req.method != Method::HEAD { if req.method != Method::HEAD {
buffer.extend_from_slice(b"\r\ncontent-length: 0\r\n"); SharedBytes::extend_from_slice_(buffer, b"\r\ncontent-length: 0\r\n");
} else { } else {
buffer.extend_from_slice(b"\r\n"); SharedBytes::extend_from_slice_(buffer, b"\r\n");
}, },
Body::Binary(ref bytes) => Body::Binary(ref bytes) =>
helpers::write_content_length(bytes.len(), &mut buffer), helpers::write_content_length(bytes.len(), &mut buffer),
_ => _ =>
buffer.extend_from_slice(b"\r\n"), SharedBytes::extend_from_slice_(buffer, b"\r\n"),
} }
// write headers // write headers
let mut pos = 0;
let mut remaining = buffer.remaining_mut();
let mut buf: &mut [u8] = unsafe{ mem::transmute(buffer.bytes_mut()) };
for (key, value) in msg.headers() { for (key, value) in msg.headers() {
let v = value.as_ref(); let v = value.as_ref();
let k = key.as_str().as_bytes(); let k = key.as_str().as_bytes();
buffer.reserve(k.len() + v.len() + 4); let len = k.len() + v.len() + 4;
buffer.put_slice(k); if len > remaining {
buffer.put_slice(b": "); unsafe{buffer.advance_mut(pos)};
buffer.put_slice(v); pos = 0;
buffer.put_slice(b"\r\n"); buffer.reserve(len);
remaining = buffer.remaining_mut();
buf = unsafe{ mem::transmute(buffer.bytes_mut()) };
}
buf[pos..pos+k.len()].copy_from_slice(k);
pos += k.len();
buf[pos..pos+2].copy_from_slice(b": ");
pos += 2;
buf[pos..pos+v.len()].copy_from_slice(v);
pos += v.len();
buf[pos..pos+2].copy_from_slice(b"\r\n");
pos += 2;
remaining -= len;
//buffer.put_slice(k);
//buffer.put_slice(b": ");
//buffer.put_slice(v);
//buffer.put_slice(b"\r\n");
} }
unsafe{buffer.advance_mut(pos)};
// using helpers::date is quite a lot faster // using helpers::date is quite a lot faster
if !msg.headers().contains_key(DATE) { if !msg.headers().contains_key(DATE) {
helpers::date(&mut buffer); helpers::date(&mut buffer);
} else { } else {
// msg eof // msg eof
buffer.extend_from_slice(b"\r\n"); SharedBytes::extend_from_slice_(buffer, b"\r\n");
} }
self.headers_size = buffer.len() as u32; self.headers_size = buffer.len() as u32;
} }

View File

@ -2,7 +2,7 @@ use std::mem;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::collections::VecDeque; use std::collections::VecDeque;
use bytes::BytesMut; use bytes::{BufMut, BytesMut};
use body::Binary; use body::Binary;
@ -98,12 +98,32 @@ impl SharedBytes {
#[inline] #[inline]
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
pub fn extend(&self, data: Binary) { pub fn extend(&self, data: Binary) {
self.get_mut().extend_from_slice(data.as_ref()); let buf = self.get_mut();
let data = data.as_ref();
buf.reserve(data.len());
SharedBytes::put_slice(buf, data);
} }
#[inline] #[inline]
pub fn extend_from_slice(&self, data: &[u8]) { pub fn extend_from_slice(&self, data: &[u8]) {
self.get_mut().extend_from_slice(data); let buf = self.get_mut();
buf.reserve(data.len());
SharedBytes::put_slice(buf, data);
}
#[inline]
pub(crate) fn put_slice(buf: &mut BytesMut, src: &[u8]) {
let len = src.len();
unsafe {
buf.bytes_mut()[..len].copy_from_slice(src);
buf.advance_mut(len);
}
}
#[inline]
pub(crate) fn extend_from_slice_(buf: &mut BytesMut, data: &[u8]) {
buf.reserve(data.len());
SharedBytes::put_slice(buf, data);
} }
} }