1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-21 15:46:48 +00:00

simplify write buffer

This commit is contained in:
Nikolay Kim 2018-06-24 10:30:58 +06:00
parent 45682c04a8
commit 40ca9ba9c5
11 changed files with 130 additions and 170 deletions

View file

@ -103,6 +103,8 @@ tokio-tls = { version="0.1", optional = true }
openssl = { version="0.10", optional = true } openssl = { version="0.10", optional = true }
tokio-openssl = { version="0.2", optional = true } tokio-openssl = { version="0.2", optional = true }
backtrace="*"
[dev-dependencies] [dev-dependencies]
env_logger = "0.5" env_logger = "0.5"
serde_derive = "1.0" serde_derive = "1.0"

View file

@ -22,7 +22,6 @@ use tokio_io::AsyncWrite;
use body::{Binary, Body}; use body::{Binary, Body};
use header::ContentEncoding; use header::ContentEncoding;
use server::encoding::{ContentEncoder, Output, TransferEncoding}; use server::encoding::{ContentEncoder, Output, TransferEncoding};
use server::shared::SharedBytes;
use server::WriterState; use server::WriterState;
use client::ClientRequest; use client::ClientRequest;
@ -53,7 +52,7 @@ impl HttpClientWriter {
written: 0, written: 0,
headers_size: 0, headers_size: 0,
buffer_capacity: 0, buffer_capacity: 0,
buffer: Output::Buffer(SharedBytes::empty()), buffer: Output::Buffer(BytesMut::new()),
} }
} }
@ -110,6 +109,7 @@ impl<'a> io::Write for Writer<'a> {
impl HttpClientWriter { impl HttpClientWriter {
pub fn start(&mut self, msg: &mut ClientRequest) -> io::Result<()> { pub fn start(&mut self, msg: &mut ClientRequest) -> io::Result<()> {
// prepare task // prepare task
self.buffer = content_encoder(self.buffer.take(), msg);
self.flags.insert(Flags::STARTED); self.flags.insert(Flags::STARTED);
if msg.upgrade() { if msg.upgrade() {
self.flags.insert(Flags::UPGRADE); self.flags.insert(Flags::UPGRADE);
@ -118,7 +118,7 @@ impl HttpClientWriter {
// render message // render message
{ {
// output buffer // output buffer
let buffer = self.buffer.get_mut(); let buffer = self.buffer.as_mut();
// status line // status line
writeln!( writeln!(
@ -160,8 +160,6 @@ impl HttpClientWriter {
} }
self.headers_size = self.buffer.len() as u32; self.headers_size = self.buffer.len() as u32;
self.buffer = content_encoder(self.buffer.take(), msg);
if msg.body().is_binary() { if msg.body().is_binary() {
if let Body::Binary(bytes) = msg.replace_body(Body::Empty) { if let Body::Binary(bytes) = msg.replace_body(Body::Empty) {
self.written += bytes.len() as u64; self.written += bytes.len() as u64;
@ -215,7 +213,7 @@ impl HttpClientWriter {
} }
} }
fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> Output { fn content_encoder(buf: BytesMut, req: &mut ClientRequest) -> Output {
let version = req.version(); let version = req.version();
let mut body = req.replace_body(Body::Empty); let mut body = req.replace_body(Body::Empty);
let mut encoding = req.content_encoding(); let mut encoding = req.content_encoding();
@ -227,7 +225,7 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> Output {
} }
Body::Binary(ref mut bytes) => { Body::Binary(ref mut bytes) => {
if encoding.is_compression() { if encoding.is_compression() {
let mut tmp = SharedBytes::empty(); let mut tmp = BytesMut::new();
let mut transfer = TransferEncoding::eof(tmp); let mut transfer = TransferEncoding::eof(tmp);
let mut enc = match encoding { let mut enc = match encoding {
#[cfg(feature = "flate2")] #[cfg(feature = "flate2")]
@ -308,7 +306,7 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> Output {
} }
fn streaming_encoding( fn streaming_encoding(
buf: SharedBytes, version: Version, req: &mut ClientRequest, buf: BytesMut, version: Version, req: &mut ClientRequest,
) -> TransferEncoding { ) -> TransferEncoding {
if req.chunked() { if req.chunked() {
// Enable transfer encoding // Enable transfer encoding

View file

@ -1127,7 +1127,6 @@ mod tests {
let response = srv.execute(request.send()).unwrap(); let response = srv.execute(request.send()).unwrap();
println!("RESP: {:?}", response);
let te = response let te = response
.headers() .headers()
.get(header::TRANSFER_ENCODING) .get(header::TRANSFER_ENCODING)

View file

@ -1,7 +1,7 @@
use std::fmt::Write as FmtWrite; use std::fmt::Write as FmtWrite;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::str::FromStr; use std::str::FromStr;
use std::{cmp, io, mem}; use std::{cmp, fmt, io, mem};
#[cfg(feature = "brotli")] #[cfg(feature = "brotli")]
use brotli2::write::{BrotliDecoder, BrotliEncoder}; use brotli2::write::{BrotliDecoder, BrotliEncoder};
@ -25,8 +25,6 @@ use httprequest::HttpInnerMessage;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
use payload::{PayloadSender, PayloadStatus, PayloadWriter}; use payload::{PayloadSender, PayloadStatus, PayloadWriter};
use super::shared::SharedBytes;
pub(crate) enum PayloadType { pub(crate) enum PayloadType {
Sender(PayloadSender), Sender(PayloadSender),
Encoding(Box<EncodedPayload>), Encoding(Box<EncodedPayload>),
@ -370,21 +368,34 @@ impl PayloadStream {
} }
} }
#[derive(Debug)]
pub(crate) enum Output { pub(crate) enum Output {
Buffer(SharedBytes), Buffer(BytesMut),
Encoder(ContentEncoder), Encoder(ContentEncoder),
TE(TransferEncoding), TE(TransferEncoding),
Empty, Empty,
} }
impl Output { impl Output {
pub fn take(&mut self) -> SharedBytes { pub fn take(&mut self) -> BytesMut {
match mem::replace(self, Output::Empty) { match mem::replace(self, Output::Empty) {
Output::Buffer(bytes) => bytes, Output::Buffer(bytes) => bytes,
Output::Encoder(mut enc) => enc.take_buf(),
Output::TE(mut te) => te.take(),
_ => panic!(), _ => panic!(),
} }
} }
pub fn as_ref(&mut self) -> &SharedBytes {
pub fn take_option(&mut self) -> Option<BytesMut> {
match mem::replace(self, Output::Empty) {
Output::Buffer(bytes) => Some(bytes),
Output::Encoder(mut enc) => Some(enc.take_buf()),
Output::TE(mut te) => Some(te.take()),
_ => None,
}
}
pub fn as_ref(&mut self) -> &BytesMut {
match self { match self {
Output::Buffer(ref mut bytes) => bytes, Output::Buffer(ref mut bytes) => bytes,
Output::Encoder(ref mut enc) => enc.buf_ref(), Output::Encoder(ref mut enc) => enc.buf_ref(),
@ -392,9 +403,11 @@ impl Output {
Output::Empty => panic!(), Output::Empty => panic!(),
} }
} }
pub fn get_mut(&mut self) -> &mut BytesMut { pub fn as_mut(&mut self) -> &mut BytesMut {
match self { match self {
Output::Buffer(ref mut bytes) => bytes.get_mut(), Output::Buffer(ref mut bytes) => bytes,
Output::Encoder(ref mut enc) => enc.buf_mut(),
Output::TE(ref mut te) => te.buf_mut(),
_ => panic!(), _ => panic!(),
} }
} }
@ -457,9 +470,23 @@ pub(crate) enum ContentEncoder {
Identity(TransferEncoding), Identity(TransferEncoding),
} }
impl fmt::Debug for ContentEncoder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(_) => writeln!(f, "ContentEncoder(Brotli)"),
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(_) => writeln!(f, "ContentEncoder(Deflate)"),
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(_) => writeln!(f, "ContentEncoder(Gzip)"),
ContentEncoder::Identity(_) => writeln!(f, "ContentEncoder(Identity)"),
}
}
}
impl ContentEncoder { impl ContentEncoder {
pub fn for_server( pub fn for_server(
buf: SharedBytes, req: &HttpInnerMessage, resp: &mut HttpResponse, buf: BytesMut, req: &HttpInnerMessage, resp: &mut HttpResponse,
response_encoding: ContentEncoding, response_encoding: ContentEncoding,
) -> Output { ) -> Output {
let version = resp.version().unwrap_or_else(|| req.version); let version = resp.version().unwrap_or_else(|| req.version);
@ -522,7 +549,7 @@ impl ContentEncoder {
if !(encoding == ContentEncoding::Identity if !(encoding == ContentEncoding::Identity
|| encoding == ContentEncoding::Auto) || encoding == ContentEncoding::Auto)
{ {
let mut tmp = SharedBytes::empty(); let mut tmp = BytesMut::new();
let mut transfer = TransferEncoding::eof(tmp); let mut transfer = TransferEncoding::eof(tmp);
let mut enc = match encoding { let mut enc = match encoding {
#[cfg(feature = "flate2")] #[cfg(feature = "flate2")]
@ -613,7 +640,7 @@ impl ContentEncoder {
} }
fn streaming_encoding( fn streaming_encoding(
buf: SharedBytes, version: Version, resp: &mut HttpResponse, buf: BytesMut, version: Version, resp: &mut HttpResponse,
) -> TransferEncoding { ) -> TransferEncoding {
match resp.chunked() { match resp.chunked() {
Some(true) => { Some(true) => {
@ -703,6 +730,19 @@ impl ContentEncoder {
} }
} }
#[inline]
pub(crate) fn take_buf(&mut self) -> BytesMut {
match *self {
#[cfg(feature = "brotli")]
ContentEncoder::Br(ref mut encoder) => encoder.get_mut().take(),
#[cfg(feature = "flate2")]
ContentEncoder::Deflate(ref mut encoder) => encoder.get_mut().take(),
#[cfg(feature = "flate2")]
ContentEncoder::Gzip(ref mut encoder) => encoder.get_mut().take(),
ContentEncoder::Identity(ref mut encoder) => encoder.take(),
}
}
#[inline] #[inline]
pub(crate) fn buf_mut(&mut self) -> &mut BytesMut { pub(crate) fn buf_mut(&mut self) -> &mut BytesMut {
match *self { match *self {
@ -717,7 +757,7 @@ impl ContentEncoder {
} }
#[inline] #[inline]
pub(crate) fn buf_ref(&mut self) -> &SharedBytes { pub(crate) fn buf_ref(&mut self) -> &BytesMut {
match *self { match *self {
#[cfg(feature = "brotli")] #[cfg(feature = "brotli")]
ContentEncoder::Br(ref mut encoder) => encoder.get_mut().buf_ref(), ContentEncoder::Br(ref mut encoder) => encoder.get_mut().buf_ref(),
@ -810,7 +850,7 @@ impl ContentEncoder {
/// Encoders to handle different Transfer-Encodings. /// Encoders to handle different Transfer-Encodings.
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct TransferEncoding { pub(crate) struct TransferEncoding {
buf: Option<SharedBytes>, buf: Option<BytesMut>,
kind: TransferEncodingKind, kind: TransferEncodingKind,
} }
@ -829,11 +869,11 @@ enum TransferEncodingKind {
} }
impl TransferEncoding { impl TransferEncoding {
fn take(self) -> SharedBytes { fn take(&mut self) -> BytesMut {
self.buf.unwrap() self.buf.take().unwrap()
} }
fn buf_ref(&mut self) -> &SharedBytes { fn buf_ref(&mut self) -> &BytesMut {
self.buf.as_ref().unwrap() self.buf.as_ref().unwrap()
} }
@ -846,7 +886,7 @@ impl TransferEncoding {
} }
fn buf_mut(&mut self) -> &mut BytesMut { fn buf_mut(&mut self) -> &mut BytesMut {
self.buf.as_mut().unwrap().get_mut() self.buf.as_mut().unwrap()
} }
#[inline] #[inline]
@ -858,7 +898,7 @@ impl TransferEncoding {
} }
#[inline] #[inline]
pub fn eof(buf: SharedBytes) -> TransferEncoding { pub fn eof(buf: BytesMut) -> TransferEncoding {
TransferEncoding { TransferEncoding {
buf: Some(buf), buf: Some(buf),
kind: TransferEncodingKind::Eof, kind: TransferEncodingKind::Eof,
@ -866,7 +906,7 @@ impl TransferEncoding {
} }
#[inline] #[inline]
pub fn chunked(buf: SharedBytes) -> TransferEncoding { pub fn chunked(buf: BytesMut) -> TransferEncoding {
TransferEncoding { TransferEncoding {
buf: Some(buf), buf: Some(buf),
kind: TransferEncodingKind::Chunked(false), kind: TransferEncodingKind::Chunked(false),
@ -874,7 +914,7 @@ impl TransferEncoding {
} }
#[inline] #[inline]
pub fn length(len: u64, buf: SharedBytes) -> TransferEncoding { pub fn length(len: u64, buf: BytesMut) -> TransferEncoding {
TransferEncoding { TransferEncoding {
buf: Some(buf), buf: Some(buf),
kind: TransferEncodingKind::Length(len), kind: TransferEncodingKind::Length(len),
@ -1034,7 +1074,7 @@ mod tests {
#[test] #[test]
fn test_chunked_te() { fn test_chunked_te() {
let bytes = SharedBytes::empty(); let bytes = BytesMut::new();
let mut enc = TransferEncoding::chunked(bytes); let mut enc = TransferEncoding::chunked(bytes);
{ {
assert!(!enc.encode(b"test").ok().unwrap()); assert!(!enc.encode(b"test").ok().unwrap());

View file

@ -93,10 +93,9 @@ where
settings: Rc<WorkerSettings<H>>, stream: T, addr: Option<SocketAddr>, settings: Rc<WorkerSettings<H>>, stream: T, addr: Option<SocketAddr>,
buf: BytesMut, buf: BytesMut,
) -> Self { ) -> Self {
let bytes = settings.get_shared_bytes();
Http1 { Http1 {
flags: Flags::KEEPALIVE, flags: Flags::KEEPALIVE,
stream: H1Writer::new(stream, bytes, Rc::clone(&settings)), stream: H1Writer::new(stream, Rc::clone(&settings)),
decoder: H1Decoder::new(), decoder: H1Decoder::new(),
payload: None, payload: None,
tasks: VecDeque::new(), tasks: VecDeque::new(),

View file

@ -9,7 +9,6 @@ use tokio_io::AsyncWrite;
use super::encoding::{ContentEncoder, Output}; use super::encoding::{ContentEncoder, Output};
use super::helpers; use super::helpers;
use super::settings::WorkerSettings; use super::settings::WorkerSettings;
use super::shared::SharedBytes;
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE}; use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
use body::{Binary, Body}; use body::{Binary, Body};
use header::ContentEncoding; use header::ContentEncoding;
@ -40,14 +39,12 @@ pub(crate) struct H1Writer<T: AsyncWrite, H: 'static> {
} }
impl<T: AsyncWrite, H: 'static> H1Writer<T, H> { impl<T: AsyncWrite, H: 'static> H1Writer<T, H> {
pub fn new( pub fn new(stream: T, settings: Rc<WorkerSettings<H>>) -> H1Writer<T, H> {
stream: T, buf: SharedBytes, settings: Rc<WorkerSettings<H>>,
) -> H1Writer<T, H> {
H1Writer { H1Writer {
flags: Flags::KEEPALIVE, flags: Flags::KEEPALIVE,
written: 0, written: 0,
headers_size: 0, headers_size: 0,
buffer: Output::Buffer(buf), buffer: Output::Buffer(settings.get_bytes()),
buffer_capacity: 0, buffer_capacity: 0,
stream, stream,
settings, settings,
@ -91,6 +88,14 @@ impl<T: AsyncWrite, H: 'static> H1Writer<T, H> {
} }
} }
impl<T: AsyncWrite, H: 'static> Drop for H1Writer<T, H> {
fn drop(&mut self) {
if let Some(bytes) = self.buffer.take_option() {
self.settings.release_bytes(bytes);
}
}
}
impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> { impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
#[inline] #[inline]
fn written(&self) -> u64 { fn written(&self) -> u64 {
@ -104,8 +109,7 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
#[inline] #[inline]
fn buffer(&mut self) -> &mut BytesMut { fn buffer(&mut self) -> &mut BytesMut {
//self.buffer.get_mut() self.buffer.as_mut()
unimplemented!()
} }
fn start( fn start(
@ -113,6 +117,7 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
encoding: ContentEncoding, encoding: ContentEncoding,
) -> io::Result<WriterState> { ) -> io::Result<WriterState> {
// prepare task // prepare task
self.buffer = ContentEncoder::for_server(self.buffer.take(), req, msg, encoding);
if msg.keep_alive().unwrap_or_else(|| req.keep_alive()) { if msg.keep_alive().unwrap_or_else(|| req.keep_alive()) {
self.flags = Flags::STARTED | Flags::KEEPALIVE; self.flags = Flags::STARTED | Flags::KEEPALIVE;
} else { } else {
@ -141,7 +146,7 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
// render message // render message
{ {
// output buffer // output buffer
let mut buffer = self.buffer.get_mut(); let mut buffer = self.buffer.as_mut();
let reason = msg.reason().as_bytes(); let reason = msg.reason().as_bytes();
let mut is_bin = if let Body::Binary(ref bytes) = body { let mut is_bin = if let Body::Binary(ref bytes) = body {
@ -221,9 +226,6 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
self.headers_size = buffer.len() as u32; self.headers_size = buffer.len() as u32;
} }
// output encoding
self.buffer = ContentEncoder::for_server(self.buffer.take(), req, msg, encoding);
if let Body::Binary(bytes) = body { if let Body::Binary(bytes) = body {
self.written = bytes.len() as u64; self.written = bytes.len() as u64;
self.buffer.write(bytes.as_ref())?; self.buffer.write(bytes.as_ref())?;
@ -255,11 +257,11 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
Ok(val) => val, Ok(val) => val,
}; };
if n < pl.len() { if n < pl.len() {
self.buffer.write(&pl[n..]); self.buffer.write(&pl[n..])?;
return Ok(WriterState::Done); return Ok(WriterState::Done);
} }
} else { } else {
self.buffer.write(payload.as_ref()); self.buffer.write(payload.as_ref())?;
} }
} else { } else {
// TODO: add warning, write after EOF // TODO: add warning, write after EOF
@ -267,7 +269,7 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
} }
} else { } else {
// could be response to EXCEPT header // could be response to EXCEPT header
self.buffer.write(payload.as_ref()); self.buffer.write(payload.as_ref())?;
} }
} }

View file

@ -363,11 +363,7 @@ impl<H: HttpHandler + 'static> Entry<H> {
EntryPipe::Error(Pipeline::error(HttpResponse::NotFound())) EntryPipe::Error(Pipeline::error(HttpResponse::NotFound()))
}), }),
payload: psender, payload: psender,
stream: H2Writer::new( stream: H2Writer::new(resp, Rc::clone(settings)),
resp,
settings.get_shared_bytes(),
Rc::clone(settings),
),
flags: EntryFlags::empty(), flags: EntryFlags::empty(),
recv, recv,
} }

View file

@ -14,7 +14,6 @@ use http::{HttpTryFrom, Version};
use super::encoding::{ContentEncoder, Output}; use super::encoding::{ContentEncoder, Output};
use super::helpers; use super::helpers;
use super::settings::WorkerSettings; use super::settings::WorkerSettings;
use super::shared::SharedBytes;
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE}; use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
use body::{Binary, Body}; use body::{Binary, Body};
use header::ContentEncoding; use header::ContentEncoding;
@ -44,16 +43,16 @@ pub(crate) struct H2Writer<H: 'static> {
impl<H: 'static> H2Writer<H> { impl<H: 'static> H2Writer<H> {
pub fn new( pub fn new(
respond: SendResponse<Bytes>, buf: SharedBytes, settings: Rc<WorkerSettings<H>>, respond: SendResponse<Bytes>, settings: Rc<WorkerSettings<H>>,
) -> H2Writer<H> { ) -> H2Writer<H> {
H2Writer { H2Writer {
respond,
settings,
stream: None, stream: None,
flags: Flags::empty(), flags: Flags::empty(),
written: 0, written: 0,
buffer: Output::Buffer(buf), buffer: Output::Buffer(settings.get_bytes()),
buffer_capacity: 0, buffer_capacity: 0,
respond,
settings,
} }
} }
@ -64,6 +63,12 @@ impl<H: 'static> H2Writer<H> {
} }
} }
impl<H: 'static> Drop for H2Writer<H> {
fn drop(&mut self) {
self.settings.release_bytes(self.buffer.take());
}
}
impl<H: 'static> Writer for H2Writer<H> { impl<H: 'static> Writer for H2Writer<H> {
fn written(&self) -> u64 { fn written(&self) -> u64 {
self.written self.written
@ -76,7 +81,7 @@ impl<H: 'static> Writer for H2Writer<H> {
#[inline] #[inline]
fn buffer(&mut self) -> &mut BytesMut { fn buffer(&mut self) -> &mut BytesMut {
self.buffer.get_mut() self.buffer.as_mut()
} }
fn start( fn start(

View file

@ -16,7 +16,6 @@ mod h2;
mod h2writer; mod h2writer;
pub(crate) mod helpers; pub(crate) mod helpers;
pub(crate) mod settings; pub(crate) mod settings;
pub(crate) mod shared;
mod srv; mod srv;
mod worker; mod worker;

View file

@ -1,4 +1,5 @@
use std::cell::{Cell, RefCell, RefMut, UnsafeCell}; use std::cell::{Cell, RefCell, RefMut, UnsafeCell};
use std::collections::VecDeque;
use std::fmt::Write; use std::fmt::Write;
use std::rc::Rc; use std::rc::Rc;
use std::{env, fmt, mem, net}; use std::{env, fmt, mem, net};
@ -11,7 +12,6 @@ use time;
use super::channel::Node; use super::channel::Node;
use super::helpers; use super::helpers;
use super::shared::{SharedBytes, SharedBytesPool};
use super::KeepAlive; use super::KeepAlive;
use body::Body; use body::Body;
use httpresponse::{HttpResponse, HttpResponseBuilder, HttpResponsePool}; use httpresponse::{HttpResponse, HttpResponseBuilder, HttpResponsePool};
@ -201,8 +201,12 @@ impl<H> WorkerSettings<H> {
self.ka_enabled self.ka_enabled
} }
pub fn get_shared_bytes(&self) -> SharedBytes { pub fn get_bytes(&self) -> BytesMut {
SharedBytes::new(self.bytes.get_bytes(), Rc::clone(&self.bytes)) self.bytes.get_bytes()
}
pub fn release_bytes(&self, bytes: BytesMut) {
self.bytes.release_bytes(bytes)
} }
pub fn get_http_message(&self) -> helpers::SharedHttpInnerMessage { pub fn get_http_message(&self) -> helpers::SharedHttpInnerMessage {
@ -273,6 +277,31 @@ impl fmt::Write for Date {
} }
} }
#[derive(Debug)]
pub(crate) struct SharedBytesPool(RefCell<VecDeque<BytesMut>>);
impl SharedBytesPool {
pub fn new() -> SharedBytesPool {
SharedBytesPool(RefCell::new(VecDeque::with_capacity(128)))
}
pub fn get_bytes(&self) -> BytesMut {
if let Some(bytes) = self.0.borrow_mut().pop_front() {
bytes
} else {
BytesMut::new()
}
}
pub fn release_bytes(&self, mut bytes: BytesMut) {
let v = &mut self.0.borrow_mut();
if v.len() < 128 {
bytes.clear();
v.push_front(bytes);
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -1,109 +0,0 @@
use std::cell::RefCell;
use std::collections::VecDeque;
use std::io;
use std::rc::Rc;
use bytes::BytesMut;
#[derive(Debug)]
pub(crate) struct SharedBytesPool(RefCell<VecDeque<BytesMut>>);
impl SharedBytesPool {
pub fn new() -> SharedBytesPool {
SharedBytesPool(RefCell::new(VecDeque::with_capacity(128)))
}
pub fn get_bytes(&self) -> BytesMut {
if let Some(bytes) = self.0.borrow_mut().pop_front() {
bytes
} else {
BytesMut::new()
}
}
pub fn release_bytes(&self, mut bytes: BytesMut) {
let v = &mut self.0.borrow_mut();
if v.len() < 128 {
bytes.clear();
v.push_front(bytes);
}
}
}
#[derive(Debug)]
pub(crate) struct SharedBytes(Option<BytesMut>, Option<Rc<SharedBytesPool>>);
impl Drop for SharedBytes {
fn drop(&mut self) {
if let Some(pool) = self.1.take() {
if let Some(bytes) = self.0.take() {
pool.release_bytes(bytes);
}
}
}
}
impl SharedBytes {
pub fn new(bytes: BytesMut, pool: Rc<SharedBytesPool>) -> SharedBytes {
SharedBytes(Some(bytes), Some(pool))
}
pub fn empty() -> SharedBytes {
SharedBytes(Some(BytesMut::new()), None)
}
#[inline]
pub(crate) fn get_mut(&mut self) -> &mut BytesMut {
self.0.as_mut().unwrap()
}
#[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(&mut self, n: usize) -> BytesMut {
self.get_mut().split_to(n)
}
pub fn take(&mut self) -> BytesMut {
self.get_mut().take()
}
#[inline]
pub fn reserve(&mut self, cap: usize) {
self.get_mut().reserve(cap);
}
#[inline]
pub fn extend_from_slice(&mut self, data: &[u8]) {
let buf = self.get_mut();
buf.extend_from_slice(data);
}
}
impl Default for SharedBytes {
fn default() -> Self {
SharedBytes(Some(BytesMut::new()), None)
}
}
impl io::Write for SharedBytes {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}