Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add PersistentDict based on a HAMT (#51164)
The implementation is based on a [Hash Array Mapped Trie (HAMT)](https://en.wikipedia.org/wiki/Hash_array_mapped_trie) following [Bagwell (2000)](http:https://infoscience.epfl.ch/record/64398/files/idealhashtrees.pdf). A HAMT uses a fixed branching factor (commonly 32) together with each node being sparse. In order to search for an entry we take the hash of the key and chunk it up into blocks, with a branching factor of 32 each block is 5 bits. We use those 5 bits to calculate the index inside the node and use a bitmap within the node to keep track if an element is already set. This makes search a `log(32, n)` operation. Persistency is implemented by path-copying. When we insert/delete a value into the HAMT we copy each node along the path into a new HAMT, all other nodes are shared with the previous HAMT. A noteable implementation choice is that I didn't add a (resizeable) root table. Normally this root table is dense and uses the first `t` bits to calculate an index within. This makes large HAMT a bit cheaper since the root-table effectivly folds multiple lookup steps into one. It does hurt persistent use-cases since path-copying means that we also copy the root node/table. Importantly the HAMT itself is not immutable/persistent, the use of it as part of the `PersistentDict` is. Direct mutation of the underlying data breaks the persistentcy invariants. One could use the HAMT to implement a non-persistent dictionary (or other datastructures). As an interesting side-note we could use a related data-structure [Ctrie](http:https://lamp.epfl.ch/~prokopec/ctries-snapshot.pdf) to implement a concurrent lock-free dictionary. Ctrie also support `O(1)` snapshotting so we could replace the HAMT used here with a Ctrie.
- Loading branch information