Skip to content

Commit d71d654

Browse files
committed
refactor(headers): changed from rwlock to mucell underneath
1 parent 1014f63 commit d71d654

File tree

4 files changed

+103
-80
lines changed

4 files changed

+103
-80
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ git = "https://github.com/alexcrichton/cookie-rs"
2727

2828
[dependencies.time]
2929
git = "https://github.com/rust-lang/time"
30+
31+
[dependencies.mucell]
32+
git = "https://github.com/chris-morgan/mucell"

src/header/common/mod.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,24 @@ macro_rules! bench_header(
2626
#[cfg(test)]
2727
mod $name {
2828
use test::Bencher;
29-
use std::fmt::{mod, Show};
30-
3129
use super::*;
3230

33-
use header::{Header, HeaderFormat};
34-
35-
struct HeaderFormatter($ty);
36-
37-
impl Show for HeaderFormatter {
38-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39-
self.0.fmt_header(f)
40-
}
41-
}
31+
use header::{Header, HeaderFormatter};
4232

4333
#[bench]
4434
fn bench_parse(b: &mut Bencher) {
4535
let val = $value;
4636
b.iter(|| {
47-
let _: $ty= Header::parse_header(val[]).unwrap();
37+
let _: $ty = Header::parse_header(val[]).unwrap();
4838
});
4939
}
5040

5141
#[bench]
5242
fn bench_format(b: &mut Bencher) {
53-
let val = HeaderFormatter(Header::parse_header($value[]).unwrap());
43+
let val: $ty = Header::parse_header($value[]).unwrap();
44+
let fmt = HeaderFormatter(&val);
5445
b.iter(|| {
55-
format!("{}", val);
46+
format!("{}", fmt);
5647
});
5748
}
5849
}

src/header/mod.rs

Lines changed: 94 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ use std::raw::TraitObject;
1313
use std::str::SendStr;
1414
use std::collections::HashMap;
1515
use std::collections::hash_map::{Entries, Occupied, Vacant};
16-
use std::sync::RWLock;
1716
use std::{hash, mem};
1817

18+
use mucell::MuCell;
1919
use uany::{UncheckedAnyDowncast, UncheckedAnyMutDowncast};
2020

2121
use http::{mod, LineEnding};
@@ -96,7 +96,7 @@ fn header_name<T: Header>() -> &'static str {
9696
/// A map of header fields on requests and responses.
9797
#[deriving(Clone)]
9898
pub struct Headers {
99-
data: HashMap<CaseInsensitive, RWLock<Item>>
99+
data: HashMap<CaseInsensitive, MuCell<Item>>
100100
}
101101

