Skip to content

Commit 90cc2aa

Browse files
authored
refactor: improve node cache public API naming and docs (#432)
Clarify the node cache public API before it stabilizes. - Rename `node_cache_size` → `node_cache_num_slots` to avoid ambiguity with byte size - Rename `node_cache_clear_metrics` → `node_cache_reset_metrics` to distinguish from `node_cache_clear` (which evicts nodes *and* resets metrics) - Rename `node_cache_size_bytes_approx` → `node_cache_heap_usage` for brevity - Consolidate cache sizing guidance (0 / 1 / 16 / 32 slot options) on the `DEFAULT_NODE_CACHE_NUM_SLOTS` constant, remove duplicated hardcoded values from method docs - Expand `node_cache_metrics` doctest to show the reset-then-measure pattern - Add accumulation/reset note to `NodeCacheMetrics` struct doc
1 parent e9d9f45 commit 90cc2aa

2 files changed

Lines changed: 43 additions & 16 deletions

File tree

src/btreemap.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,18 @@ const PAGE_SIZE_VALUE_MARKER: u32 = u32::MAX;
8787

8888
/// Default number of slots in the direct-mapped node cache.
8989
///
90-
/// 16 slots cover the top two tree levels (1 root + up to 12 children =
91-
/// 13 nodes) while keeping heap usage modest.
90+
/// Sizing options (prefer powers of two for efficient slot indexing):
91+
///
92+
/// - **0** — cache disabled, every access reads from stable memory.
93+
/// - **1** — only the root node is cached; saves one read per operation.
94+
/// - **16** — covers the top two tree levels (1 root + up to 12
95+
/// children = 13 nodes). Good balance of hit rate and heap usage.
96+
/// - **32** — extra headroom over 16 that reduces collision evictions
97+
/// in the direct-mapped scheme and typically yields ≥2 cache hits
98+
/// per operation regardless of tree size.
9299
///
93100
/// Users can adjust via [`BTreeMap::with_node_cache`] or
94-
/// [`BTreeMap::node_cache_resize`], including setting to 0 to disable.
101+
/// [`BTreeMap::node_cache_resize`].
95102
const DEFAULT_NODE_CACHE_NUM_SLOTS: usize = 16;
96103

97104
/// A B-Tree map implementation that stores its data into a designated memory.
@@ -312,14 +319,8 @@ where
312319
/// Each slot can hold one deserialized node; on collision, shallower
313320
/// nodes (closer to the root) are kept over deeper ones.
314321
///
315-
/// Pass `0` to disable the cache (the default).
316-
///
317-
/// The top 2 levels of the tree contain 13 nodes (1 root + up to
318-
/// 12 children). **16** slots is the smallest power of two that
319-
/// covers them, but a direct-mapped cache is sensitive to address
320-
/// collisions, so **32** is a safer default that leaves headroom
321-
/// and typically gives 2 cache hits per operation regardless of
322-
/// tree size. Prefer powers of two for efficient slot indexing.
322+
/// The cache is enabled by default. Pass `0` to disable.
323+
/// Prefer powers of two for efficient slot indexing.
323324
///
324325
/// # Examples
325326
///
@@ -365,7 +366,7 @@ where
365366
/// Returns the current number of slots in the node cache.
366367
///
367368
/// Returns `0` when the cache is disabled.
368-
pub fn node_cache_size(&self) -> usize {
369+
pub fn node_cache_num_slots(&self) -> usize {
369370
self.cache.borrow().num_slots()
370371
}
371372

@@ -377,12 +378,22 @@ where
377378

378379
/// Resets cache metrics (hit/miss counters) without evicting
379380
/// cached nodes.
380-
pub fn node_cache_clear_metrics(&mut self) {
381+
///
382+
/// Call this before the workload you want to measure so that
383+
/// counters reflect only that workload, not the entire lifetime
384+
/// of the map.
385+
pub fn node_cache_reset_metrics(&mut self) {
381386
self.cache.get_mut().clear_metrics();
382387
}
383388

384389
/// Returns node-cache performance metrics.
385390
///
391+
/// Counters accumulate from map creation (or the last call to
392+
/// [`node_cache_reset_metrics`](Self::node_cache_reset_metrics))
393+
/// and are never cleared automatically. To measure a specific
394+
/// workload, call `node_cache_reset_metrics` first, run the
395+
/// workload, then read the metrics.
396+
///
386397
/// # Examples
387398
///
388399
/// ```rust
@@ -391,8 +402,19 @@ where
391402
/// let mut map: BTreeMap<u64, u64, _> =
392403
/// BTreeMap::init(DefaultMemoryImpl::default())
393404
/// .with_node_cache(32);
394-
/// map.insert(1, 100);
395-
/// let _ = map.get(&1);
405+
///
406+
/// // Populate the map (metrics accumulate during inserts).
407+
/// for i in 0..100u64 {
408+
/// map.insert(i, i);
409+
/// }
410+
///
411+
/// // Clear counters before the workload we care about.
412+
/// map.node_cache_reset_metrics();
413+
///
414+
/// // Workload: read every key.
415+
/// for i in 0..100u64 {
416+
/// let _ = map.get(&i);
417+
/// }
396418
///
397419
/// let metrics = map.node_cache_metrics();
398420
/// println!("hit ratio: {:.1}%", metrics.hit_ratio() * 100.0);
@@ -406,7 +428,7 @@ where
406428
/// Actual usage depends on key size and how many slots are
407429
/// occupied. Treat this as an order-of-magnitude guide, not a
408430
/// precise budget.
409-
pub fn node_cache_size_bytes_approx(&self) -> usize {
431+
pub fn node_cache_heap_usage(&self) -> usize {
410432
self.cache.borrow().num_slots()
411433
* (self.version.page_size().get() as usize + NodeCache::<K>::slot_size())
412434
}

src/btreemap/node_cache.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ use crate::Storable;
44
use super::node::Node;
55

66
/// Node-cache performance metrics.
7+
///
8+
/// Counters accumulate over the lifetime of the cache and are **never
9+
/// cleared automatically**. To measure a specific workload, call
10+
/// [`BTreeMap::node_cache_reset_metrics`](super::BTreeMap::node_cache_reset_metrics)
11+
/// before the workload, then read the metrics afterward.
712
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
813
pub struct NodeCacheMetrics {
914
/// Successful cache lookups.

0 commit comments

Comments
 (0)