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 174 175 176 177 178 179 180 181 182 183 184
//! _**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)]`. There are some limitations with the //! raw locking API that _could cause you to write a bug_, but it should be hard to so! //! //! * **Zero dependencies.** By default, the library only uses `std`. If you'd like to pull in some community //! crates such as `parking_lot`, just use the **3rd-party** 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.~~ **??** //! //! * **Flexible API.**. Bring your own lock or collection types. `sharded::Map` is just a type alias for //! `Shard<Lock<Collection<_>>>`. There's support for Sets and Trees, too! //! //! //! ### 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`, `hashbrown`, and `ahash` //! # by specifing the feature "3rd-party" //! sharded = { version = "0.0.1", features = ["3rd-party"] } //! ``` //! ### Examples //! //! **Use a concurrent HashMap** //! //! ```ignore //! use sharded::Map; //! let concurrent = Map::new() //! //! // or use an existing HashMap, //! //! let users = Shard::from(users); //! //! let guard = users.write(32); //! guard.insert(32, user); //! ``` //! //! ## 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)] #![allow(dead_code)] #![allow(unused_macros)] #![allow(incomplete_features)] #![feature(generic_associated_types)] #![feature(in_band_lifetimes)] #[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(not(any(feature = "ahash", feature = "fxhash")))] use std::collections::hash_map::DefaultHasher; #[cfg(not(any(feature = "ahash", feature = "fxhash")))] use std::collections::hash_map::RandomState as DefaultRandomState; #[cfg(feature = "hashbrown")] use hashbrown_utils::HashMap; #[cfg(feature = "hashbrown")] use hashbrown_utils::HashSet; #[cfg(not(feature = "hashbrown"))] use std::collections::HashMap; #[cfg(not(feature = "hashbrown"))] use std::collections::HashSet; use std::hash::Hash; mod lock; pub use lock::Lock; pub use lock::RwLock; pub use lock::ShardLock; mod collection; pub use collection::Collection; pub type RandomState = DefaultRandomState; mod shard; pub use shard::ExtractShardKey; pub use shard::Shard; /// Sharded lock-based concurrent map using the crate default lock and map implementations. pub type Map<K, V, S = RandomState> = Shard<RwLock<HashMap<K, V, S>>>; /// Sharded lock-based concurrent set using the crate default lock and set implementations. pub type Set<K> = Shard<RwLock<HashSet<K>>>; impl<K: Hash + Eq + Clone, V: Clone> Map<K, V> { pub fn new() -> Self { Shard::from(HashMap::<K, V, RandomState>::with_hasher( RandomState::default(), )) } pub fn with_capacity(capacity: usize) -> Self { Shard::from(HashMap::<K, V, RandomState>::with_capacity_and_hasher( capacity, RandomState::default(), )) } } #[cfg(test)] mod tests { use super::*; #[test] fn read_and_write() { let x = Map::new(); x.write(&"key".to_string()) .insert("key".to_string(), "value".to_string()); assert_eq!( x.read(&"key".to_string()).get(&"key".to_string()).unwrap(), "value" ); } #[test] fn hold_read_and_write() { let map = Map::new(); let mut write = map.write(&"abc".to_string()); write.insert("abc".to_string(), "asdf".to_string()); let _read = map.read(&"asdfas".to_string()); let _read_too = map.read(&"asdfas".to_string()); assert!(_read.is_empty()); } }