diff --git a/runtime/src/read_only_accounts_cache.rs b/runtime/src/read_only_accounts_cache.rs index 0532a570596d53..f3145bc8651821 100644 --- a/runtime/src/read_only_accounts_cache.rs +++ b/runtime/src/read_only_accounts_cache.rs @@ -9,7 +9,7 @@ use { pubkey::Pubkey, }, std::sync::{ - atomic::{AtomicU64, AtomicUsize, Ordering}, + atomic::{AtomicU32, AtomicU64, AtomicUsize, Ordering}, Mutex, }, }; @@ -22,7 +22,7 @@ type ReadOnlyCacheKey = (Pubkey, Slot); #[derive(Debug)] struct ReadOnlyAccountCacheEntry { account: AccountSharedData, - index: Index, // Index of the entry in the eviction queue. + index: AtomicU32, // Index of the entry in the eviction queue. } #[derive(Debug)] @@ -72,7 +72,7 @@ impl ReadOnlyAccountsCache { pub(crate) fn load(&self, pubkey: Pubkey, slot: Slot) -> Option { let key = (pubkey, slot); - let Some(mut entry) = self.cache.get_mut(&key) else { + let Some(entry) = self.cache.get(&key) else { self.misses.fetch_add(1, Ordering::Relaxed); return None; }; @@ -82,8 +82,8 @@ impl ReadOnlyAccountsCache { // so that another thread cannot write to the same key. { let mut queue = self.queue.lock().unwrap(); - queue.remove(entry.index); - entry.index = queue.insert_last(key); + queue.remove(entry.index()); + entry.set_index(queue.insert_last(key)); } Some(entry.account.clone()) } @@ -103,7 +103,7 @@ impl ReadOnlyAccountsCache { // Insert the entry at the end of the queue. let mut queue = self.queue.lock().unwrap(); let index = queue.insert_last(key); - entry.insert(ReadOnlyAccountCacheEntry { account, index }); + entry.insert(ReadOnlyAccountCacheEntry::new(account, index)); } Entry::Occupied(mut entry) => { let entry = entry.get_mut(); @@ -112,8 +112,8 @@ impl ReadOnlyAccountsCache { entry.account = account; // Move the entry to the end of the queue. let mut queue = self.queue.lock().unwrap(); - queue.remove(entry.index); - entry.index = queue.insert_last(key); + queue.remove(entry.index()); + entry.set_index(queue.insert_last(key)); } }; // Evict entries from the front of the queue. @@ -133,7 +133,7 @@ impl ReadOnlyAccountsCache { // self.queue should be modified only after removing the entry from the // cache, so that this is still safe if another thread writes to the // same key. - self.queue.lock().unwrap().remove(entry.index); + self.queue.lock().unwrap().remove(entry.index()); let account_size = self.account_size(&entry.account); self.data_size.fetch_sub(account_size, Ordering::Relaxed); Some(entry.account) @@ -156,6 +156,26 @@ impl ReadOnlyAccountsCache { } } +impl ReadOnlyAccountCacheEntry { + fn new(account: AccountSharedData, index: Index) -> Self { + let index = unsafe { std::mem::transmute::(index) }; + let index = AtomicU32::new(index); + Self { account, index } + } + + #[inline] + fn index(&self) -> Index { + let index = self.index.load(Ordering::Relaxed); + unsafe { std::mem::transmute::(index) } + } + + #[inline] + fn set_index(&self, index: Index) { + let index = unsafe { std::mem::transmute::(index) }; + self.index.store(index, Ordering::Relaxed); + } +} + #[cfg(test)] mod tests { use {