use a non leak pool for HttpRequestInner

This commit is contained in:
fakeshadow 2021-01-08 19:51:16 +08:00
parent 188ee44f81
commit 9936cd5bcd
4 changed files with 56 additions and 26 deletions

View File

@ -13,7 +13,7 @@ use crate::config::{AppConfig, AppService};
use crate::data::{DataFactory, FnDataFactory}; use crate::data::{DataFactory, FnDataFactory};
use crate::error::Error; use crate::error::Error;
use crate::guard::Guard; use crate::guard::Guard;
use crate::request::{HttpRequest, HttpRequestPool}; use crate::request::HttpRequest;
use crate::rmap::ResourceMap; use crate::rmap::ResourceMap;
use crate::service::{AppServiceFactory, ServiceRequest, ServiceResponse}; use crate::service::{AppServiceFactory, ServiceRequest, ServiceResponse};
@ -144,7 +144,6 @@ where
rmap, rmap,
config, config,
app_data: Rc::new(app_data), app_data: Rc::new(app_data),
pool: HttpRequestPool::create(),
}) })
}) })
} }
@ -159,7 +158,6 @@ where
rmap: Rc<ResourceMap>, rmap: Rc<ResourceMap>,
config: AppConfig, config: AppConfig,
app_data: Rc<Extensions>, app_data: Rc<Extensions>,
pool: &'static HttpRequestPool,
} }
impl<T, B> Service<Request> for AppInitService<T, B> impl<T, B> Service<Request> for AppInitService<T, B>
@ -177,7 +175,7 @@ where
fn call(&mut self, req: Request) -> Self::Future { fn call(&mut self, req: Request) -> Self::Future {
let (head, payload) = req.into_parts(); let (head, payload) = req.into_parts();
let req = if let Some(mut req) = self.pool.get_request() { let req = if let Some(mut req) = self.config.pool().get() {
let inner = Rc::get_mut(&mut req.inner).unwrap(); let inner = Rc::get_mut(&mut req.inner).unwrap();
inner.path.get_mut().update(&head.uri); inner.path.get_mut().update(&head.uri);
inner.path.reset(); inner.path.reset();
@ -192,19 +190,19 @@ where
self.rmap.clone(), self.rmap.clone(),
self.config.clone(), self.config.clone(),
self.app_data.clone(), self.app_data.clone(),
self.pool,
) )
}; };
self.service.call(ServiceRequest::new(req)) self.service.call(ServiceRequest::new(req))
} }
} }
// TODO: remove the drop impl as pool is not leaked anymore.
impl<T, B> Drop for AppInitService<T, B> impl<T, B> Drop for AppInitService<T, B>
where where
T: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, T: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{ {
fn drop(&mut self) { fn drop(&mut self) {
self.pool.clear(); self.config.pool().clear();
} }
} }

View File

