From 1b5fb3cc5e451b49d8b3ad5f997e20c0e79c09f0 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Wed, 30 May 2018 14:22:08 -0700 Subject: [PATCH] perf(h1): reduce clock checks for date rendering when pipelined --- src/proto/h1/date.rs | 36 +++++++++++++++++++++++++----------- src/proto/h1/dispatch.rs | 1 + src/proto/h1/mod.rs | 2 ++ src/proto/h1/role.rs | 32 ++++---------------------------- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/proto/h1/date.rs b/src/proto/h1/date.rs index 38a18e1e..48bcdfcd 100644 --- a/src/proto/h1/date.rs +++ b/src/proto/h1/date.rs @@ -9,12 +9,13 @@ pub const DATE_VALUE_LENGTH: usize = 29; pub fn extend(dst: &mut Vec) { CACHED.with(|cache| { - let mut cache = cache.borrow_mut(); - let now = time::get_time(); - if now > cache.next_update { - cache.update(now); - } - dst.extend_from_slice(cache.buffer()); + dst.extend_from_slice(cache.borrow().buffer()); + }) +} + +pub fn update() { + CACHED.with(|cache| { + cache.borrow_mut().check(); }) } @@ -24,17 +25,30 @@ struct CachedDate { next_update: time::Timespec, } -thread_local!(static CACHED: RefCell = RefCell::new(CachedDate { - bytes: [0; DATE_VALUE_LENGTH], - pos: 0, - next_update: time::Timespec::new(0, 0), -})); +thread_local!(static CACHED: RefCell = RefCell::new(CachedDate::new())); impl CachedDate { + fn new() -> Self { + let mut cache = CachedDate { + bytes: [0; DATE_VALUE_LENGTH], + pos: 0, + next_update: time::Timespec::new(0, 0), + }; + cache.update(time::get_time()); + cache + } + fn buffer(&self) -> &[u8] { &self.bytes[..] } + fn check(&mut self) { + let now = time::get_time(); + if now > self.next_update { + self.update(now); + } + } + fn update(&mut self, now: time::Timespec) { self.pos = 0; let _ = write!(self, "{}", time::at_utc(now).rfc822()); diff --git a/src/proto/h1/dispatch.rs b/src/proto/h1/dispatch.rs index 2de161ba..364048c7 100644 --- a/src/proto/h1/dispatch.rs +++ b/src/proto/h1/dispatch.rs @@ -89,6 +89,7 @@ where } fn poll_inner(&mut self, should_shutdown: bool) -> Poll<(), ::Error> { + T::update_date(); loop { self.poll_read()?; self.poll_write()?; diff --git a/src/proto/h1/mod.rs b/src/proto/h1/mod.rs index d3576fa4..46f0eeab 100644 --- a/src/proto/h1/mod.rs +++ b/src/proto/h1/mod.rs @@ -36,6 +36,8 @@ pub(crate) trait Http1Transaction { fn should_error_on_parse_eof() -> bool; fn should_read_first() -> bool; + + fn update_date() {} } pub(crate) type ParseResult = Result>, ::error::Parse>; diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index 605010ec..261179eb 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -182,34 +182,6 @@ where })) } - /* - fn decoder(head: &MessageHead, method: &mut Option) -> ::Result { - *method = Some(head.subject.0.clone()); - if head.headers.contains_key(TRANSFER_ENCODING) { - // https://tools.ietf.org/html/rfc7230#section-3.3.3 - // If Transfer-Encoding header is present, and 'chunked' is - // not the final encoding, and this is a Request, then it is - // mal-formed. A server should respond with 400 Bad Request. - if head.version == Version::HTTP_10 { - debug!("HTTP/1.0 cannot have Transfer-Encoding header"); - Err(::Error::new_header()) - } else if headers::transfer_encoding_is_chunked(&head.headers) { - Ok(Decode::Normal(Decoder::chunked())) - } else { - debug!("request with transfer-encoding header, but not chunked, bad request"); - Err(::Error::new_header()) - } - } else if let Some(len) = headers::content_length_parse(&head.headers) { - Ok(Decode::Normal(Decoder::length(len))) - } else if head.headers.contains_key(CONTENT_LENGTH) { - debug!("illegal Content-Length header"); - Err(::Error::new_header()) - } else { - Ok(Decode::Normal(Decoder::length(0))) - } - }*/ - - fn encode(mut msg: Encode, dst: &mut Vec) -> ::Result { trace!("Server::encode body={:?}, method={:?}", msg.body, msg.req_method); debug_assert!(!msg.title_case_headers, "no server config for title case headers"); @@ -464,6 +436,10 @@ where fn should_read_first() -> bool { true } + + fn update_date() { + date::update(); + } } impl Server<()> {