From 800c404c72a254ebac67b04b3588c6dae19f3a53 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 25 Jun 2018 10:10:02 +0600 Subject: [PATCH] explicit response release --- src/httpresponse.rs | 53 ++++++++++++++++++++++++++------------------- src/pipeline.rs | 34 ++++++++++++----------------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/httpresponse.rs b/src/httpresponse.rs index 7ed82a8d1..3f6dce76c 100644 --- a/src/httpresponse.rs +++ b/src/httpresponse.rs @@ -35,7 +35,7 @@ pub enum ConnectionType { } /// An HTTP Response -pub struct HttpResponse(Box); +pub struct HttpResponse(Box, &'static HttpResponsePool); impl HttpResponse { #[inline] @@ -96,6 +96,7 @@ impl HttpResponse { } HttpResponseBuilder { + pool: self.1, response: Some(self.0), err: None, cookies: jar, @@ -282,12 +283,19 @@ impl HttpResponse { self.get_mut().write_capacity = cap; } + pub(crate) fn release(self) { + self.1.release(self.0); + } + pub(crate) fn into_parts(self) -> HttpResponseParts { self.0.into_parts() } pub(crate) fn from_parts(parts: HttpResponseParts) -> HttpResponse { - HttpResponse(Box::new(InnerHttpResponse::from_parts(parts))) + HttpResponse( + Box::new(InnerHttpResponse::from_parts(parts)), + HttpResponsePool::get_pool(), + ) } } @@ -332,6 +340,7 @@ impl<'a> Iterator for CookieIter<'a> { /// This type can be used to construct an instance of `HttpResponse` through a /// builder-like pattern. pub struct HttpResponseBuilder { + pool: &'static HttpResponsePool, response: Option>, err: Option, cookies: Option, @@ -622,7 +631,7 @@ impl HttpResponseBuilder { } } response.body = body.into(); - HttpResponse(response) + HttpResponse(response, self.pool) } #[inline] @@ -670,6 +679,7 @@ impl HttpResponseBuilder { /// This method construct new `HttpResponseBuilder` pub fn take(&mut self) -> HttpResponseBuilder { HttpResponseBuilder { + pool: self.pool, response: self.response.take(), err: self.err.take(), cookies: self.cookies.take(), @@ -972,6 +982,7 @@ impl HttpResponsePool { if let Some(mut msg) = pool.0.borrow_mut().pop_front() { msg.status = status; HttpResponseBuilder { + pool, response: Some(msg), err: None, cookies: None, @@ -979,6 +990,7 @@ impl HttpResponsePool { } else { let msg = Box::new(InnerHttpResponse::new(status, Body::Empty)); HttpResponseBuilder { + pool, response: Some(msg), err: None, cookies: None, @@ -993,10 +1005,10 @@ impl HttpResponsePool { if let Some(mut msg) = pool.0.borrow_mut().pop_front() { msg.status = status; msg.body = body; - HttpResponse(msg) + HttpResponse(msg, pool) } else { let msg = Box::new(InnerHttpResponse::new(status, body)); - HttpResponse(msg) + HttpResponse(msg, pool) } } @@ -1011,23 +1023,20 @@ impl HttpResponsePool { } #[inline] - pub(crate) fn release(resp: HttpResponse) { - let mut inner = resp.0; - POOL.with(|pool| { - let mut p = pool.0.borrow_mut(); - if p.len() < 128 { - inner.headers.clear(); - inner.version = None; - inner.chunked = None; - inner.reason = None; - inner.encoding = None; - inner.connection_type = None; - inner.response_size = 0; - inner.error = None; - inner.write_capacity = MAX_WRITE_BUFFER_SIZE; - p.push_front(inner); - } - }); + fn release(&self, mut inner: Box) { + let mut p = self.0.borrow_mut(); + if p.len() < 128 { + inner.headers.clear(); + inner.version = None; + inner.chunked = None; + inner.reason = None; + inner.encoding = None; + inner.connection_type = None; + inner.response_size = 0; + inner.error = None; + inner.write_capacity = MAX_WRITE_BUFFER_SIZE; + p.push_front(inner); + } } } diff --git a/src/pipeline.rs b/src/pipeline.rs index 9f38f768d..192759442 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -13,7 +13,7 @@ use error::Error; use handler::{AsyncResult, AsyncResultItem}; use header::ContentEncoding; use httprequest::HttpRequest; -use httpresponse::{HttpResponse, HttpResponsePool}; +use httpresponse::HttpResponse; use middleware::{Finished, Middleware, Response, Started}; use server::{HttpHandlerTask, Writer, WriterState}; @@ -703,7 +703,8 @@ impl FinishingMiddlewares { info: &mut PipelineInfo, mws: &[Box>], resp: HttpResponse, ) -> PipelineState { if info.count == 0 { - Completed::init(info, resp) + resp.release(); + Completed::init(info) } else { let mut state = FinishingMiddlewares { resp: Some(resp), @@ -741,7 +742,8 @@ impl FinishingMiddlewares { } self.fut = None; if info.count == 0 { - return Some(Completed::init(info, self.resp.take().unwrap())); + self.resp.take().unwrap().release(); + return Some(Completed::init(info)); } info.count -= 1; @@ -750,7 +752,8 @@ impl FinishingMiddlewares { match state { Finished::Done => { if info.count == 0 { - return Some(Completed::init(info, self.resp.take().unwrap())); + self.resp.take().unwrap().release(); + return Some(Completed::init(info)); } } Finished::Future(fut) => { @@ -762,20 +765,19 @@ impl FinishingMiddlewares { } #[derive(Debug)] -struct Completed(PhantomData, PhantomData, Option); +struct Completed(PhantomData, PhantomData); impl Completed { #[inline] - fn init(info: &mut PipelineInfo, resp: HttpResponse) -> PipelineState { + fn init(info: &mut PipelineInfo) -> PipelineState { if let Some(ref err) = info.error { error!("Error occurred during request handling: {}", err); } if info.context.is_none() { - HttpResponsePool::release(resp); PipelineState::None } else { - PipelineState::Completed(Completed(PhantomData, PhantomData, Some(resp))) + PipelineState::Completed(Completed(PhantomData, PhantomData)) } } @@ -783,14 +785,8 @@ impl Completed { fn poll(&mut self, info: &mut PipelineInfo) -> Option> { match info.poll_context() { Ok(Async::NotReady) => None, - Ok(Async::Ready(())) => { - HttpResponsePool::release(self.2.take().unwrap()); - Some(PipelineState::None) - } - Err(_) => { - HttpResponsePool::release(self.2.take().unwrap()); - Some(PipelineState::Error) - } + Ok(Async::Ready(())) => Some(PipelineState::None), + Err(_) => Some(PipelineState::Error), } } } @@ -832,18 +828,16 @@ mod tests { .unwrap() .block_on(lazy(|| { let mut info = PipelineInfo::new(HttpRequest::default()); - let resp = HttpResponse::new(StatusCode::OK); - Completed::<(), Inner<()>>::init(&mut info, resp) + Completed::<(), Inner<()>>::init(&mut info) .is_none() .unwrap(); let req = HttpRequest::default(); let ctx = HttpContext::new(req.clone(), MyActor); let addr = ctx.address(); - let resp = HttpResponse::new(StatusCode::OK); let mut info = PipelineInfo::new(req); info.context = Some(Box::new(ctx)); - let mut state = Completed::<(), Inner<()>>::init(&mut info, resp) + let mut state = Completed::<(), Inner<()>>::init(&mut info) .completed() .unwrap();