Skip to content

Commit 46f7667

Browse files
committed
Alright, let's do the dumb thing of caching Date
1 parent d7e0180 commit 46f7667

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

http/src/date.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use std::cell::RefCell;
2+
use std::fmt::{self, Write};
3+
use std::str;
4+
5+
use time::{self, Duration};
6+
7+
pub struct Now(());
8+
9+
/// Returns a struct, which when formatted, renders an appropriate `Date` header
10+
/// value.
11+
pub fn now() -> Now {
12+
Now(())
13+
}
14+
15+
// Gee Alex, doesn't this seem like premature optimization. Well you see there
16+
// Billy, you're absolutely correct! If your server is *bottlenecked* on
17+
// rendering the `Date` header, well then boy do I have news for you, you don't
18+
// need this optimization.
19+
//
20+
// In all seriousness, though, a simple "hello world" benchmark which just sends
21+
// back literally "hello world" with standard headers actually is bottlenecked
22+
// on rendering a date into a byte buffer. Since it was at the top of a profile,
23+
// and this was done for some competitive benchmarks, this module was written.
24+
//
25+
// Just to be clear, though, I was not intending on doing this because it really
26+
// does seem kinda absurd, but it was done by someone else [1], so I blame them!
27+
// :)
28+
//
29+
// [1]: https://github.com/rapidoid/rapidoid/blob/f1c55c0555007e986b5d069fe1086e6d09933f7b/rapidoid-commons/src/main/java/org/rapidoid/commons/Dates.java#L48-L66
30+
31+
struct LastRenderedNow {
32+
bytes: [u8; 128],
33+
amt: usize,
34+
next_update: time::Timespec,
35+
}
36+
37+
thread_local!(static LAST: RefCell<LastRenderedNow> = RefCell::new(LastRenderedNow {
38+
bytes: [0; 128],
39+
amt: 0,
40+
next_update: time::Timespec::new(0, 0),
41+
}));
42+
43+
impl fmt::Display for Now {
44+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45+
LAST.with(|cache| {
46+
let mut cache = cache.borrow_mut();
47+
let now = time::get_time();
48+
if now > cache.next_update {
49+
cache.update(now);
50+
}
51+
f.write_str(cache.buffer())
52+
})
53+
}
54+
}
55+
56+
impl LastRenderedNow {
57+
fn buffer(&self) -> &str {
58+
str::from_utf8(&self.bytes[..self.amt]).unwrap()
59+
}
60+
61+
fn update(&mut self, now: time::Timespec) {
62+
self.amt = 0;
63+
write!(LocalBuffer(self), "{}", time::at(now).rfc822()).unwrap();
64+
self.next_update = now + Duration::seconds(1);
65+
}
66+
}
67+
68+
struct LocalBuffer<'a>(&'a mut LastRenderedNow);
69+
70+
impl<'a> fmt::Write for LocalBuffer<'a> {
71+
fn write_str(&mut self, s: &str) -> fmt::Result {
72+
let start = self.0.amt;
73+
let end = start + s.len();
74+
self.0.bytes[start..end].copy_from_slice(s.as_bytes());
75+
self.0.amt += s.len();
76+
Ok(())
77+
}
78+
}

http/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ mod io2;
2525
pub use io2::{Parse, Serialize};
2626
use io2::{ParseStream, StreamWriter};
2727

28+
mod date;
29+
2830
pub trait Service<Req, Resp>: Send + Sync + 'static
2931
where Req: Send + 'static,
3032
Resp: Send + 'static

http/src/response.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use std::fmt::{self, Write};
22

3-
use time;
4-
53
use io2::Serialize;
64

75
pub struct Response {
@@ -35,7 +33,7 @@ impl Serialize for Response {
3533
Server: Example\r\n\
3634
Content-Length: {}\r\n\
3735
Date: {}\r\n\
38-
", self.response.len(), time::now().rfc822()).unwrap();
36+
", self.response.len(), ::date::now()).unwrap();
3937
for &(ref k, ref v) in &self.headers {
4038
extend(buf, k.as_bytes());
4139
extend(buf, b": ");
@@ -59,6 +57,10 @@ impl<'a> fmt::Write for FastWrite<'a> {
5957
extend(self.0, s.as_bytes());
6058
Ok(())
6159
}
60+
61+
fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
62+
fmt::write(self, args)
63+
}
6264
}
6365

6466
// TODO: why doesn't extend_from_slice optimize to this?

0 commit comments

Comments
 (0)