@ -8,6 +8,7 @@ use actix_service::{boxed, IntoServiceFactory, ServiceFactory};
use crate::data::{Data, DataFactory}; use crate::data::{Data, DataFactory};
use crate::error::Error; use crate::error::Error;
use crate::guard::Guard; use crate::guard::Guard;
use crate::request::HttpRequestPool;
use crate::resource::Resource; use crate::resource::Resource;
use crate::rmap::ResourceMap; use crate::rmap::ResourceMap;
use crate::route::Route; use crate::route::Route;
@ -131,11 +132,17 @@ struct AppConfigInner {
secure: bool, secure: bool,
host: String, host: String,
addr: SocketAddr, addr: SocketAddr,
pool: HttpRequestPool,
} }
impl AppConfig { impl AppConfig {
pub(crate) fn new(secure: bool, addr: SocketAddr, host: String) -> Self { pub(crate) fn new(secure: bool, addr: SocketAddr, host: String) -> Self {
AppConfig(Rc::new(AppConfigInner { secure, addr, host })) AppConfig(Rc::new(AppConfigInner {
secure,
addr,
host,
pool: HttpRequestPool::default(),
}))
} }
/// Server host name. /// Server host name.
@ -158,6 +165,11 @@ impl AppConfig {
pub fn local_addr(&self) -> SocketAddr { pub fn local_addr(&self) -> SocketAddr {
self.0.addr self.0.addr
} }
#[inline]
pub(crate) fn pool(&self) -> &HttpRequestPool {
&self.0.pool
}
} }
impl Default for AppConfig { impl Default for AppConfig {

View File

@ -30,7 +30,6 @@ pub(crate) struct HttpRequestInner {
pub(crate) app_data: SmallVec<[Rc<Extensions>; 4]>, pub(crate) app_data: SmallVec<[Rc<Extensions>; 4]>,
rmap: Rc<ResourceMap>, rmap: Rc<ResourceMap>,
config: AppConfig, config: AppConfig,
pool: &'static HttpRequestPool,
} }
impl HttpRequest { impl HttpRequest {
@ -42,7 +41,6 @@ impl HttpRequest {
rmap: Rc<ResourceMap>, rmap: Rc<ResourceMap>,
config: AppConfig, config: AppConfig,
app_data: Rc<Extensions>, app_data: Rc<Extensions>,
pool: &'static HttpRequestPool,
) -> HttpRequest { ) -> HttpRequest {
let mut data = SmallVec::<[Rc<Extensions>; 4]>::new(); let mut data = SmallVec::<[Rc<Extensions>; 4]>::new();
data.push(app_data); data.push(app_data);
@ -55,7 +53,6 @@ impl HttpRequest {
rmap, rmap,
config, config,
app_data: data, app_data: data,
pool,
}), }),
} }
} }
@ -287,14 +284,16 @@ impl Drop for HttpRequest {
// This relies on no Weak<HttpRequestInner> exists anywhere.(There is none) // This relies on no Weak<HttpRequestInner> exists anywhere.(There is none)
if let Some(inner) = Rc::get_mut(&mut self.inner) { if let Some(inner) = Rc::get_mut(&mut self.inner) {
let v = &mut inner.pool.0.borrow_mut(); if inner.config.pool().is_available() {
if v.len() < 128 {
// clear additional app_data and keep the root one for reuse. // clear additional app_data and keep the root one for reuse.
inner.app_data.truncate(1); inner.app_data.truncate(1);
// inner is borrowed mut here. get head's Extension mutably // inner is borrowed mut here. get head's Extension mutably
// to reduce borrow check // to reduce borrow check
inner.head.extensions.get_mut().clear(); inner.head.extensions.get_mut().clear();
v.push(self.inner.clone());
// a re-borrow of pool is necessary here.
let req = self.inner.clone();
self.inner.config.pool().push(req);
} }
} }
} }
@ -363,25 +362,50 @@ impl fmt::Debug for HttpRequest {
/// Request objects are added when they are dropped (see `<HttpRequest as Drop>::drop`) and re-used /// Request objects are added when they are dropped (see `<HttpRequest as Drop>::drop`) and re-used
/// in `<AppInitService as Service>::call` when there are available objects in the list. /// in `<AppInitService as Service>::call` when there are available objects in the list.
/// ///
/// The pool's initial capacity is 128 items. /// The pool's default capacity is 128 items.
pub(crate) struct HttpRequestPool(RefCell<Vec<Rc<HttpRequestInner>>>); pub(crate) struct HttpRequestPool {
inner: RefCell<Vec<Rc<HttpRequestInner>>>,
cap: usize,
}
impl Default for HttpRequestPool {
fn default() -> Self {
Self::with_capacity(128)
}
}
impl HttpRequestPool { impl HttpRequestPool {
/// Allocates a slab of memory for pool use. pub(crate) fn with_capacity(cap: usize) -> Self {
pub(crate) fn create() -> &'static HttpRequestPool { HttpRequestPool {
let pool = HttpRequestPool(RefCell::new(Vec::with_capacity(128))); inner: RefCell::new(Vec::with_capacity(cap)),
Box::leak(Box::new(pool)) cap,
}
} }
/// Re-use a previously allocated (but now completed/discarded) HttpRequest object. /// Re-use a previously allocated (but now completed/discarded) HttpRequest object.
#[inline] #[inline]
pub(crate) fn get_request(&self) -> Option<HttpRequest> { pub(crate) fn get(&self) -> Option<HttpRequest> {
self.0.borrow_mut().pop().map(|inner| HttpRequest { inner }) self.inner
.borrow_mut()
.pop()
.map(|inner| HttpRequest { inner })
}
/// Check if the pool still has capacity for request storage.
#[inline]
pub(crate) fn is_available(&self) -> bool {
self.inner.borrow_mut().len() < self.cap
}
/// Push a request to pool.
#[inline]
pub(crate) fn push(&self, req: Rc<HttpRequestInner>) {
self.inner.borrow_mut().push(req);
} }
/// Clears all allocated HttpRequest objects. /// Clears all allocated HttpRequest objects.
pub(crate) fn clear(&self) { pub(crate) fn clear(&self) {
self.0.borrow_mut().clear() self.inner.borrow_mut().clear()
} }
} }

View File

@ -30,7 +30,6 @@ pub use actix_http::test::TestBuffer;
use crate::config::AppConfig; use crate::config::AppConfig;
use crate::data::Data; use crate::data::Data;
use crate::dev::{Body, MessageBody, Payload, Server}; use crate::dev::{Body, MessageBody, Payload, Server};
use crate::request::HttpRequestPool;
use crate::rmap::ResourceMap; use crate::rmap::ResourceMap;
use crate::service::{ServiceRequest, ServiceResponse}; use crate::service::{ServiceRequest, ServiceResponse};
use crate::{Error, HttpRequest, HttpResponse}; use crate::{Error, HttpRequest, HttpResponse};
@ -549,7 +548,6 @@ impl TestRequest {
Rc::new(self.rmap), Rc::new(self.rmap),
self.config.clone(), self.config.clone(),
Rc::new(self.app_data), Rc::new(self.app_data),
HttpRequestPool::create(),
)) ))
} }
@ -571,7 +569,6 @@ impl TestRequest {
Rc::new(self.rmap), Rc::new(self.rmap),
self.config.clone(), self.config.clone(),
Rc::new(self.app_data), Rc::new(self.app_data),
HttpRequestPool::create(),
) )
} }
@ -588,7 +585,6 @@ impl TestRequest {
Rc::new(self.rmap), Rc::new(self.rmap),
self.config.clone(), self.config.clone(),
Rc::new(self.app_data), Rc::new(self.app_data),
HttpRequestPool::create(),
); );
(req, payload) (req, payload)