Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions rust/crates/monad-triedb/include/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,30 @@ typedef struct triedb_storage_stats

void triedb_storage_stats_read(TriedbRoInner *, triedb_storage_stats *out);

// Trie-node LRU counters for this handle. Totals since the handle was opened;
// reading does not reset them. `used_bytes` is against the node_lru_max_mem
// the handle was opened with, and `entries` against the slot count derived
// from it — compare the two to see which bound is binding.
//
// Covers the async paths only: triedb_async_read, triedb_async_traverse and
// triedb_async_ranged_get. triedb_read and triedb_traverse are blocking and
// consult no cache, so a caller using only those sees zeros here — which is
// not the same as an unused cache.
//
// Returns false without writing `out` if no counters are available; all-zero
// is a legitimate reading for an idle cache, so it cannot double as an error.
typedef struct triedb_node_cache_stats
{
uint64_t hits;
uint64_t misses;
uint64_t evictions;
uint64_t used_bytes;
uint64_t entries;
} triedb_node_cache_stats;

bool triedb_node_cache_stats_read(
TriedbRoInner *, triedb_node_cache_stats *out);
Comment on lines +75 to +87

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] The header advertises a "no counters available" false-return, but the implementation in ffi.cpp only returns false when db == nullptr or out == nullptr — a well-formed caller can never observe a non-null false. Cascading to TriedbHandle::node_cache_stats -> Option<NodeCacheStats>, the None branch is unreachable (self.db_ptr is non-null for any TriedbHandle produced by try_new), which defeats the commit-message intent to mirror triedb_storage_stats_read. Either drop the boolean return (and the Rust Option) to match the storage-stats shape, or tighten the doc to say the boolean signals only null-pointer misuse.


// Compute the storage page key for a 32-byte slot key on a page-encoded db:
// page_key = slot >> 7. Writes the 32-byte big-endian page key (the key the
// storage trie is looked up by) to out_page_key.
Expand Down
17 changes: 17 additions & 0 deletions rust/crates/monad-triedb/src/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,23 @@ void triedb_storage_stats_read(
out->disk_used_bytes = stats.disk_used_bytes;
}

bool triedb_node_cache_stats_read(
TriedbRoInner *const db, triedb_node_cache_stats *const out)
{
if (out == nullptr || db == nullptr) {
return false;
}
*out = {};
auto const &cache = db->async_ctx.node_cache;
auto const stats = cache.stats();
out->hits = stats.hits;
out->misses = stats.misses;
out->evictions = stats.evictions;
out->used_bytes = static_cast<uint64_t>(cache.used_bytes());
out->entries = static_cast<uint64_t>(cache.size());
Comment on lines +208 to +209
return true;
}

void triedb_compute_page_key(
uint8_t const *const slot_key, uint8_t *const out_page_key)
{
Expand Down
6 changes: 3 additions & 3 deletions rust/crates/monad-triedb/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ pub(crate) use self::bindings::{
triedb_earliest_version, triedb_finalize, triedb_free_valset, triedb_is_page_encoded,
triedb_latest_finalized_version, triedb_latest_proposed_block_id,
triedb_latest_proposed_version, triedb_latest_verified_version, triedb_latest_voted_block_id,
triedb_latest_voted_version, triedb_migration_phase, triedb_open, triedb_poll, triedb_read,
triedb_read_valset, triedb_storage_stats, triedb_storage_stats_read, triedb_traverse,
TriedbRoInner,
triedb_latest_voted_version, triedb_migration_phase, triedb_node_cache_stats,
triedb_node_cache_stats_read, triedb_open, triedb_poll, triedb_read, triedb_read_valset,
triedb_storage_stats, triedb_storage_stats_read, triedb_traverse, TriedbRoInner,
};
pub use self::bindings::{validator_data, validator_set};

Expand Down
40 changes: 40 additions & 0 deletions rust/crates/monad-triedb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ pub struct StorageStats {
pub disk_used_bytes: u64,
}

/// Trie-node LRU counters for one handle. Totals since the handle was opened;
/// reading does not reset them, so a scraper derives its own rates.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct NodeCacheStats {
pub hits: u64,
pub misses: u64,
pub evictions: u64,
/// Bytes of cached nodes, against the handle's `node_lru_max_mem`.
pub used_bytes: u64,
/// Cached nodes, against the slot count derived from `node_lru_max_mem`.
/// Compare with `used_bytes` to see which of the two bounds is binding.
pub entries: u64,
}

struct SenderContext {
sender: Sender<Option<Vec<u8>>>,
completed_counter: Arc<AtomicUsize>,
Expand Down Expand Up @@ -303,6 +317,32 @@ impl TriedbHandle {
}
}

/// Trie-node LRU counters for this handle. Each handle owns an independent
/// cache, so these are per-handle and not comparable across handles.
///
/// Only the async paths consult the cache. Both [`Self::read`] and
/// synchronous traversal are blocking and uncached, so a caller using only
/// those sees zeros.
pub fn node_cache_stats(&self) -> Option<NodeCacheStats> {
let mut out = ffi::triedb_node_cache_stats {
hits: 0,
misses: 0,
evictions: 0,
used_bytes: 0,
entries: 0,
};
if !unsafe { ffi::triedb_node_cache_stats_read(self.db_ptr, &mut out) } {
return None;
}
Some(NodeCacheStats {
hits: out.hits,
misses: out.misses,
evictions: out.evictions,
used_bytes: out.used_bytes,
entries: out.entries,
})
}

pub fn read(&self, key: &[u8], key_len_nibbles: u8, block_id: u64) -> Option<Vec<u8>> {
validate_nibble_key(key, key_len_nibbles, "Key")?;

Expand Down
Loading