Skip to content

Commit e193303

Browse files
committed
Merge pull request #161 from hyperium/mucell
refactor(headers): changed from rwlock to mucell underneath
2 parents ad22d79 + d71d654 commit e193303

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};
@@ -98,7 +98,7 @@ fn header_name<T: Header>() -> &'static str {
9898
/// A map of header fields on requests and responses.
9999
#[deriving(Clone)]
100100
pub struct Headers {
101-
data: HashMap<CaseInsensitive, RWLock<Item>>
101+
data: HashMap<CaseInsensitive, MuCell<Item>>
102102
}
103103

104104
impl Headers {
@@ -118,12 +118,12 @@ impl Headers {
118118
Some((name, value)) => {
119119
debug!("raw header: {}={}", name, value[].to_ascii());
120120
let name = CaseInsensitive(Owned(name));
121-
let item = match headers.data.entry(name) {
122-
Vacant(entry) => entry.set(RWLock::new(Item::raw(vec![]))),
121+
let mut item = match headers.data.entry(name) {
122+
Vacant(entry) => entry.set(MuCell::new(Item::raw(vec![]))),
123123
Occupied(entry) => entry.into_mut()
124124
};
125125

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

146146
/// Access the raw value of a header.
@@ -159,15 +159,19 @@ impl Headers {
159159
// FIXME(reem): Find a better way to do this lookup without find_equiv.
160160
.get(&CaseInsensitive(Borrowed(unsafe { mem::transmute::<&str, &str>(name) })))
161161
.and_then(|item| {
162-
let lock = item.read();
163-
if let Some(ref raw) = lock.raw {
162+
if let Some(ref raw) = item.borrow().raw {
164163
return unsafe { mem::transmute(Some(raw[])) };
165164
}
166165

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

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

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

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

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

209215
/// Returns a boolean of whether a certain header is in the map.
@@ -255,7 +261,7 @@ impl fmt::Show for Headers {
255261

256262
/// An `Iterator` over the fields in a `Headers` map.
257263
pub struct HeadersItems<'a> {
258-
inner: Entries<'a, CaseInsensitive, RWLock<Item>>
264+
inner: Entries<'a, CaseInsensitive, MuCell<Item>>
259265
}
260266

261267
impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> {
@@ -268,7 +274,7 @@ impl<'a> Iterator<HeaderView<'a>> for HeadersItems<'a> {
268274
}
269275

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

273279
impl<'a> HeaderView<'a> {
274280
/// Check if a HeaderView is a certain Header.
@@ -288,21 +294,21 @@ impl<'a> HeaderView<'a> {
288294
pub fn value<H: Header + HeaderFormat>(&self) -> Option<&'a H> {
289295
get_or_parse::<H>(self.1).map(|item| {
290296
unsafe {
291-
mem::transmute::<&H, &H>(downcast(&*item.read()))
297+
mem::transmute::<&H, &H>(downcast(&*item.borrow()))
292298
}
293299
})
294300
}
295301

296302
/// Get just the header value as a String.
297303
#[inline]
298304
pub fn value_string(&self) -> String {
299-
(*self.1.read()).to_string()
305+
(*self.1.borrow()).to_string()
300306
}
301307
}
302308

303309
impl<'a> fmt::Show for HeaderView<'a> {
304310
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305-
write!(f, "{}: {}", self.0, *self.1.read())
311+
write!(f, "{}: {}", self.0, *self.1.borrow())
306312
}
307313
}
308314

@@ -345,8 +351,8 @@ impl Item {
345351

346352
}
347353

348-
fn get_or_parse<H: Header + HeaderFormat>(item: &RWLock<Item>) -> Option<&RWLock<Item>> {
349-
match item.read().typed {
354+
fn get_or_parse<H: Header + HeaderFormat>(item: &MuCell<Item>) -> Option<&MuCell<Item>> {
355+
match item.borrow().typed {
350356
Some(ref typed) if typed.is::<H>() => return Some(item),
351357
Some(ref typed) => {
352358
warn!("attempted to access {} as wrong type", typed);
@@ -355,53 +361,55 @@ fn get_or_parse<H: Header + HeaderFormat>(item: &RWLock<Item>) -> Option<&RWLock
355361
_ => ()
356362
}
357363

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

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

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

380-
let header = match write.raw {
397+
fn parse<H: Header + HeaderFormat>(item: &mut Item) {
398+
item.typed = match item.raw {
381399
Some(ref raw) => match Header::parse_header(raw[]) {
382-
Some::<H>(h) => h,
383-
None => return None
400+
Some::<H>(h) => Some(box h as Box<HeaderFormat + Send + Sync>),
401+
None => None
384402
},
385403
None => unreachable!()
386404
};
387-
388-
// Mutate!
389-
write.typed = Some(box header as Box<HeaderFormat + Send + Sync>);
390-
Some(item)
391405
}
392406

393-
fn downcast<H: Header + HeaderFormat>(read: &Item) -> &H {
394-
match read.typed {
395-
Some(ref val) => unsafe { val.downcast_ref_unchecked() },
396-
_ => unreachable!()
397-
}
407+
unsafe fn downcast<H: Header + HeaderFormat>(item: &Item) -> &H {
408+
item.typed.as_ref().expect("item.typed must be set").downcast_ref_unchecked()
398409
}
399410

400-
fn downcast_mut<H: Header + HeaderFormat>(write: &mut Item) -> &mut H {
401-
match write.typed {
402-
Some(ref mut val) => unsafe { val.downcast_mut_unchecked() },
403-
_ => unreachable!()
404-
}
411+
unsafe fn downcast_mut<H: Header + HeaderFormat>(item: &mut Item) -> &mut H {
412+
item.typed.as_mut().expect("item.typed must be set").downcast_mut_unchecked()
405413
}
406414

407415
impl fmt::Show for Item {
@@ -421,12 +429,6 @@ impl fmt::Show for Item {
421429
}
422430
}
423431

424-
impl Clone for RWLock<Item> {
425-
fn clone(&self) -> RWLock<Item> {
426-
RWLock::new(self.read().clone())
427-
}
428-
}
429-
430432
impl fmt::Show for Box<HeaderFormat + Send + Sync> {
431433
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
432434
(**self).fmt_header(fmt)
@@ -659,6 +661,32 @@ mod tests {
659661
}
660662
}
661663

664+
#[bench]
665+
fn bench_header_get(b: &mut Bencher) {
666+
let mut headers = Headers::new();
667+
headers.set(ContentLength(11));
668+
b.iter(|| assert_eq!(headers.get::<ContentLength>(), Some(&ContentLength(11))))
669+
}
670+
671+
#[bench]
672+
fn bench_header_get_miss(b: &mut Bencher) {
673+
let headers = Headers::new();
674+
b.iter(|| assert!(headers.get::<ContentLength>().is_none()))
675+
}
676+
677+
#[bench]
678+
fn bench_header_set(b: &mut Bencher) {
679+
let mut headers = Headers::new();
680+
b.iter(|| headers.set(ContentLength(12)))
681+
}
682+
683+
#[bench]
684+
fn bench_header_has(b: &mut Bencher) {
685+
let mut headers = Headers::new();
686+
headers.set(ContentLength(11));
687+
b.iter(|| assert!(headers.has::<ContentLength>()))
688+
}
689+
662690
#[bench]
663691
fn bench_header_view_is(b: &mut Bencher) {
664692
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)