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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## v0.15.0 (TBD)

- Fixed `FifoCache::push` creating a ghost eviction entry when called with a key that already exists in the cache. The duplicate queue entry inflated the eviction queue length beyond the number of live map entries, consumed an eviction slot without a corresponding map value, and caused a still-live entry to be prematurely dropped when the ghost surfaced as the oldest key. Existing keys are now updated in-place without modifying the eviction queue.

- Added `ca-certificates` to the node Docker runtime image so outbound `https` connections work in containerized deployments ([#1661](https://github.com/0xMiden/node/issues/1661)).
- Reworked `SyncNotes` store queries to fetch multiple matching blocks within one database transaction while preserving the response payload cap ([#2027](https://github.com/0xMiden/node/pull/2027)).
- Added composite index `idx_transactions_account_block_txid` on `transactions(account_id, block_num, transaction_id)` to speed up `select_transactions_records` queries used by `SyncTransactions` ([#1965](https://github.com/0xMiden/node/issues/1965)).
Expand Down
12 changes: 12 additions & 0 deletions crates/utils/src/fifo_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,20 @@ where
}

/// Inserts a key-value pair, evicting the oldest entry if the cache is at capacity.
/// Inserts or updates `key` with `value`.
///
/// If `key` already exists, its value is updated in-place without touching the eviction
/// queue. Re-enqueueing an existing key would create a ghost entry: the queue would
/// grow beyond the number of live map entries, consume an eviction slot for a key that
/// may no longer exist, and prematurely evict a valid entry when the ghost surfaces as
/// the oldest key.
pub fn push(&self, key: K, value: V) {
let mut inner = self.0.lock().expect("fifo cache lock poisoned");
// Key already in cache: update value in-place, leave eviction queue unchanged.
if inner.map.contains_key(&key) {
inner.map.insert(key, value);
return;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for identifying the bug. However the FIFO behaviour is still not quite right with this fix.

Every time an entry is pushed into the FIFO cache, it should be put (or moved) into the back of the eviction queue. This still doesn't happen after this fix.

I think we have two options as to how to implement this (without an O(n) scan of the eviction queue):

  1. Use a linked hash map (requires external crate) instead of the map and vecdeque; or
  2. A tombstone mechanism which prevents prior entries in the eviction queue from removing entries that were pushed multiple times.

@Mirko-von-Leipzig any thoughts / preference?

if inner.eviction.len() >= inner.capacity.get() {
if let Some(oldest) = inner.eviction.pop_front() {
inner.map.remove(&oldest);
Expand Down