Merge pull request #582 from ethcore/secret-store-sync-ready

making key directory thread-safe
This commit is contained in:
Marek Kotewicz 2016-03-04 13:22:32 +01:00
commit 9c1f3d5fff

View File

@ -461,17 +461,17 @@ enum KeyFileLoadError {
pub struct KeyDirectory { pub struct KeyDirectory {
/// Directory path for key management. /// Directory path for key management.
path: String, path: String,
cache: RefCell<HashMap<Uuid, KeyFileContent>>, cache: RwLock<HashMap<Uuid, KeyFileContent>>,
cache_usage: RefCell<VecDeque<Uuid>>, cache_usage: RwLock<VecDeque<Uuid>>,
} }
impl KeyDirectory { impl KeyDirectory {
/// Initializes new cache directory context with a given `path` /// Initializes new cache directory context with a given `path`
pub fn new(path: &Path) -> KeyDirectory { pub fn new(path: &Path) -> KeyDirectory {
KeyDirectory { KeyDirectory {
cache: RefCell::new(HashMap::new()), cache: RwLock::new(HashMap::new()),
path: path.to_str().expect("Initialized key directory with empty path").to_owned(), path: path.to_str().expect("Initialized key directory with empty path").to_owned(),
cache_usage: RefCell::new(VecDeque::new()), cache_usage: RwLock::new(VecDeque::new()),
} }
} }
@ -484,7 +484,7 @@ impl KeyDirectory {
let json_bytes = json_text.into_bytes(); let json_bytes = json_text.into_bytes();
try!(file.write(&json_bytes)); try!(file.write(&json_bytes));
} }
let mut cache = self.cache.borrow_mut(); let mut cache = self.cache.write().unwrap();
let id = key_file.id.clone(); let id = key_file.id.clone();
cache.insert(id.clone(), key_file); cache.insert(id.clone(), key_file);
Ok(id.clone()) Ok(id.clone())
@ -495,14 +495,14 @@ impl KeyDirectory {
pub fn get(&self, id: &Uuid) -> Option<KeyFileContent> { pub fn get(&self, id: &Uuid) -> Option<KeyFileContent> {
let path = self.key_path(id); let path = self.key_path(id);
{ {
let mut usage = self.cache_usage.borrow_mut(); let mut usage = self.cache_usage.write().unwrap();
usage.push_back(id.clone()); usage.push_back(id.clone());
} }
if !self.cache.borrow().contains_key(id) { if !self.cache.read().unwrap().contains_key(id) {
match KeyDirectory::load_key(&path) { match KeyDirectory::load_key(&path) {
Ok(loaded_key) => { Ok(loaded_key) => {
self.cache.borrow_mut().insert(id.to_owned(), loaded_key); self.cache.write().unwrap().insert(id.to_owned(), loaded_key);
} }
Err(error) => { Err(error) => {
warn!(target: "sstore", "error loading key {:?}: {:?}", id, error); warn!(target: "sstore", "error loading key {:?}: {:?}", id, error);
@ -512,7 +512,7 @@ impl KeyDirectory {
} }
// todo: replace with Ref::map when it stabilized to avoid copies // todo: replace with Ref::map when it stabilized to avoid copies
Some(self.cache.borrow().get(id) Some(self.cache.read().unwrap().get(id)
.expect("Key should be there, we have just inserted or checked it.") .expect("Key should be there, we have just inserted or checked it.")
.clone()) .clone())
} }
@ -524,7 +524,7 @@ impl KeyDirectory {
/// Removes keys that never been requested during last `MAX_USAGE_TRACK` times /// Removes keys that never been requested during last `MAX_USAGE_TRACK` times
pub fn collect_garbage(&mut self) { pub fn collect_garbage(&mut self) {
let mut cache_usage = self.cache_usage.borrow_mut(); let mut cache_usage = self.cache_usage.write().unwrap();
let total_usages = cache_usage.len(); let total_usages = cache_usage.len();
let untracked_usages = max(total_usages as i64 - MAX_CACHE_USAGE_TRACK as i64, 0) as usize; let untracked_usages = max(total_usages as i64 - MAX_CACHE_USAGE_TRACK as i64, 0) as usize;
@ -532,31 +532,31 @@ impl KeyDirectory {
cache_usage.drain(..untracked_usages); cache_usage.drain(..untracked_usages);
} }
if self.cache.borrow().len() <= MAX_CACHE_USAGE_TRACK { return; } if self.cache.read().unwrap().len() <= MAX_CACHE_USAGE_TRACK { return; }
let uniqs: HashSet<&Uuid> = cache_usage.iter().collect(); let uniqs: HashSet<&Uuid> = cache_usage.iter().collect();
let removes:Vec<Uuid> = { let removes:Vec<Uuid> = {
let cache = self.cache.borrow(); let cache = self.cache.read().unwrap();
cache.keys().cloned().filter(|key| !uniqs.contains(key)).collect() cache.keys().cloned().filter(|key| !uniqs.contains(key)).collect()
}; };
if removes.is_empty() { return; } if removes.is_empty() { return; }
let mut cache = self.cache.borrow_mut(); let mut cache = self.cache.write().unwrap();
for key in removes { cache.remove(&key); } for key in removes { cache.remove(&key); }
} }
/// Reports how many keys are currently cached. /// Reports how many keys are currently cached.
pub fn cache_size(&self) -> usize { pub fn cache_size(&self) -> usize {
self.cache.borrow().len() self.cache.read().unwrap().len()
} }
/// Removes key file from key directory /// Removes key file from key directory
pub fn delete(&mut self, id: &Uuid) -> Result<(), ::std::io::Error> { pub fn delete(&mut self, id: &Uuid) -> Result<(), ::std::io::Error> {
let path = self.key_path(id); let path = self.key_path(id);
if !self.cache.borrow().contains_key(id) { if !self.cache.read().unwrap().contains_key(id) {
return match fs::remove_file(&path) { return match fs::remove_file(&path) {
Ok(_) => { Ok(_) => {
self.cache.borrow_mut().remove(&id); self.cache.write().unwrap().remove(&id);
Ok(()) Ok(())
}, },
Err(e) => Err(e) Err(e) => Err(e)