Skip to main content

Crate embed_btree

Crate embed_btree 

Source
Expand description

§embed-btree

We provide a BTreeMap for single-threaded in-memory storage. It’s b+tree designed

  • cache-aware principles,
    • All page is aligned in 4*CACHE_LINE (256 bytes on x86_64).
    • Use Layout API to determine the capacity, offset and alignment for the keys and values.
    • Keys is a tight array to enable efficient forward search for CPU pipeline.
    • No parent pointer in the page, saving the space.
      • we fill reused PathBuffer during descending, and pop when working upward.
      • PathBuffer only used during ops that require mutation of the map, so it’s safe for concurrent reads.
    • Avoid memory fragmentation for the allocator.

There tree variants:

  • various_map:
    • Delay page allocation by inlining K, V with option.
    • Fallback to std BTreeMap after inserting the 2nd element
  • compact
    • For short-lived, small size tree.
    • Avoid allocation of PathBuffer on heap, until the tree height grows pass threshold. (>4 for insert/remove, >2 for entry ops)
    • PathBuffer allocation is reused.
  • large
    • For long-lived, large size tree.
    • after tree height grows beyond 1, allocate a small heap for PathBuffer, and page statistic (inter and leavse).

§Supported K, V types

Optimised for numeric key

  • Respecting numeric space, more compact tree when doing sequential insertion
  • Reduce latency for sequential get and insertion.

Optimised for unbalanced size K / V, and specially 0-size V, for most capacity.

Bytes keys on the heap are supported, but we will not do prefix compress. (You may look for other structures with prefix compression: Art, Masstree)

Limits:

  • K should have Clone (for propagate into the InterNode during split)
  • K + V should < 2 * CACHE_LINE_SIZE
    • compile error will be raised if size requirement not met.
    • It make sure InterNode can hold at least two children.
    • If K & V is large you should put into Box, for room saving, and for the speed to move value
  • K should not contains and reference.
    • Although our BTreeMap<K, ()> will act like a btree set, it should only work for integer and string (or composite) keys.
    • DO NOT use Arc<T> as K, it might still keep the reference after value is removed from the map (only can ganrantee release until all InterNode is destroy).

§Compared to std btree_map

(Analyse based on source of rust 1.94)

std:

  • pure btree (without horizontal links).
  • Each key store only once at either leaf and inter nodes, don’t require key to be Clone.
  • good for point lookup (value may be at top level)
  • has fixed Cap=11, node size varies according to T. (For T=U64, size is 288B for InterNode and 192B for LeafNode)
  • the size of page varies for different type of K / V, might not perfectly aligned for the cache and allocator.
  • each page has keys, values, pointers. the section of pointers may be wasted for leaves.
  • cursor API is still unstable, need nightly.

crate::bptree:

  • faster sequential get & insert
  • faster iteration
  • faster teardown
  • higher fan-out, reduction in height

Struct size:

std: BTreeMap<u32, u32>: 24
std: Option<BTreeMap<u32, u32>>: 32
std: VacantEntry<u32, u32>: 40
std: OccupiedEntry<u32, u32>: 32

compact: BTreeMap<u32, u32>: 24
compact: Option<BTreeMap<u32, u32>>: 24
compact: Entry<u32,u32>:  32
compact: Option<Entry<u32, u32>>:  40
compact: VacantEntry<u32, u32>: 32
compact: OccupiedEntry<u32, u32>: 24

large: BTreeMap 24
large: Option<BTreeMap> 24
large: Entry size: 24
large: Option<Entry>: 32
large: VacantEntry<u32, u32>: 24
large: OccupiedEntry<u32, u32>: 16

§Special API and Scenario

statistic (node count and memory usage) in large variant

Entries:

Batch removal:

Readonly Cursor:

Use case:

§benchmark

platform: intel i7-8550U, key: u32, value: u32, rust 1.97.

Measured in million ops for different size of dataset:

insert_seqcompactlargestd
1k84.77791.14020.001
10k72.02279.06016.04
1m44.86346.20011.207
insert_randcompactlargestdavl(box)avl(arc)
1k21.45922.28417.79211.1729.5397
10k13.93114.31911.5876.36695.651
1M5.81245.97103.06910.780.732
get_seqcompactlargestd
1k59.21462.89134.248
10k40.65241.82327.571
1M30.64032.59719.907
get_randcompactlargestdavl(box)avl(arc)
1k52.21351.23027.65124.25423.466
10k22.11720.89416.86811.77110.806
1M6.13696.24033.25691.44231.2712
remove_randcompactlargestd
1k18.33619.96315.968
10k14.09415.46211.701
1M5.22625.47133.0724
itercompactlargestd
1k1423,31443.2346.8
10k1226.31286.9303.83
1M217.10215.9551.147
into_itercompactlargestd
1k364.14396.07143.81
10k356.85410.3281.389
1M327.87360.1856.742

Re-exports§

pub use various_map::VariousMap;
pub use bptree::Key;
pub use bptree::Value;

Modules§

bptree
generic interface of b+tree
compact
BtreeMap with no stats (for many short-live dataset)
large
BtreeMap with stats (for large love-live dataset)
various_map
VariousMap: Provide a tempoary map optimise for empty or one condition, to delay allocation.

Macros§

print_log
logging macro for development
trace_log
logging macro for development

Constants§

CACHE_LINE_SIZE
Cache line size in bytes

Type Aliases§

BTreeMap