read only accounts cache uses accurate size representation (#16610)
* read ony accounts cache uses accurate size representation * add comment and test
This commit is contained in:
committed by
GitHub
parent
bc90e04e64
commit
36e11998c7
@ -33,6 +33,7 @@ pub struct ReadOnlyAccountsCache {
|
|||||||
hits: AtomicU64,
|
hits: AtomicU64,
|
||||||
misses: AtomicU64,
|
misses: AtomicU64,
|
||||||
lru: LruList,
|
lru: LruList,
|
||||||
|
per_account_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadOnlyAccountsCache {
|
impl ReadOnlyAccountsCache {
|
||||||
@ -44,9 +45,15 @@ impl ReadOnlyAccountsCache {
|
|||||||
hits: AtomicU64::new(0),
|
hits: AtomicU64::new(0),
|
||||||
misses: AtomicU64::new(0),
|
misses: AtomicU64::new(0),
|
||||||
lru: Arc::new(RwLock::new(Vec::new())),
|
lru: Arc::new(RwLock::new(Vec::new())),
|
||||||
|
per_account_size: Self::per_account_size(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn per_account_size() -> usize {
|
||||||
|
// size_of(arc(x)) does not return the size of x, so we have to add the size of RwLock...
|
||||||
|
std::mem::size_of::<ReadOnlyAccountCacheEntry>() + std::mem::size_of::<RwLock<Instant>>()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load(&self, pubkey: &Pubkey, slot: Slot) -> Option<AccountSharedData> {
|
pub fn load(&self, pubkey: &Pubkey, slot: Slot) -> Option<AccountSharedData> {
|
||||||
self.cache
|
self.cache
|
||||||
.get(&(*pubkey, slot))
|
.get(&(*pubkey, slot))
|
||||||
@ -65,7 +72,7 @@ impl ReadOnlyAccountsCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn store(&self, pubkey: &Pubkey, slot: Slot, account: &AccountSharedData) {
|
pub fn store(&self, pubkey: &Pubkey, slot: Slot, account: &AccountSharedData) {
|
||||||
let len = account.data().len();
|
let len = account.data().len() + self.per_account_size;
|
||||||
self.cache.insert(
|
self.cache.insert(
|
||||||
(*pubkey, slot),
|
(*pubkey, slot),
|
||||||
ReadOnlyAccountCacheEntry {
|
ReadOnlyAccountCacheEntry {
|
||||||
@ -129,7 +136,7 @@ impl ReadOnlyAccountsCache {
|
|||||||
let mut new_size = 0;
|
let mut new_size = 0;
|
||||||
for item in self.cache.iter() {
|
for item in self.cache.iter() {
|
||||||
let value = item.value();
|
let value = item.value();
|
||||||
let item_len = value.account.data().len();
|
let item_len = value.account.data().len() + self.per_account_size;
|
||||||
new_size += item_len;
|
new_size += item_len;
|
||||||
lru.push((*value.last_used.read().unwrap(), item_len, *item.key()));
|
lru.push((*value.last_used.read().unwrap(), item_len, *item.key()));
|
||||||
}
|
}
|
||||||
@ -178,10 +185,19 @@ impl ReadOnlyAccountsCache {
|
|||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use solana_sdk::account::{accounts_equal, Account};
|
use solana_sdk::account::{accounts_equal, Account};
|
||||||
|
#[test]
|
||||||
|
fn test_accountsdb_sizeof() {
|
||||||
|
// size_of(arc(x)) does not return the size of x
|
||||||
|
assert!(std::mem::size_of::<Arc<u64>>() == std::mem::size_of::<Arc<u8>>());
|
||||||
|
assert!(std::mem::size_of::<Arc<u64>>() == std::mem::size_of::<Arc<[u8; 32]>>());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_read_only_accounts_cache() {
|
fn test_read_only_accounts_cache() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
let max = 100;
|
let per_account_size = ReadOnlyAccountsCache::per_account_size();
|
||||||
|
let data_size = 100;
|
||||||
|
let max = data_size + per_account_size;
|
||||||
let cache = ReadOnlyAccountsCache::new(max);
|
let cache = ReadOnlyAccountsCache::new(max);
|
||||||
let slot = 0;
|
let slot = 0;
|
||||||
assert!(cache.load(&Pubkey::default(), slot).is_none());
|
assert!(cache.load(&Pubkey::default(), slot).is_none());
|
||||||
@ -192,7 +208,7 @@ pub mod tests {
|
|||||||
let key2 = Pubkey::new_unique();
|
let key2 = Pubkey::new_unique();
|
||||||
let key3 = Pubkey::new_unique();
|
let key3 = Pubkey::new_unique();
|
||||||
let account1 = AccountSharedData::from(Account {
|
let account1 = AccountSharedData::from(Account {
|
||||||
data: vec![0; max],
|
data: vec![0; data_size],
|
||||||
..Account::default()
|
..Account::default()
|
||||||
});
|
});
|
||||||
let mut account2 = account1.clone();
|
let mut account2 = account1.clone();
|
||||||
@ -200,40 +216,40 @@ pub mod tests {
|
|||||||
let mut account3 = account1.clone();
|
let mut account3 = account1.clone();
|
||||||
account3.lamports += 4; // so they compare differently
|
account3.lamports += 4; // so they compare differently
|
||||||
cache.store(&key1, slot, &account1);
|
cache.store(&key1, slot, &account1);
|
||||||
assert_eq!(100, cache.data_size());
|
assert_eq!(100 + per_account_size, cache.data_size());
|
||||||
assert!(accounts_equal(&cache.load(&key1, slot).unwrap(), &account1));
|
assert!(accounts_equal(&cache.load(&key1, slot).unwrap(), &account1));
|
||||||
assert_eq!(1, cache.cache_len());
|
assert_eq!(1, cache.cache_len());
|
||||||
cache.store(&key2, slot, &account2);
|
cache.store(&key2, slot, &account2);
|
||||||
assert_eq!(100, cache.data_size());
|
assert_eq!(100 + per_account_size, cache.data_size());
|
||||||
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account2));
|
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account2));
|
||||||
assert_eq!(1, cache.cache_len());
|
assert_eq!(1, cache.cache_len());
|
||||||
cache.store(&key2, slot, &account1); // overwrite key2 with account1
|
cache.store(&key2, slot, &account1); // overwrite key2 with account1
|
||||||
assert_eq!(100, cache.data_size());
|
assert_eq!(100 + per_account_size, cache.data_size());
|
||||||
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account1));
|
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account1));
|
||||||
assert_eq!(1, cache.cache_len());
|
assert_eq!(1, cache.cache_len());
|
||||||
cache.remove(&key2, slot);
|
cache.remove(&key2, slot);
|
||||||
assert_eq!(100, cache.data_size());
|
assert_eq!(100 + per_account_size, cache.data_size());
|
||||||
assert_eq!(0, cache.cache_len());
|
assert_eq!(0, cache.cache_len());
|
||||||
|
|
||||||
// can store 2 items, 3rd item kicks oldest item out
|
// can store 2 items, 3rd item kicks oldest item out
|
||||||
let max = 200;
|
let max = (data_size + per_account_size) * 2;
|
||||||
let cache = ReadOnlyAccountsCache::new(max);
|
let cache = ReadOnlyAccountsCache::new(max);
|
||||||
cache.store(&key1, slot, &account1);
|
cache.store(&key1, slot, &account1);
|
||||||
assert_eq!(100, cache.data_size());
|
assert_eq!(100 + per_account_size, cache.data_size());
|
||||||
assert!(accounts_equal(&cache.load(&key1, slot).unwrap(), &account1));
|
assert!(accounts_equal(&cache.load(&key1, slot).unwrap(), &account1));
|
||||||
assert_eq!(1, cache.cache_len());
|
assert_eq!(1, cache.cache_len());
|
||||||
cache.store(&key2, slot, &account2);
|
cache.store(&key2, slot, &account2);
|
||||||
assert_eq!(200, cache.data_size());
|
assert_eq!(max, cache.data_size());
|
||||||
assert!(accounts_equal(&cache.load(&key1, slot).unwrap(), &account1));
|
assert!(accounts_equal(&cache.load(&key1, slot).unwrap(), &account1));
|
||||||
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account2));
|
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account2));
|
||||||
assert_eq!(2, cache.cache_len());
|
assert_eq!(2, cache.cache_len());
|
||||||
cache.store(&key2, slot, &account1); // overwrite key2 with account1
|
cache.store(&key2, slot, &account1); // overwrite key2 with account1
|
||||||
assert_eq!(200, cache.data_size());
|
assert_eq!(max, cache.data_size());
|
||||||
assert!(accounts_equal(&cache.load(&key1, slot).unwrap(), &account1));
|
assert!(accounts_equal(&cache.load(&key1, slot).unwrap(), &account1));
|
||||||
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account1));
|
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account1));
|
||||||
assert_eq!(2, cache.cache_len());
|
assert_eq!(2, cache.cache_len());
|
||||||
cache.store(&key3, slot, &account3);
|
cache.store(&key3, slot, &account3);
|
||||||
assert_eq!(200, cache.data_size());
|
assert_eq!(max, cache.data_size());
|
||||||
assert!(cache.load(&key1, slot).is_none()); // was lru purged
|
assert!(cache.load(&key1, slot).is_none()); // was lru purged
|
||||||
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account1));
|
assert!(accounts_equal(&cache.load(&key2, slot).unwrap(), &account1));
|
||||||
assert!(accounts_equal(&cache.load(&key3, slot).unwrap(), &account3));
|
assert!(accounts_equal(&cache.load(&key3, slot).unwrap(), &account3));
|
||||||
|
Reference in New Issue
Block a user