1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! _**Note:** This crate is still in early development and undergoing API changes. Contributions, feature requests, and
//! constructive feedback are warmly welcomed._
//!
//! # sharded   ![Build] ![Crate]
//!
//! [Build]: https://github.com/nkconnor/sharded/workflows/build/badge.svg
//! [Crate]: https://img.shields.io/crates/v/sharded
//!
//! **Sharded provides safe, fast, and obvious concurrent collections in Rust**. This crate splits the
//! underlying collection into `N shards` each with its own lock. Calling `read(&key)` or `write(&key)`
//! returns a guard for a single shard.
//!
//! ## Features
//!
//! * **Zero unsafe code.** This library uses `#![forbid(unsafe_code)]`.
//!
//! * **Zero dependencies (almost).** By default, the library only uses `std` and `hashbrown`. If you'd like to pull in some community
//! crates such as `parking_lot`, `ahash`, etc.. just use add the corresponding feature.
//!
//! * **Tiny footprint.** The core logic is ~100 lines of code. This may build up over time as utilities
//! and ergonomics are added.
//!
//! * ~~**Extremely fast.** This implementation may be a more performant choice for your workload than some
//! of the most popular concurrent hashmaps out there.~~ **??**
//!
//! ### See Also
//!
//! - **[flurry](https://github.com/jonhoo/flurry)** - A port of Java's `java.util.concurrent.ConcurrentHashMap` to Rust. (Also part of a live stream series)
//! - **[dashmap](https://github.com/xacrimon/dashmap)** - Blazing fast concurrent HashMap for Rust.
//! - **[countrie](https://crates.io/crates/contrie)** - A concurrent hash-trie map & set.
//!
//!
//! ## Quick Start
//!
//! ```toml
//! [dependencies]
//! # Optionally use `parking_lot`, `ahash`, `fxhash`, and `xxhash`
//! # by specifing the feature by the same name e.g.
//! sharded = { version = "0.1.0", features = ["fxhash", "parking_lot"] }
//! ```
//! ### Examples
//!
//! **Insert a key value pair**
//!
//! ```
//! # use sharded::Map;
//! let users = Map::new();
//! users.insert(32, "Henry");
//! ```
//!
//! **Access a storage shard**
//!
//! `Map` provides `read` and `write` which give access to the underlying
//! storage (which is built using `hashbrown::raw`). Both methods return a tuple of `(Key,
//! Guard<Shard>)`
//!
//! ```
//! # use sharded::Map;
//! # let users = Map::new();
//! # users.insert(32, "Henry");
//! let (key, shard) = users.read(&32);
//! assert_eq!(shard.get(key), Some(&"Henry"));
//! ```
//!
//! **Determine if a storage shard is locked**
//!
//! `try_read` and `try_write` are available for avoiding blocks or in situations that could
//! deadlock
//!
//! ```
//! # use sharded::{WouldBlock, Map};
//! # let users = Map::new();
//! # users.insert(32, "Henry");
//! match users.try_read(&32) {
//!     Ok((key, mut shard)) => Ok(shard.get(key)),
//!     Err(WouldBlock) => Err(WouldBlock)
//! };
//! ```
//!
//! ## Performance Comparison
//!
//! _**Note**: These benchmarks are stale._
//!
//! _**Disclaimer**: I'm no expert in performance testing._ Probably the best you can do is benchmark your application
//! using the different implementations in the most realistic setting possible.
//!
//! These measurements were generated using [`jonhoo/bustle`](https://github.com/jonhoo/bustle). To reproduce the charts,
//! see the `benchmarks` directory.
//!
//! ### Average Performance by Implementation
//!
//! This ran each implementation over the presets in [`bustle::Mix`](https://docs.rs/bustle/0.4.1/bustle/struct.Mix.html) for 5
//! iterations. Lower numbers are better. Approaches using a single `std::sync` Lock and `chashmap` were discarded for clarity (they are
//! a lot slower). If you know why `chashmap` is so slow in this test, please help here.
//!
//! #### Read Heavy
//!
//! ![Read Heavy Performance)](benchmarks/avg_performance_read_heavy.png)
//!
//! [.. continued in benchmarks/](benchmarks/README.md)
//!
//! ## Acknowledgements
//!
//! Many thanks to
//!
//! - [Reddit community](https://www.reddit.com/r/rust) for a few pointers and
//! some motivation to take this project further.
//!
//! - [Jon Gjengset](https://github.com/jonhoo) for the live streams and utility crates involved
//!
//! - and countless OSS contributors that made this work possible
//!
//! ## License
//!
//! Licensed under either of <a href="LICENSE-APACHE">Apache License, Version
//! 2.0</a> or <a href="LICENSE-MIT">MIT license</a> at your option.
//!
//! Unless you explicitly state otherwise, any contribution intentionally submitted
//! for inclusion in `sharded` by you, as defined in the Apache-2.0 license, shall be
//! dual licensed as above, without any additional terms or conditions.
#![forbid(unsafe_code)]

//#[cfg(feature = "fxhash")]
//use fxhash_utils::FxHasher as DefaultHasher;

#[cfg(feature = "fxhash")]
use fxhash_utils::FxBuildHasher as DefaultRandomState;

//#[cfg(feature = "ahash")]
//use ahash_utils::AHasher as DefaultHasher;

#[cfg(feature = "ahash")]
use ahash_utils::RandomState as DefaultRandomState;

//#[cfg(feature = "xxhash")]
//use xxhash_utils::XxHash64 as DefaultHasher;

#[cfg(feature = "xxhash")]
use xxhash_utils::RandomXxHashBuilder64 as DefaultRandomState;

//#[cfg(not(any(feature = "ahash", feature = "fxhash", feature = "xxhash")))]
//use std::collections::hash_map::DefaultHasher;

#[cfg(not(any(feature = "ahash", feature = "fxhash", feature = "xxhash")))]
use std::collections::hash_map::RandomState as DefaultRandomState;

#[cfg(feature = "parking_lot")]
pub type Lock<T> = parking_lot_utils::RwLock<T>;

#[cfg(feature = "parking_lot")]
pub type ReadGuard<'a, T> = parking_lot_utils::RwLockReadGuard<'a, T>;

#[cfg(feature = "parking_lot")]
pub type WriteGuard<'a, T> = parking_lot_utils::RwLockWriteGuard<'a, T>;

#[cfg(not(feature = "parking_lot"))]
pub type Lock<T> = std::sync::RwLock<T>;

#[cfg(not(feature = "parking_lot"))]
type ReadGuard<'a, T> = std::sync::RwLockReadGuard<'a, T>;

#[cfg(not(feature = "parking_lot"))]
type WriteGuard<'a, T> = std::sync::RwLockWriteGuard<'a, T>;

pub type RandomState = DefaultRandomState;

pub struct WouldBlock;

/// Number of shards
const DEFAULT_SHARD_COUNT: u64 = 128;

pub mod map;
pub use map::Map;