|
1 |
| -# evmap |
| 1 | +This crate holds the implementation of the `left-right` concurrency |
| 2 | +primitive, and its primary user `evmap`. See the documentation for each |
| 3 | +crate for details. |
| 4 | + |
| 5 | +Left-right is a concurrency primitive for high concurrency reads over a |
| 6 | +single-writer data structure. The primitive keeps two copies of the |
| 7 | +backing data structure, one that is accessed by readers, and one that is |
| 8 | +access by the (single) writer. This enables all reads to proceed in |
| 9 | +parallel with minimal coordination, and shifts the coordination overhead |
| 10 | +to the writer. In the absence of writes, reads scale linearly with the |
| 11 | +number of cores. |
| 12 | + |
| 13 | +[](https://crates.io/crates/left-right) |
| 14 | +[](https://docs.rs/left-right/) |
2 | 15 |
|
3 | 16 | [](https://crates.io/crates/evmap)
|
4 | 17 | [](https://docs.rs/evmap/)
|
| 18 | + |
5 | 19 | [](https://dev.azure.com/jonhoo/jonhoo/_build/latest?definitionId=8&branchName=master)
|
6 | 20 | [](https://codecov.io/gh/jonhoo/rust-evmap)
|
7 | 21 |
|
8 |
| -A lock-free, eventually consistent, concurrent multi-value map. |
9 |
| - |
10 |
| -This map implementation allows reads and writes to execute entirely in parallel, with no |
11 |
| -implicit synchronization overhead. Reads never take locks on their critical path, and neither |
12 |
| -do writes assuming there is a single writer (multi-writer is possible using a `Mutex`), which |
13 |
| -significantly improves performance under contention. |
14 |
| - |
15 |
| -The trade-off exposed by this module is one of eventual consistency: writes are not visible to |
16 |
| -readers except following explicit synchronization. Specifically, readers only see the |
17 |
| -operations that preceeded the last call to `WriteHandle::refresh` by a writer. This lets |
18 |
| -writers decide how stale they are willing to let reads get. They can refresh the map after |
19 |
| -every write to emulate a regular concurrent `HashMap`, or they can refresh only occasionally to |
20 |
| -reduce the synchronization overhead at the cost of stale reads. |
21 |
| - |
22 |
| -For read-heavy workloads, the scheme used by this module is particularly useful. Writers can |
23 |
| -afford to refresh after every write, which provides up-to-date reads, and readers remain fast |
24 |
| -as they do not need to ever take locks. |
25 |
| - |
26 |
| -The map is multi-value, meaning that every key maps to a *collection* of values. This |
27 |
| -introduces some memory cost by adding a layer of indirection through a `Vec` for each value, |
28 |
| -but enables more advanced use. This choice was made as it would not be possible to emulate such |
29 |
| -functionality on top of the semantics of this map (think about it -- what would the operational |
30 |
| -log contain?). |
31 |
| - |
32 |
| -To faciliate more advanced use-cases, each of the two maps also carry some customizeable |
33 |
| -meta-information. The writers may update this at will, and when a refresh happens, the current |
34 |
| -meta will also be made visible to readers. This could be useful, for example, to indicate what |
35 |
| -time the refresh happened. |
36 |
| - |
37 | 22 | ## Performance
|
38 | 23 |
|
| 24 | +**These benchmarks are outdated at this point, but communicate the right |
| 25 | +point. Hopefully I'll have a chance to update them again some time |
| 26 | +soon.** |
| 27 | + |
39 | 28 | I've run some benchmarks of evmap against a standard Rust `HashMap` protected
|
40 | 29 | by a [reader-writer
|
41 | 30 | lock](https://doc.rust-lang.org/std/sync/struct.RwLock.html), as well as
|
|
0 commit comments