[go: up one dir, main page]

contrie/
lib.rs

1#![doc(
2    html_root_url = "https://docs.rs/contrie/0.1.4/contrie/",
3    test(attr(deny(warnings)))
4)]
5// Note: we can't use forbid(unsafe_code). We do allow unsafe code in the raw submodule (but not
6// outside of it).
7#![deny(missing_docs, warnings, unsafe_code)]
8
9//! A concurrent trie.
10//!
11//! The crate provides implementation of a hash map and a hash set. Unlike the versions from the
12//! standard library, these allow concurrent accesses and *modifications* from multiple threads at
13//! once, without locking. Actually, even the inner implementation is [lock-free] and the lookups
14//! are [wait-free] (though even the lookup methods may invoke collecting garbage in
15//! [crossbeam-epoch] which while unlikely might contain non-wait-free functions).
16//!
17//! # Downsides
18//!
19//! The concurrent access does not come for free, if you can, you should prefer using the usual
20//! single-threaded alternatives or consider combining them with locks. In particular, there are
21//! several downsides.
22//!
23//! * Under the hood, the [crossbeam-epoch] is used to manage memory. This has the effect that
24//!   removed elements are not deleted at precisely known moment. While the [crossbeam-epoch] is
25//!   usually reasonably fast in collecting garbage, this might be unsuitable for object with
26//!   observable side effects in their destructors (like, containing open files that need to be
27//!   flushed and closed).
28//! * As even after removing an element this element might be still being accessed by another
29//!   thread, there's no way to get an owned access to the original element once it is inserted.
30//!   Depending on the flavour, the data structure either clones the data or returns [`Arc`]s to
31//!   them.
32//! * They are slower in single-threaded usage and use more memory than their standard library
33//!   counter-parts. While the mileage may differ, 2-3 times slowdown was measured in trivial
34//!   benchmarks.
35//! * The order of modifications as seen by different threads may be different (if one thread
36//!   inserts elements `a` and `b`, another thread may see `b` already inserted while `a` still not
37//!   being present). In other words, the existence of values of different keys is considered
38//!   independent on each other. This limitation might be lifted in the future by letting the user
39//!   configure the desired sequentially consistent behaviour at the cost of further slowdown.
40//! * Iteration doesn't take a snapshot at a given time. In other words, if the data structure is
41//!   modified during the iteration (even if by the same thread that iterates), the changes may or
42//!   may not be reflected in the list of iterated elements.
43//! * Iteration pins an epoch for the whole time it iterates, possibly delaying releasing some
44//!   memory. Therefore, it is advised not to hold onto iterators for extended periods of time.
45//! * Because the garbage collection of [crossbeam-epoch] can postpone destroying values for
46//!   arbitrary time, the values and keys stored inside need to be owned (eg. `'static`). This
47//!   limitation will likely be lifted eventually.
48//!
49//! # The gist of the data structure
50//!
51//! Internally, the data structure is an array-mapped trie. At each level there's an array of 16
52//! pointers. They get indexed by 4 bits of the hash of the key. The branches are kept as short as
53//! possible to still distinguish between different hashes (once a subtree contains only one value,
54//! it contains only the data leaf without further intermediate levels). These pointers can be
55//! updated atomically with compare-and-swap operations.
56//!
57//! The idea was inspired by this [article] and [wikipedia entry], but with severe simplifications.
58//! The simplifications were done to lower the number of traversed pointers during operations and
59//! to gain more confidence in correctness of the implementation, however at the cost of the
60//! snapshots for iteration and higher memory consumption. Pruning of the trie of unneeded branches
61//! on removals was preserved.
62//!
63//! For further technical details, arguments of correctness and similar, see the source code and
64//! comments in there, especially the [`raw`] module.
65//!
66//! # Examples
67//!
68//! ```rust
69//! use contrie::ConMap;
70//! use crossbeam_utils::thread;
71//!
72//! let map = ConMap::new();
73//!
74//! thread::scope(|s| {
75//!     s.spawn(|_| {
76//!         map.insert(1, 2);
77//!     });
78//!     s.spawn(|_| {
79//!         map.insert(2, 3);
80//!     });
81//! }).unwrap();
82//!
83//! assert_eq!(3, *map.get(&2).unwrap().value());
84//! ```
85//!
86//! # Features
87//!
88//! If compiled with the `rayon` feature, some parallel traits will be implemented for
89//! the types provided by this crate.
90//!
91//! [wait-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom
92//! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom
93//! [crossbeam-epoch]: https://docs.rs/crossbeam-epoch
94//! [`Arc`]: std::sync::Arc
95//! [article]: https://www.researchgate.net/publication/221643801_Concurrent_Tries_with_Efficient_Non-Blocking_Snapshots
96//! [Wikipedia entry]: https://en.wikipedia.org/wiki/Ctrie
97
98pub mod clonemap;
99mod existing_or_new;
100pub mod map;
101pub mod raw;
102pub mod set;
103// Some integration-like tests live here, instead of crate/tests. This is because this allows cargo
104// to compile them in parallel with the crate and also run them more in parallel. And I like to get
105// all the test failures at once.
106//
107// Interface is tested through doctests anyway.
108#[cfg(test)]
109mod tests;
110
111pub use self::clonemap::CloneConMap;
112pub use self::existing_or_new::ExistingOrNew;
113pub use self::map::ConMap;
114pub use self::set::ConSet;