102102
impl Headers {
@@ -116,12 +116,12 @@ impl Headers {
116116
Some((name, value)) => {
117117
debug!("raw header: {}={}", name, value[].to_ascii());
118118
let name = CaseInsensitive(Owned(name));
119-
let item = match headers.data.entry(name) {
120-
Vacant(entry) => entry.set(RWLock::new(Item::raw(vec![]))),
119+
let mut item = match headers.data.entry(name) {
120+
Vacant(entry) => entry.set(MuCell::new(Item::raw(vec![]))),
121121
Occupied(entry) => entry.into_mut()
122122
};
123123

124-
match &mut item.write().raw {
124+
match &mut item.borrow_mut().raw {
125125
&Some(ref mut raw) => raw.push(value),
126126
// Unreachable
127127
_ => {}
@@ -138,7 +138,7 @@ impl Headers {
138138
/// The field is determined by the type of the value being set.
139139
pub fn set<H: Header + HeaderFormat>(&mut self, value: H) {
140140
self.data.insert(CaseInsensitive(Borrowed(header_name::<H>())),
141-
RWLock::new(Item::typed(box value as Box<HeaderFormat + Send + Sync>)));
141+
MuCell::new(Item::typed(box value as Box<HeaderFormat + Send + Sync>)));
142142
}
143143

144144
/// Access the raw value of a header.
@@ -157,15 +157,19 @@ impl Headers {
157157
// FIXME(reem): Find a better way to do this lookup without find_equiv.
158158
.get(&CaseInsensitive(Borrowed(unsafe { mem::transmute::<&str, &str>(name) })))
159159
.and_then(|item| {
160-
let lock = item.read();
161-
if let Some(ref raw) = lock.raw {
160+
if let Some(ref raw) = item.borrow().raw {
162161
return unsafe { mem::transmute(Some(raw[])) };
163162
}
164163

165-
let mut lock = item.write();
166-
let raw = vec![lock.typed.as_ref().unwrap().to_string().into_bytes()];
167-
lock.raw = Some(raw);
168-
unsafe { mem::transmute(Some(lock.raw.as_ref().unwrap()[])) }
164+
let worked = item.try_mutate(|item| {
165+
let raw = vec![item.typed.as_ref().unwrap().to_string().into_bytes()];
166+
item.raw = Some(raw);
167+
});
168+
debug_assert!(worked, "item.try_mutate should return true");
169+
170+
let item = item.borrow();
171+
let raw = item.raw.as_ref().unwrap();
172+
unsafe { mem::transmute(Some(raw[])) }
169173
})
170174
}
171175

@@ -179,29 +183,31 @@ impl Headers {
179183
/// headers.set_raw("content-length", vec!["5".as_bytes().to_vec()]);
180184
/// ```
181185
pub fn set_raw<K: IntoCow<'static, String, str>>(&mut self, name: K, value: Vec<Vec<u8>>) {
182-
self.data.insert(CaseInsensitive(name.into_cow()), RWLock::new(Item::raw(value)));
186+
self.data.insert(CaseInsensitive(name.into_cow()), MuCell::new(Item::raw(value)));
183187
}
184188

185189
/// Get a reference to the header field's value, if it exists.
186190
pub fn get<H: Header + HeaderFormat>(&self) -> Option<&H> {
187191
self.get_or_parse::<H>().map(|item| {
188192
unsafe {
189-
mem::transmute::<&H, &H>(downcast(&*item.read()))
193+
mem::transmute::<&H, &H>(downcast(&*item.borrow()))
190194
}
191195
})
192196
}
193197

194198
/// Get a mutable reference to the header field's value, if it exists.
195199
pub fn get_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut H> {
196-
self.get_or_parse::<H>().map(|item| {
197-
unsafe {
198-
mem::transmute::<&mut H, &mut H>(downcast_mut(&mut *item.write()))
199-
}
200+
self.get_or_parse_mut::<H>().map(|item| {
201+
unsafe { downcast_mut(item.borrow_mut()) }
200202
})
201203
}
202204

203-
fn get_or_parse<H: Header + HeaderFormat>(&self) -> Option<&RWLock<Item>> {
204-
self.data.get(&CaseInsensitive(Borrowed(header_name::<H>()))).and_then(|item| get_or_parse::<H>(item))
205+
fn get_or_parse<H: Header + HeaderFormat>(&self) -> Option<&MuCell<Item>> {
206+
self.data.get(&CaseInsensitive(Borrowed(header_name::<H>()))).and_then(get_or_parse::<H>)
207+
}
208+
209+
fn get_or_parse_mut<H: Header + HeaderFormat>(&mut self) -> Option<&mut MuCell<Item>> {
210+
self.data.get_mut(&CaseInsensitive(Borrowed(header_name::<H>()))).and_then(get_or_parse_mut::<H>)
205211
}
206212

207213
/// Returns a boolean of whether a certain header is in the map.
@@ -253,7 +259,7 @@ impl fmt::Show for Headers {
253259

254260
/// An `Iterator` over the fields in a `Headers` map.
255261
pub struct HeadersItems<'a> {
256-
inner: Entries<'a, CaseInsensitive, RWLock<Item>>
262+
inner: Entries<'a, CaseInsensitive, MuCell<Item>>
257263
}
258264

259265
impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> {
@@ -266,7 +272,7 @@ impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> {
266272
}
267273

268274
/// Returned with the `HeadersItems` iterator.
269-
pub struct HeaderView<'a>(&'a CaseInsensitive, &'a RWLock<Item>);
275+
pub struct HeaderView<'a>(&'a CaseInsensitive, &'a MuCell<Item>);
270276

271277
impl<'a> HeaderView<'a> {
272278
/// Check if a HeaderView is a certain Header.
@@ -286,21 +292,21 @@ impl<'a> HeaderView<'a> {
286292
pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> {
287293
get_or_parse::<H>(self.1).map(|item| {
288294
unsafe {
289-
mem::transmute::<&H, &H>(downcast(&*item.read()))
295+
mem::transmute::<&H, &H>(downcast(&*item.borrow()))
290296
}
291297
})
292298
}
293299

294300
/// Get just the header value as a String.
295301
#[inline]
296302
pub fn value_string(&self) -> String {
297-
(*self.1.read()).to_string()
303+
(*self.1.borrow()).to_string()
298304
}
299305
}
300306

301307
impl<'a> fmt::Show for HeaderView<'a> {
302308
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
303-
write!(f, "{}: {}", self.0, *self.1.read())
309+
write!(f, "{}: {}", self.0, *self.1.borrow())
304310
}
305311
}
306312

@@ -343,8 +349,8 @@ impl Item {
343349

344350
}
345351

346-
fn get_or_parse<H: Header + HeaderFormat>(item: &RWLock<Item>) -> Option<&RWLock<Item>> {
347-
match item.read().typed {
352+
fn get_or_parse<H: Header + HeaderFormat>(item: &MuCell<Item>) -> Option<&MuCell<Item>> {
353+
match item.borrow().typed {
348354
Some(ref typed) if typed.is::<H>() => return Some(item),
349355
Some(ref typed) => {
350356
warn!("attempted to access {} as wrong type", typed);
@@ -353,53 +359,55 @@ fn get_or_parse<H: Header + HeaderFormat>(item: &RWLock<Item>) -> Option<&RWLock
353359
_ => ()
354360
}
355361

356-
// Take out a write lock to do the parsing and mutation.
357-
let mut write = item.write();
358-
359-
// Since this lock can queue, it's possible another thread just
360-
// did the work for us.
361-
match write.typed {
362-
// Check they inserted the correct type and move on.
363-
Some(ref typed) if typed.is::<H>() => return Some(item),
362+
let worked = item.try_mutate(parse::<H>);
363+
debug_assert!(worked, "item.try_mutate should return true");
364+
if item.borrow().typed.is_some() {
365+
Some(item)
366+
} else {
367+
None
368+
}
369+
}
364370

365-
// Wrong type, another thread got here before us and parsed
366-
// as a different representation.
371+
fn get_or_parse_mut<H: Header + HeaderFormat>(item: &mut MuCell<Item>) -> Option<&mut MuCell<Item>> {
372+
let is_correct_type = match item.borrow().typed {
373+
Some(ref typed) if typed.is::<H>() => Some(true),
367374
Some(ref typed) => {
368-
debug!("other thread was here first?")
369375
warn!("attempted to access {} as wrong type", typed);
370-
return None;
371-
},
376+
Some(false)
377+
}
378+
_ => None
379+
};
372380

373-
// We are first in the queue or the only ones, so do the actual
374-
// work of parsing and mutation.
375-
_ => ()
381+
match is_correct_type {
382+
Some(true) => return Some(item),
383+
Some(false) => return None,
384+
None => ()
385+
}
386+
387+
parse::<H>(item.borrow_mut());
388+
if item.borrow().typed.is_some() {
389+
Some(item)
390+
} else {
391+
None
376392
}
393+
}
377394

378-
let header = match write.raw {
395+
fn parse<H: Header + HeaderFormat>(item: &mut Item) {
396+
item.typed = match item.raw {
379397
Some(ref raw) => match Header::parse_header(raw[]) {
380-
Some::<H>(h) => h,
381-
None => return None
398+
Some::<H>(h) => Some(box h as Box<HeaderFormat + Send + Sync>),
399+
None => None
382400
},
383401
None => unreachable!()
384402
};
385-
386-
// Mutate!
387-
write.typed = Some(box header as Box<HeaderFormat + Send + Sync>);
388-
Some(item)
389403
}
390404

391-
fn downcast<H: Header + HeaderFormat>(read: &Item) -> &H {
392-
match read.typed {
393-
Some(ref val) => unsafe { val.downcast_ref_unchecked() },
394-
_ => unreachable!()
395-
}
405+
unsafe fn downcast<H: Header + HeaderFormat>(item: &Item) -> &H {
406+
item.typed.as_ref().expect("item.typed must be set").downcast_ref_unchecked()
396407
}
397408

398-
fn downcast_mut<H: Header + HeaderFormat>(write: &mut Item) -> &mut H {
399-
match write.typed {
400-
Some(ref mut val) => unsafe { val.downcast_mut_unchecked() },
401-
_ => unreachable!()
402-
}
409+
unsafe fn downcast_mut<H: Header + HeaderFormat>(item: &mut Item) -> &mut H {
410+
item.typed.as_mut().expect("item.typed must be set").downcast_mut_unchecked()
403411
}
404412

405413
impl fmt::Show for Item {
@@ -419,12 +427,6 @@ impl fmt::Show for Item {
419427
}
420428
}
421429

422-
impl Clone for RWLock<Item> {
423-
fn clone(&self) -> RWLock<Item> {
424-
RWLock::new(self.read().clone())
425-
}
426-
}
427-
428430
impl fmt::Show for Box<HeaderFormat + Send + Sync> {
429431
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
430432
(**self).fmt_header(fmt)
@@ -655,6 +657,32 @@ mod tests {
655657
}
656658
}
657659

660+
#[bench]
661+
fn bench_header_get(b: &mut Bencher) {
662+
let mut headers = Headers::new();
663+
headers.set(ContentLength(11));
664+
b.iter(|| assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(11))))
665+
}
666+
667+
#[bench]
668+
fn bench_header_get_miss(b: &mut Bencher) {
669+
let headers = Headers::new();
670+
b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
671+
}
672+
673+
#[bench]
674+
fn bench_header_set(b: &mut Bencher) {
675+
let mut headers = Headers::new();
676+
b.iter(|| headers.set(ContentLength(12)))
677+
}
678+
679+
#[bench]
680+
fn bench_header_has(b: &mut Bencher) {
681+
let mut headers = Headers::new();
682+
headers.set(ContentLength(11));
683+
b.iter(|| assert!(headers.has::<ContentLength>()))
684+
}
685+
658686
#[bench]
659687
fn bench_header_view_is(b: &mut Bencher) {
660688
let mut headers = Headers::new();

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ extern crate openssl;
134134
#[cfg(test)] extern crate test;
135135
extern crate "unsafe-any" as uany;
136136
extern crate cookie;
137+
extern crate mucell;
137138

138139
pub use std::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr, Port};
139140
pub use mimewrapper::mime;

0 commit comments

Comments
 (0)