sled/doc/merge_operators/mod.rs
1//! Merge operators are an extremely powerful tool for use in embedded kv
2//! stores. They allow users to specify custom logic for combining multiple
3//! versions of a value into one.
4//!
5//! As a motivating example, imagine that you have a counter. In a traditional
6//! kv store, you would need to read the old value, modify it, then write it
7//! back (RMW). If you want to increment the counter from multiple threads, you
8//! would need to either use higher-level locking or you need to spin in a CAS
9//! loop until your increment is successful. Merge operators remove the need for
10//! all of this by allowing multiple threads to "merge" in the desired
11//! operation, rather than performing a read, then modification, then later
12//! writing. `+1 -> +1 -> +1` instead of `w(r(key) + 1) -> w(r(key)+ 1) ->
13//! w(r(key) + 1)`.
14//!
15//! Here's an example of using a merge operator to just concatenate merged bytes
16//! together. Note that calling `set` acts as a value replacement, bypassing the
17//! merging logic and replacing previously merged values. Calling `merge` is
18//! like `set` but when the key is fetched, it will use the merge operator to
19//! combine all `merge`'s since the last `set`.
20//!
21//! ```rust
22//! fn concatenate_merge(
23//! _key: &[u8], // the key being merged
24//! old_value: Option<&[u8]>, // the previous value, if one existed
25//! merged_bytes: &[u8] // the new bytes being merged in
26//! ) -> Option<Vec<u8>> { // set the new value, return None to delete
27//! let mut ret = old_value
28//! .map(|ov| ov.to_vec())
29//! .unwrap_or_else(|| vec![]);
30//!
31//! ret.extend_from_slice(merged_bytes);
32//!
33//! Some(ret)
34//! }
35//!
36//! let config = ConfigBuilder::new()
37//! .temporary(true)
38//! .build();
39//!
40//! let tree = Tree::start(config).unwrap();
41//! tree.set_merge_operator(concatenate_merge);
42//!
43//! tree.set(k, vec![0]);
44//! tree.merge(k, vec![1]);
45//! tree.merge(k, vec![2]);
46//! assert_eq!(tree.get(&k), Ok(Some(vec![0, 1, 2])));
47//!
48//! // sets replace previously merged data,
49//! // bypassing the merge function.
50//! tree.set(k, vec![3]);
51//! assert_eq!(tree.get(&k), Ok(Some(vec![3])));
52//!
53//! // merges on non-present values will add them
54//! tree.del(&k);
55//! tree.merge(k, vec![4]);
56//! assert_eq!(tree.get(&k), Ok(Some(vec![4])));
57//! ```
58//!
59//! ### beyond the basics
60//!
61//! Merge operators can be used to express arbitrarily complex logic. You can
62//! use them to implement any sort of high-level data structure on top of sled,
63//! using merges of different values to represent your desired operations.
64//! Similar to the above example, you could implement a list that lets you push
65//! items. Bloom filters are particularly easy to implement, and merge operators
66//! also are quite handy for building persistent CRDTs.
67//!
68//! ### warnings
69//!
70//! If you call `merge` without setting a merge operator, an error will be
71//! returned. Merge operators may be changed over time, but make sure you do
72//! this carefully to avoid race conditions. If you need to push a one-time
73//! operation to a value, use `update_and_fetch` or `fetch_and_update` instead.