Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Implement len caching for parking_lot RwLock #10032

Merged
merged 12 commits into from
Dec 13, 2018
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ethcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ kvdb-rocksdb = "0.1.3"
serde = "1.0"
serde_derive = "1.0"
tempdir = {version="0.3", optional = true}
len-caching-mutex = { path = "../util/len-caching-mutex" }
len-caching-lock = { path = "../util/len-caching-lock" }

[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))'.dependencies]
hardware-wallet = { path = "../hw" }
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ extern crate journaldb;
extern crate serde;
#[cfg(any(test, feature = "json-tests", feature = "test-helpers"))]
extern crate tempdir;
extern crate len_caching_mutex;
extern crate len_caching_lock;

#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "android"))]
extern crate hardware_wallet;
Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/verification/queue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use io::*;
use error::{BlockError, ImportErrorKind, ErrorKind, Error};
use engines::EthEngine;
use client::ClientIoMessage;
use len_caching_mutex::LenCachingMutex;
use len_caching_lock::LenCachingMutex;

use self::kind::{BlockLike, Kind};

Expand Down
10 changes: 10 additions & 0 deletions util/len-caching-lock/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
description = "Atomically cached len(), for use with collections contained in parking_lot Mutex and RwLock"
homepage = "http://parity.io"
license = "GPL-3.0"
name = "len-caching-lock"
version = "0.1.1"
authors = ["Parity Technologies <[email protected]>"]

[dependencies]
parking_lot = "0.7"
87 changes: 87 additions & 0 deletions util/len-caching-lock/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

//! This crate allows automatic caching of `T.len()` with an api that
//! allows drop in replacement for `parking_lot`
//! [`Mutex`](../lock_api/struct.Mutex.html)
//! and [`RwLock`](../lock_api/struct.RwLock.html) for most common use-cases.
//!
//! This crate implements `Len` for the following types:
//! `std::collections::{VecDeque, LinkedList, HashMap, BTreeMap, HashSet, BTreeSet, BinaryHeap}`
//!
//! ## Example
//!
//! ```rust
//! extern crate len_caching_lock;
//! use len_caching_lock::LenCachingMutex;
//!
//! fn main() {
//! let vec: Vec<i32> = Vec::new();
//! let len_caching_mutex = LenCachingMutex::new(vec);
//! assert_eq!(len_caching_mutex.lock().len(), len_caching_mutex.load_len());
//! len_caching_mutex.lock().push(0);
//! assert_eq!(1, len_caching_mutex.load_len());
//! }
//! ```

extern crate parking_lot;
use std::collections::{VecDeque, LinkedList, HashMap, BTreeMap, HashSet, BTreeSet, BinaryHeap};
use std::hash::Hash;

pub mod mutex;
pub mod rwlock;

pub use mutex::LenCachingMutex;
pub use rwlock::LenCachingRwLock;

/// Implement to allow a type with a len() method to be used
/// with [`LenCachingMutex`](mutex/struct.LenCachingMutex.html)
/// or [`LenCachingRwLock`](rwlock/struct.LenCachingRwLock.html)
pub trait Len {
fn len(&self) -> usize;
}

impl<T> Len for Vec<T> {
fn len(&self) -> usize { Vec::len(self) }
}

impl<T> Len for VecDeque<T> {
fn len(&self) -> usize { VecDeque::len(self) }
}

impl<T> Len for LinkedList<T> {
fn len(&self) -> usize { LinkedList::len(self) }
}

impl<K: Eq + Hash, V> Len for HashMap<K, V> {
fn len(&self) -> usize { HashMap::len(self) }
}

impl<K, V> Len for BTreeMap<K, V> {
fn len(&self) -> usize { BTreeMap::len(self) }
}

impl<T: Eq + Hash> Len for HashSet<T> {
fn len(&self) -> usize { HashSet::len(self) }
}

impl<T> Len for BTreeSet<T> {
fn len(&self) -> usize { BTreeSet::len(self) }
}

