mirror of
https://github.com/actix/actix-web.git
synced 2024-12-24 00:50:36 +00:00
refactor shared bytes api
This commit is contained in:
parent
3425f7be40
commit
89a89e7b18
7 changed files with 159 additions and 157 deletions
|
@ -66,84 +66,6 @@ impl fmt::Write for CachedDate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal use only! unsafe
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct SharedBytesPool(RefCell<VecDeque<Rc<BytesMut>>>);
|
|
||||||
|
|
||||||
impl SharedBytesPool {
|
|
||||||
pub fn new() -> SharedBytesPool {
|
|
||||||
SharedBytesPool(RefCell::new(VecDeque::with_capacity(128)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_bytes(&self) -> Rc<BytesMut> {
|
|
||||||
if let Some(bytes) = self.0.borrow_mut().pop_front() {
|
|
||||||
bytes
|
|
||||||
} else {
|
|
||||||
Rc::new(BytesMut::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn release_bytes(&self, mut bytes: Rc<BytesMut>) {
|
|
||||||
let v = &mut self.0.borrow_mut();
|
|
||||||
if v.len() < 128 {
|
|
||||||
Rc::get_mut(&mut bytes).unwrap().take();
|
|
||||||
v.push_front(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct SharedBytes(
|
|
||||||
Option<Rc<BytesMut>>, Option<Rc<SharedBytesPool>>);
|
|
||||||
|
|
||||||
impl Drop for SharedBytes {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if let Some(ref pool) = self.1 {
|
|
||||||
if let Some(bytes) = self.0.take() {
|
|
||||||
if Rc::strong_count(&bytes) == 1 {
|
|
||||||
pool.release_bytes(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SharedBytes {
|
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
|
||||||
SharedBytes(None, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(bytes: Rc<BytesMut>, pool: Rc<SharedBytesPool>) -> SharedBytes {
|
|
||||||
SharedBytes(Some(bytes), Some(pool))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
#[allow(mutable_transmutes)]
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref, inline_always))]
|
|
||||||
pub fn get_mut(&self) -> &mut BytesMut {
|
|
||||||
let r: &BytesMut = self.0.as_ref().unwrap().as_ref();
|
|
||||||
unsafe{mem::transmute(r)}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_ref(&self) -> &BytesMut {
|
|
||||||
self.0.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SharedBytes {
|
|
||||||
fn default() -> Self {
|
|
||||||
SharedBytes(Some(Rc::new(BytesMut::new())), None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for SharedBytes {
|
|
||||||
fn clone(&self) -> SharedBytes {
|
|
||||||
SharedBytes(self.0.clone(), self.1.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Internal use only! unsafe
|
/// Internal use only! unsafe
|
||||||
pub(crate) struct SharedMessagePool(RefCell<VecDeque<Rc<HttpMessage>>>);
|
pub(crate) struct SharedMessagePool(RefCell<VecDeque<Rc<HttpMessage>>>);
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,13 @@ use bytes::{Bytes, BytesMut, BufMut, Writer};
|
||||||
use headers::ContentEncoding;
|
use headers::ContentEncoding;
|
||||||
use body::{Body, Binary};
|
use body::{Body, Binary};
|
||||||
use error::PayloadError;
|
use error::PayloadError;
|
||||||
use helpers::SharedBytes;
|
|
||||||
use httprequest::HttpMessage;
|
use httprequest::HttpMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use payload::{PayloadSender, PayloadWriter};
|
use payload::{PayloadSender, PayloadWriter};
|
||||||
|
|
||||||
|
use super::shared::SharedBytes;
|
||||||
|
|
||||||
|
|
||||||
impl ContentEncoding {
|
impl ContentEncoding {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -399,7 +401,7 @@ impl PayloadEncoder {
|
||||||
let _ = enc.write(bytes.clone());
|
let _ = enc.write(bytes.clone());
|
||||||
let _ = enc.write_eof();
|
let _ = enc.write_eof();
|
||||||
|
|
||||||
*bytes = Binary::from(tmp.get_mut().take());
|
*bytes = Binary::from(tmp.take());
|
||||||
encoding = ContentEncoding::Identity;
|
encoding = ContentEncoding::Identity;
|
||||||
}
|
}
|
||||||
resp.headers_mut().remove(CONTENT_LENGTH);
|
resp.headers_mut().remove(CONTENT_LENGTH);
|
||||||
|
@ -503,16 +505,6 @@ impl PayloadEncoder {
|
||||||
|
|
||||||
impl PayloadEncoder {
|
impl PayloadEncoder {
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.get_ref().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_mut(&mut self) -> &mut BytesMut {
|
|
||||||
self.0.get_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_eof(&self) -> bool {
|
pub fn is_eof(&self) -> bool {
|
||||||
self.0.is_eof()
|
self.0.is_eof()
|
||||||
|
@ -554,34 +546,6 @@ impl ContentEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_ref(&self) -> &BytesMut {
|
|
||||||
match *self {
|
|
||||||
ContentEncoder::Br(ref encoder) =>
|
|
||||||
encoder.get_ref().buffer.get_ref(),
|
|
||||||
ContentEncoder::Deflate(ref encoder) =>
|
|
||||||
encoder.get_ref().buffer.get_ref(),
|
|
||||||
ContentEncoder::Gzip(ref encoder) =>
|
|
||||||
encoder.get_ref().buffer.get_ref(),
|
|
||||||
ContentEncoder::Identity(ref encoder) =>
|
|
||||||
encoder.buffer.get_ref(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_mut(&mut self) -> &mut BytesMut {
|
|
||||||
match *self {
|
|
||||||
ContentEncoder::Br(ref mut encoder) =>
|
|
||||||
encoder.get_mut().buffer.get_mut(),
|
|
||||||
ContentEncoder::Deflate(ref mut encoder) =>
|
|
||||||
encoder.get_mut().buffer.get_mut(),
|
|
||||||
ContentEncoder::Gzip(ref mut encoder) =>
|
|
||||||
encoder.get_mut().buffer.get_mut(),
|
|
||||||
ContentEncoder::Identity(ref mut encoder) =>
|
|
||||||
encoder.buffer.get_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn write_eof(&mut self) -> Result<(), io::Error> {
|
pub fn write_eof(&mut self) -> Result<(), io::Error> {
|
||||||
|
@ -727,11 +691,12 @@ impl TransferEncoding {
|
||||||
|
|
||||||
/// Encode message. Return `EOF` state of encoder
|
/// Encode message. Return `EOF` state of encoder
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn encode(&mut self, msg: Binary) -> io::Result<bool> {
|
pub fn encode(&mut self, mut msg: Binary) -> io::Result<bool> {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
TransferEncodingKind::Eof => {
|
TransferEncodingKind::Eof => {
|
||||||
self.buffer.get_mut().extend_from_slice(msg.as_ref());
|
let eof = msg.is_empty();
|
||||||
Ok(msg.is_empty())
|
self.buffer.extend(msg);
|
||||||
|
Ok(eof)
|
||||||
},
|
},
|
||||||
TransferEncodingKind::Chunked(ref mut eof) => {
|
TransferEncodingKind::Chunked(ref mut eof) => {
|
||||||
if *eof {
|
if *eof {
|
||||||
|
@ -740,12 +705,14 @@ impl TransferEncoding {
|
||||||
|
|
||||||
if msg.is_empty() {
|
if msg.is_empty() {
|
||||||
*eof = true;
|
*eof = true;
|
||||||
self.buffer.get_mut().extend_from_slice(b"0\r\n\r\n");
|
self.buffer.extend_from_slice(b"0\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
write!(self.buffer.get_mut(), "{:X}\r\n", msg.len())
|
let mut buf = BytesMut::new();
|
||||||
|
write!(&mut buf, "{:X}\r\n", msg.len())
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
|
||||||
self.buffer.get_mut().extend_from_slice(msg.as_ref());
|
self.buffer.extend(buf.into());
|
||||||
self.buffer.get_mut().extend_from_slice(b"\r\n");
|
self.buffer.extend(msg);
|
||||||
|
self.buffer.extend_from_slice(b"\r\n");
|
||||||
}
|
}
|
||||||
Ok(*eof)
|
Ok(*eof)
|
||||||
},
|
},
|
||||||
|
@ -754,7 +721,7 @@ impl TransferEncoding {
|
||||||
return Ok(*remaining == 0)
|
return Ok(*remaining == 0)
|
||||||
}
|
}
|
||||||
let max = cmp::min(*remaining, msg.len() as u64);
|
let max = cmp::min(*remaining, msg.len() as u64);
|
||||||
self.buffer.get_mut().extend_from_slice(msg.as_ref()[..max as usize].as_ref());
|
self.buffer.extend(msg.take().split_to(max as usize).into());
|
||||||
|
|
||||||
*remaining -= max as u64;
|
*remaining -= max as u64;
|
||||||
Ok(*remaining == 0)
|
Ok(*remaining == 0)
|
||||||
|
@ -770,7 +737,7 @@ impl TransferEncoding {
|
||||||
TransferEncodingKind::Chunked(ref mut eof) => {
|
TransferEncodingKind::Chunked(ref mut eof) => {
|
||||||
if !*eof {
|
if !*eof {
|
||||||
*eof = true;
|
*eof = true;
|
||||||
self.buffer.get_mut().extend_from_slice(b"0\r\n\r\n");
|
self.buffer.extend_from_slice(b"0\r\n\r\n");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@ use http::header::{HeaderValue, CONNECTION, DATE};
|
||||||
|
|
||||||
use helpers;
|
use helpers;
|
||||||
use body::{Body, Binary};
|
use body::{Body, Binary};
|
||||||
use helpers::SharedBytes;
|
|
||||||
use httprequest::HttpMessage;
|
use httprequest::HttpMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
|
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
|
||||||
|
use super::shared::SharedBytes;
|
||||||
use super::encoding::PayloadEncoder;
|
use super::encoding::PayloadEncoder;
|
||||||
|
|
||||||
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
||||||
|
@ -56,7 +56,7 @@ impl<T: AsyncWrite> H1Writer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disconnected(&mut self) {
|
pub fn disconnected(&mut self) {
|
||||||
self.encoder.get_mut().take();
|
self.buffer.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keepalive(&self) -> bool {
|
pub fn keepalive(&self) -> bool {
|
||||||
|
@ -64,15 +64,13 @@ impl<T: AsyncWrite> H1Writer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_stream(&mut self) -> io::Result<WriterState> {
|
fn write_to_stream(&mut self) -> io::Result<WriterState> {
|
||||||
let buffer = self.encoder.get_mut();
|
while !self.buffer.is_empty() {
|
||||||
|
match self.stream.write(self.buffer.as_ref()) {
|
||||||
while !buffer.is_empty() {
|
|
||||||
match self.stream.write(buffer.as_ref()) {
|
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
let _ = buffer.split_to(n);
|
let _ = self.buffer.split_to(n);
|
||||||
},
|
},
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||||
if buffer.len() > MAX_WRITE_BUFFER_SIZE {
|
if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
|
||||||
return Ok(WriterState::Pause)
|
return Ok(WriterState::Pause)
|
||||||
} else {
|
} else {
|
||||||
return Ok(WriterState::Done)
|
return Ok(WriterState::Done)
|
||||||
|
@ -131,7 +129,7 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
||||||
|
|
||||||
// render message
|
// render message
|
||||||
{
|
{
|
||||||
let mut buffer = self.encoder.get_mut();
|
let mut buffer = self.buffer.get_mut();
|
||||||
if let Body::Binary(ref bytes) = body {
|
if let Body::Binary(ref bytes) = body {
|
||||||
buffer.reserve(256 + msg.headers().len() * AVERAGE_HEADER_SIZE + bytes.len());
|
buffer.reserve(256 + msg.headers().len() * AVERAGE_HEADER_SIZE + bytes.len());
|
||||||
} else {
|
} else {
|
||||||
|
@ -190,11 +188,11 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
||||||
return Ok(WriterState::Done)
|
return Ok(WriterState::Done)
|
||||||
} else {
|
} else {
|
||||||
// might be response to EXCEPT
|
// might be response to EXCEPT
|
||||||
self.encoder.get_mut().extend_from_slice(payload.as_ref())
|
self.buffer.extend_from_slice(payload.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.encoder.len() > MAX_WRITE_BUFFER_SIZE {
|
if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
|
||||||
Ok(WriterState::Pause)
|
Ok(WriterState::Pause)
|
||||||
} else {
|
} else {
|
||||||
Ok(WriterState::Done)
|
Ok(WriterState::Done)
|
||||||
|
@ -207,7 +205,7 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
||||||
if !self.encoder.is_eof() {
|
if !self.encoder.is_eof() {
|
||||||
Err(io::Error::new(io::ErrorKind::Other,
|
Err(io::Error::new(io::ErrorKind::Other,
|
||||||
"Last payload item, but eof is not reached"))
|
"Last payload item, but eof is not reached"))
|
||||||
} else if self.encoder.len() > MAX_WRITE_BUFFER_SIZE {
|
} else if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
|
||||||
Ok(WriterState::Pause)
|
Ok(WriterState::Pause)
|
||||||
} else {
|
} else {
|
||||||
Ok(WriterState::Done)
|
Ok(WriterState::Done)
|
||||||
|
|
|
@ -8,10 +8,10 @@ use http::header::{HeaderValue, CONNECTION, TRANSFER_ENCODING, DATE, CONTENT_LEN
|
||||||
|
|
||||||
use helpers;
|
use helpers;
|
||||||
use body::{Body, Binary};
|
use body::{Body, Binary};
|
||||||
use helpers::SharedBytes;
|
|
||||||
use httprequest::HttpMessage;
|
use httprequest::HttpMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use super::encoding::PayloadEncoder;
|
use super::encoding::PayloadEncoder;
|
||||||
|
use super::shared::SharedBytes;
|
||||||
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
|
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
|
||||||
|
|
||||||
const CHUNK_SIZE: usize = 16_384;
|
const CHUNK_SIZE: usize = 16_384;
|
||||||
|
@ -58,9 +58,7 @@ impl H2Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref mut stream) = self.stream {
|
if let Some(ref mut stream) = self.stream {
|
||||||
let buffer = self.encoder.get_mut();
|
if self.buffer.is_empty() {
|
||||||
|
|
||||||
if buffer.is_empty() {
|
|
||||||
if self.flags.contains(Flags::EOF) {
|
if self.flags.contains(Flags::EOF) {
|
||||||
let _ = stream.send_data(Bytes::new(), true);
|
let _ = stream.send_data(Bytes::new(), true);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +68,7 @@ impl H2Writer {
|
||||||
loop {
|
loop {
|
||||||
match stream.poll_capacity() {
|
match stream.poll_capacity() {
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
if buffer.len() > MAX_WRITE_BUFFER_SIZE {
|
if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
|
||||||
return Ok(WriterState::Pause)
|
return Ok(WriterState::Pause)
|
||||||
} else {
|
} else {
|
||||||
return Ok(WriterState::Done)
|
return Ok(WriterState::Done)
|
||||||
|
@ -80,15 +78,15 @@ impl H2Writer {
|
||||||
return Ok(WriterState::Done)
|
return Ok(WriterState::Done)
|
||||||
}
|
}
|
||||||
Ok(Async::Ready(Some(cap))) => {
|
Ok(Async::Ready(Some(cap))) => {
|
||||||
let len = buffer.len();
|
let len = self.buffer.len();
|
||||||
let bytes = buffer.split_to(cmp::min(cap, len));
|
let bytes = self.buffer.split_to(cmp::min(cap, len));
|
||||||
let eof = buffer.is_empty() && self.flags.contains(Flags::EOF);
|
let eof = self.buffer.is_empty() && self.flags.contains(Flags::EOF);
|
||||||
self.written += bytes.len() as u64;
|
self.written += bytes.len() as u64;
|
||||||
|
|
||||||
if let Err(err) = stream.send_data(bytes.freeze(), eof) {
|
if let Err(err) = stream.send_data(bytes.freeze(), eof) {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, err))
|
return Err(io::Error::new(io::ErrorKind::Other, err))
|
||||||
} else if !buffer.is_empty() {
|
} else if !self.buffer.is_empty() {
|
||||||
let cap = cmp::min(buffer.len(), CHUNK_SIZE);
|
let cap = cmp::min(self.buffer.len(), CHUNK_SIZE);
|
||||||
stream.reserve_capacity(cap);
|
stream.reserve_capacity(cap);
|
||||||
} else {
|
} else {
|
||||||
return Ok(WriterState::Pause)
|
return Ok(WriterState::Pause)
|
||||||
|
@ -170,7 +168,7 @@ impl Writer for H2Writer {
|
||||||
self.written = bytes.len() as u64;
|
self.written = bytes.len() as u64;
|
||||||
self.encoder.write(bytes)?;
|
self.encoder.write(bytes)?;
|
||||||
if let Some(ref mut stream) = self.stream {
|
if let Some(ref mut stream) = self.stream {
|
||||||
stream.reserve_capacity(cmp::min(self.encoder.len(), CHUNK_SIZE));
|
stream.reserve_capacity(cmp::min(self.buffer.len(), CHUNK_SIZE));
|
||||||
}
|
}
|
||||||
Ok(WriterState::Pause)
|
Ok(WriterState::Pause)
|
||||||
} else {
|
} else {
|
||||||
|
@ -188,11 +186,11 @@ impl Writer for H2Writer {
|
||||||
self.encoder.write(payload)?;
|
self.encoder.write(payload)?;
|
||||||
} else {
|
} else {
|
||||||
// might be response for EXCEPT
|
// might be response for EXCEPT
|
||||||
self.encoder.get_mut().extend_from_slice(payload.as_ref())
|
self.buffer.extend_from_slice(payload.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.encoder.len() > MAX_WRITE_BUFFER_SIZE {
|
if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
|
||||||
Ok(WriterState::Pause)
|
Ok(WriterState::Pause)
|
||||||
} else {
|
} else {
|
||||||
Ok(WriterState::Done)
|
Ok(WriterState::Done)
|
||||||
|
@ -206,7 +204,7 @@ impl Writer for H2Writer {
|
||||||
if !self.encoder.is_eof() {
|
if !self.encoder.is_eof() {
|
||||||
Err(io::Error::new(io::ErrorKind::Other,
|
Err(io::Error::new(io::ErrorKind::Other,
|
||||||
"Last payload item, but eof is not reached"))
|
"Last payload item, but eof is not reached"))
|
||||||
} else if self.encoder.len() > MAX_WRITE_BUFFER_SIZE {
|
} else if self.buffer.len() > MAX_WRITE_BUFFER_SIZE {
|
||||||
Ok(WriterState::Pause)
|
Ok(WriterState::Pause)
|
||||||
} else {
|
} else {
|
||||||
Ok(WriterState::Done)
|
Ok(WriterState::Done)
|
||||||
|
|
|
@ -15,6 +15,7 @@ mod h2;
|
||||||
mod h1writer;
|
mod h1writer;
|
||||||
mod h2writer;
|
mod h2writer;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
mod shared;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use self::srv::HttpServer;
|
pub use self::srv::HttpServer;
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::cell::{Cell, RefCell, RefMut};
|
||||||
|
|
||||||
use helpers;
|
use helpers;
|
||||||
use super::channel::Node;
|
use super::channel::Node;
|
||||||
|
use super::shared::{SharedBytes, SharedBytesPool};
|
||||||
|
|
||||||
/// Various server settings
|
/// Various server settings
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -63,7 +64,7 @@ pub(crate) struct WorkerSettings<H> {
|
||||||
h: RefCell<Vec<H>>,
|
h: RefCell<Vec<H>>,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
keep_alive: u64,
|
keep_alive: u64,
|
||||||
bytes: Rc<helpers::SharedBytesPool>,
|
bytes: Rc<SharedBytesPool>,
|
||||||
messages: Rc<helpers::SharedMessagePool>,
|
messages: Rc<helpers::SharedMessagePool>,
|
||||||
channels: Cell<usize>,
|
channels: Cell<usize>,
|
||||||
node: Node<()>,
|
node: Node<()>,
|
||||||
|
@ -75,7 +76,7 @@ impl<H> WorkerSettings<H> {
|
||||||
h: RefCell::new(h),
|
h: RefCell::new(h),
|
||||||
enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
|
enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
|
||||||
keep_alive: keep_alive.unwrap_or(0),
|
keep_alive: keep_alive.unwrap_or(0),
|
||||||
bytes: Rc::new(helpers::SharedBytesPool::new()),
|
bytes: Rc::new(SharedBytesPool::new()),
|
||||||
messages: Rc::new(helpers::SharedMessagePool::new()),
|
messages: Rc::new(helpers::SharedMessagePool::new()),
|
||||||
channels: Cell::new(0),
|
channels: Cell::new(0),
|
||||||
node: Node::head(),
|
node: Node::head(),
|
||||||
|
@ -102,8 +103,8 @@ impl<H> WorkerSettings<H> {
|
||||||
self.enabled
|
self.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_shared_bytes(&self) -> helpers::SharedBytes {
|
pub fn get_shared_bytes(&self) -> SharedBytes {
|
||||||
helpers::SharedBytes::new(self.bytes.get_bytes(), Rc::clone(&self.bytes))
|
SharedBytes::new(self.bytes.get_bytes(), Rc::clone(&self.bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_http_message(&self) -> helpers::SharedHttpMessage {
|
pub fn get_http_message(&self) -> helpers::SharedHttpMessage {
|
||||||
|
|
115
src/server/shared.rs
Normal file
115
src/server/shared.rs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
use std::mem;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use bytes::BytesMut;
|
||||||
|
|
||||||
|
use body::Binary;
|
||||||
|
|
||||||
|
|
||||||
|
/// Internal use only! unsafe
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct SharedBytesPool(RefCell<VecDeque<Rc<BytesMut>>>);
|
||||||
|
|
||||||
|
impl SharedBytesPool {
|
||||||
|
pub fn new() -> SharedBytesPool {
|
||||||
|
SharedBytesPool(RefCell::new(VecDeque::with_capacity(128)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bytes(&self) -> Rc<BytesMut> {
|
||||||
|
if let Some(bytes) = self.0.borrow_mut().pop_front() {
|
||||||
|
bytes
|
||||||
|
} else {
|
||||||
|
Rc::new(BytesMut::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release_bytes(&self, mut bytes: Rc<BytesMut>) {
|
||||||
|
let v = &mut self.0.borrow_mut();
|
||||||
|
if v.len() < 128 {
|
||||||
|
Rc::get_mut(&mut bytes).unwrap().take();
|
||||||
|
v.push_front(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct SharedBytes(
|
||||||
|
Option<Rc<BytesMut>>, Option<Rc<SharedBytesPool>>);
|
||||||
|
|
||||||
|
impl Drop for SharedBytes {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(ref pool) = self.1 {
|
||||||
|
if let Some(bytes) = self.0.take() {
|
||||||
|
if Rc::strong_count(&bytes) == 1 {
|
||||||
|
pool.release_bytes(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SharedBytes {
|
||||||
|
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
SharedBytes(None, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(bytes: Rc<BytesMut>, pool: Rc<SharedBytesPool>) -> SharedBytes {
|
||||||
|
SharedBytes(Some(bytes), Some(pool))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
#[allow(mutable_transmutes)]
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref, inline_always))]
|
||||||
|
pub fn get_mut(&self) -> &mut BytesMut {
|
||||||
|
let r: &BytesMut = self.0.as_ref().unwrap().as_ref();
|
||||||
|
unsafe{mem::transmute(r)}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.0.as_ref().unwrap().len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.as_ref().unwrap().is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn as_ref(&self) -> &[u8] {
|
||||||
|
self.0.as_ref().unwrap().as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn split_to(&self, n: usize) -> BytesMut {
|
||||||
|
self.get_mut().split_to(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take(&self) -> BytesMut {
|
||||||
|
self.get_mut().take()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
|
||||||
|
pub fn extend(&self, data: Binary) {
|
||||||
|
self.get_mut().extend_from_slice(data.as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn extend_from_slice(&self, data: &[u8]) {
|
||||||
|
self.get_mut().extend_from_slice(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SharedBytes {
|
||||||
|
fn default() -> Self {
|
||||||
|
SharedBytes(Some(Rc::new(BytesMut::new())), None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for SharedBytes {
|
||||||
|
fn clone(&self) -> SharedBytes {
|
||||||
|
SharedBytes(self.0.clone(), self.1.clone())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue