1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-22 08:07:18 +00:00

explicit response release

This commit is contained in:
Nikolay Kim 2018-06-25 10:10:02 +06:00
parent 32212bad1f
commit 800c404c72
2 changed files with 45 additions and 42 deletions

View file

@ -35,7 +35,7 @@ pub enum ConnectionType {
} }
/// An HTTP Response /// An HTTP Response
pub struct HttpResponse(Box<InnerHttpResponse>); pub struct HttpResponse(Box<InnerHttpResponse>, &'static HttpResponsePool);
impl HttpResponse { impl HttpResponse {
#[inline] #[inline]
@ -96,6 +96,7 @@ impl HttpResponse {
} }
HttpResponseBuilder { HttpResponseBuilder {
pool: self.1,
response: Some(self.0), response: Some(self.0),
err: None, err: None,
cookies: jar, cookies: jar,
@ -282,12 +283,19 @@ impl HttpResponse {
self.get_mut().write_capacity = cap; self.get_mut().write_capacity = cap;
} }
pub(crate) fn release(self) {
self.1.release(self.0);
}
pub(crate) fn into_parts(self) -> HttpResponseParts { pub(crate) fn into_parts(self) -> HttpResponseParts {
self.0.into_parts() self.0.into_parts()
} }
pub(crate) fn from_parts(parts: HttpResponseParts) -> HttpResponse { 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 /// This type can be used to construct an instance of `HttpResponse` through a
/// builder-like pattern. /// builder-like pattern.
pub struct HttpResponseBuilder { pub struct HttpResponseBuilder {
pool: &'static HttpResponsePool,
response: Option<Box<InnerHttpResponse>>, response: Option<Box<InnerHttpResponse>>,
err: Option<HttpError>, err: Option<HttpError>,
cookies: Option<CookieJar>, cookies: Option<CookieJar>,
@ -622,7 +631,7 @@ impl HttpResponseBuilder {
} }
} }
response.body = body.into(); response.body = body.into();
HttpResponse(response) HttpResponse(response, self.pool)
} }
#[inline] #[inline]
@ -670,6 +679,7 @@ impl HttpResponseBuilder {
/// This method construct new `HttpResponseBuilder` /// This method construct new `HttpResponseBuilder`
pub fn take(&mut self) -> HttpResponseBuilder { pub fn take(&mut self) -> HttpResponseBuilder {
HttpResponseBuilder { HttpResponseBuilder {
pool: self.pool,
response: self.response.take(), response: self.response.take(),
err: self.err.take(), err: self.err.take(),
cookies: self.cookies.take(), cookies: self.cookies.take(),
@ -972,6 +982,7 @@ impl HttpResponsePool {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() { if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
msg.status = status; msg.status = status;
HttpResponseBuilder { HttpResponseBuilder {
pool,
response: Some(msg), response: Some(msg),
err: None, err: None,
cookies: None, cookies: None,
@ -979,6 +990,7 @@ impl HttpResponsePool {
} else { } else {
let msg = Box::new(InnerHttpResponse::new(status, Body::Empty)); let msg = Box::new(InnerHttpResponse::new(status, Body::Empty));
HttpResponseBuilder { HttpResponseBuilder {
pool,
response: Some(msg), response: Some(msg),
err: None, err: None,
cookies: None, cookies: None,
@ -993,10 +1005,10 @@ impl HttpResponsePool {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() { if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
msg.status = status; msg.status = status;
msg.body = body; msg.body = body;
HttpResponse(msg) HttpResponse(msg, pool)
} else { } else {
let msg = Box::new(InnerHttpResponse::new(status, body)); let msg = Box::new(InnerHttpResponse::new(status, body));
HttpResponse(msg) HttpResponse(msg, pool)
} }
} }
@ -1011,10 +1023,8 @@ impl HttpResponsePool {
} }
#[inline] #[inline]
pub(crate) fn release(resp: HttpResponse) { fn release(&self, mut inner: Box<InnerHttpResponse>) {
let mut inner = resp.0; let mut p = self.0.borrow_mut();
POOL.with(|pool| {
let mut p = pool.0.borrow_mut();
if p.len() < 128 { if p.len() < 128 {
inner.headers.clear(); inner.headers.clear();
inner.version = None; inner.version = None;
@ -1027,7 +1037,6 @@ impl HttpResponsePool {
inner.write_capacity = MAX_WRITE_BUFFER_SIZE; inner.write_capacity = MAX_WRITE_BUFFER_SIZE;
p.push_front(inner); p.push_front(inner);
} }
});
} }
} }

View file

@ -13,7 +13,7 @@ use error::Error;
use handler::{AsyncResult, AsyncResultItem}; use handler::{AsyncResult, AsyncResultItem};
use header::ContentEncoding; use header::ContentEncoding;
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::{HttpResponse, HttpResponsePool}; use httpresponse::HttpResponse;
use middleware::{Finished, Middleware, Response, Started}; use middleware::{Finished, Middleware, Response, Started};
use server::{HttpHandlerTask, Writer, WriterState}; use server::{HttpHandlerTask, Writer, WriterState};
@ -703,7 +703,8 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
info: &mut PipelineInfo<S>, mws: &[Box<Middleware<S>>], resp: HttpResponse, info: &mut PipelineInfo<S>, mws: &[Box<Middleware<S>>], resp: HttpResponse,
) -> PipelineState<S, H> { ) -> PipelineState<S, H> {
if info.count == 0 { if info.count == 0 {
Completed::init(info, resp) resp.release();
Completed::init(info)
} else { } else {
let mut state = FinishingMiddlewares { let mut state = FinishingMiddlewares {
resp: Some(resp), resp: Some(resp),
@ -741,7 +742,8 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
} }
self.fut = None; self.fut = None;
if info.count == 0 { 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; info.count -= 1;
@ -750,7 +752,8 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
match state { match state {
Finished::Done => { Finished::Done => {
if info.count == 0 { 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) => { Finished::Future(fut) => {
@ -762,20 +765,19 @@ impl<S: 'static, H> FinishingMiddlewares<S, H> {
} }
#[derive(Debug)] #[derive(Debug)]
struct Completed<S, H>(PhantomData<S>, PhantomData<H>, Option<HttpResponse>); struct Completed<S, H>(PhantomData<S>, PhantomData<H>);
impl<S, H> Completed<S, H> { impl<S, H> Completed<S, H> {
#[inline] #[inline]
fn init(info: &mut PipelineInfo<S>, resp: HttpResponse) -> PipelineState<S, H> { fn init(info: &mut PipelineInfo<S>) -> PipelineState<S, H> {
if let Some(ref err) = info.error { if let Some(ref err) = info.error {
error!("Error occurred during request handling: {}", err); error!("Error occurred during request handling: {}", err);
} }
if info.context.is_none() { if info.context.is_none() {
HttpResponsePool::release(resp);
PipelineState::None PipelineState::None
} else { } else {
PipelineState::Completed(Completed(PhantomData, PhantomData, Some(resp))) PipelineState::Completed(Completed(PhantomData, PhantomData))
} }
} }
@ -783,14 +785,8 @@ impl<S, H> Completed<S, H> {
fn poll(&mut self, info: &mut PipelineInfo<S>) -> Option<PipelineState<S, H>> { fn poll(&mut self, info: &mut PipelineInfo<S>) -> Option<PipelineState<S, H>> {
match info.poll_context() { match info.poll_context() {
Ok(Async::NotReady) => None, Ok(Async::NotReady) => None,
Ok(Async::Ready(())) => { Ok(Async::Ready(())) => Some(PipelineState::None),
HttpResponsePool::release(self.2.take().unwrap()); Err(_) => Some(PipelineState::Error),
Some(PipelineState::None)
}
Err(_) => {
HttpResponsePool::release(self.2.take().unwrap());
Some(PipelineState::Error)
}
} }
} }
} }
@ -832,18 +828,16 @@ mod tests {
.unwrap() .unwrap()
.block_on(lazy(|| { .block_on(lazy(|| {
let mut info = PipelineInfo::new(HttpRequest::default()); let mut info = PipelineInfo::new(HttpRequest::default());
let resp = HttpResponse::new(StatusCode::OK); Completed::<(), Inner<()>>::init(&mut info)
Completed::<(), Inner<()>>::init(&mut info, resp)
.is_none() .is_none()
.unwrap(); .unwrap();
let req = HttpRequest::default(); let req = HttpRequest::default();
let ctx = HttpContext::new(req.clone(), MyActor); let ctx = HttpContext::new(req.clone(), MyActor);
let addr = ctx.address(); let addr = ctx.address();
let resp = HttpResponse::new(StatusCode::OK);
let mut info = PipelineInfo::new(req); let mut info = PipelineInfo::new(req);
info.context = Some(Box::new(ctx)); info.context = Some(Box::new(ctx));
let mut state = Completed::<(), Inner<()>>::init(&mut info, resp) let mut state = Completed::<(), Inner<()>>::init(&mut info)
.completed() .completed()
.unwrap(); .unwrap();