impl<T: Ord> Len for BinaryHeap<T> {
fn len(&self) -> usize { BinaryHeap::len(self) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,95 +13,107 @@

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate parking_lot;

use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

use parking_lot::{Mutex, MutexGuard};

/// Implement to allow a type with a len() method to be used
/// with [`LenCachingMutex`](struct.LenCachingMutex.html)
pub trait Len {
fn len(&self) -> usize;
}
use Len;
mattrutherford marked this conversation as resolved.
Show resolved Hide resolved

impl<T> Len for Vec<T> {
fn len(&self) -> usize { self.len() }
/// Can be used in place of a [`Mutex`](../../lock_api/struct.Mutex.html) where reading `T`'s `len()` without
/// needing to lock, is advantageous.
/// When the Guard is released, `T`'s `len()` will be cached.
/// The cached `len()` may be at most 1 lock behind current state.
mattrutherford marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug)]
pub struct LenCachingMutex<T: ?Sized> {
len: AtomicUsize,
data: Mutex<T>,
}

impl<T> Len for VecDeque<T> {
fn len(&self) -> usize { self.len() }
impl<T: Len + Default> Default for LenCachingMutex<T> {
fn default() -> Self {
LenCachingMutex::new(T::default())
}
}

/// Can be used in place of a `Mutex` where reading `T`'s `len()` without
/// needing to lock, is advantageous.
/// When the Guard is released, `T`'s `len()` will be cached.
/// The cached `len()` may be at most 1 lock behind current state.
pub struct LenCachingMutex<T> {
data: Mutex<T>,
len: AtomicUsize,
impl<T: Len> From<T> for LenCachingMutex<T> {
fn from(data: T) -> Self {
LenCachingMutex::new(data)
}
}

impl<T: Len> LenCachingMutex<T> {
pub fn new(data: T) -> LenCachingMutex<T> {
/// Constructs a new LenCachingMutex
pub fn new(data: T) -> Self {
LenCachingMutex {
len: AtomicUsize::new(data.len()),
data: Mutex::new(data),
}
}
}

/// Load the most recent value returned from your `T`'s `len()`
impl<T: Len + ?Sized> LenCachingMutex<T> {
/// Load the cached value that was returned from your `T`'s `len()`
/// subsequent to the most recent lock being released.
pub fn load_len(&self) -> usize {
self.len.load(Ordering::SeqCst)
}

pub fn lock(&self) -> Guard<T> {
Guard {
/// Delegates to `parking_lot::Mutex`
/// [`lock()`](../../lock_api/struct.Mutex.html#method.lock).
pub fn lock(&self) -> CachingMutexGuard<T> {
CachingMutexGuard {
mutex_guard: self.data.lock(),
len: &self.len,
}
}

pub fn try_lock(&self) -> Option<Guard<T>> {
Some( Guard {
/// Delegates to `parking_lot::Mutex`
/// [`try_lock()`](../../lock_api/struct.Mutex.html#method.try_lock).
pub fn try_lock(&self) -> Option<CachingMutexGuard<T>> {
Some(CachingMutexGuard {
mutex_guard: self.data.try_lock()?,
len: &self.len,
})
}
}

pub struct Guard<'a, T: Len + 'a> {
/// Guard comprising `MutexGuard` and `AtomicUsize` for cache
pub struct CachingMutexGuard<'a, T: Len + 'a + ?Sized> {
mutex_guard: MutexGuard<'a, T>,
len: &'a AtomicUsize,
}

impl<'a, T: Len> Guard<'a, T> {
impl<'a, T: Len + ?Sized> CachingMutexGuard<'a, T> {
/// Returns a mutable reference to the contained
/// [`MutexGuard`](../../parking_lot/mutex/type.MutexGuard.html)
pub fn inner_mut(&mut self) -> &mut MutexGuard<'a, T> {
&mut self.mutex_guard
}

/// Returns a non-mutable reference to the contained
/// [`MutexGuard`](../../parking_lot/mutex/type.MutexGuard.html)
pub fn inner(&self) -> &MutexGuard<'a, T> {
&self.mutex_guard
}
}

impl<'a, T: Len> Drop for Guard<'a, T> {
impl<'a, T: Len + ?Sized> Drop for CachingMutexGuard<'a, T> {
fn drop(&mut self) {
self.len.store(self.mutex_guard.len(), Ordering::SeqCst);
}
}

impl<'a, T: Len> Deref for Guard<'a, T> {
impl<'a, T: Len + ?Sized> Deref for CachingMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
self.mutex_guard.deref()
}
}

impl<'a, T: Len> DerefMut for Guard<'a, T> {
impl<'a, T: Len + ?Sized> DerefMut for CachingMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
self.mutex_guard.deref_mut()
}
Expand Down
Loading