Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 2f63828

Browse files
committed
API to read account meta data from storage
1 parent 7fb2fc6 commit 2f63828

File tree

2 files changed

+178
-1
lines changed

2 files changed

+178
-1
lines changed

runtime/src/accounts_db.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
//! tracks the number of commits to the entire data store. So the latest
1919
//! commit for each slot entry would be indexed.
2020

21+
use crate::append_vec::AccountMeta;
2122
use {
2223
crate::{
2324
account_info::{AccountInfo, Offset, StorageLocation, StoredSize},
@@ -809,6 +810,29 @@ impl<'a> LoadedAccountAccessor<'a> {
809810
}
810811
}
811812
}
813+
814+
fn get_account_meta(&self) -> Option<AccountMeta> {
815+
match self {
816+
LoadedAccountAccessor::Cached(cached_account) => {
817+
cached_account.as_ref().map(|cached_account| AccountMeta {
818+
lamports: cached_account.account.lamports(),
819+
rent_epoch: cached_account.account.rent_epoch(),
820+
owner: cached_account.account.owner().clone(),
821+
executable: cached_account.account.executable(),
822+
})
823+
}
824+
LoadedAccountAccessor::Stored(maybe_storage_entry) => {
825+
// storage entry may not be present if slot was cleaned up in
826+
// between reading the accounts index and calling this function to
827+
// get account meta from the storage entry here
828+
maybe_storage_entry
829+
.as_ref()
830+
.and_then(|(storage_entry, offset)| {
831+
storage_entry.accounts.get_account_meta(*offset)
832+
})
833+
}
834+
}
835+
}
812836
}
813837

814838
pub enum LoadedAccount<'a> {
@@ -4913,6 +4937,33 @@ impl AccountsDb {
49134937
self.do_load(ancestors, pubkey, None, load_hint, LoadZeroLamports::None)
49144938
}
49154939

4940+
pub fn get_account_meta(&self, ancestors: &Ancestors, pubkey: &Pubkey) -> Option<AccountMeta> {
4941+
let (slot, storage_location, _maybe_account_accesor) =
4942+
self.read_index_for_accessor_or_load_slow(ancestors, pubkey, None, false)?;
4943+
4944+
if !storage_location.is_cached() {
4945+
let result = self.read_only_accounts_cache.load(*pubkey, slot);
4946+
if let Some(account) = result {
4947+
return Some(AccountMeta {
4948+
lamports: account.lamports(),
4949+
rent_epoch: account.rent_epoch(),
4950+
owner: account.owner().clone(),
4951+
executable: account.executable(),
4952+
});
4953+
}
4954+
}
4955+
4956+
let (account_accessor, _slot) = self.retry_to_get_account_accessor(
4957+
slot,
4958+
storage_location,
4959+
ancestors,
4960+
pubkey,
4961+
None,
4962+
LoadHint::Unspecified,
4963+
)?;
4964+
account_accessor.get_account_meta()
4965+
}
4966+
49164967
pub fn load_account_into_read_cache(&self, ancestors: &Ancestors, pubkey: &Pubkey) {
49174968
self.do_load_with_populate_read_cache(
49184969
ancestors,
@@ -14082,6 +14133,71 @@ pub mod tests {
1408214133
assert_eq!(db.read_only_accounts_cache.cache_len(), 1);
1408314134
}
1408414135

14136+
#[test]
14137+
fn test_get_account_meta() {
14138+
let db = Arc::new(AccountsDb::new_with_config_for_tests(
14139+
Vec::new(),
14140+
&ClusterType::Development,
14141+
AccountSecondaryIndexes::default(),
14142+
AccountShrinkThreshold::default(),
14143+
));
14144+
14145+
let account1_key = Pubkey::new_unique();
14146+
let owner1_key = Pubkey::new_unique();
14147+
let account1 = AccountSharedData::new(321, 10, &owner1_key);
14148+
14149+
let account2_key = Pubkey::new_unique();
14150+
let owner2_key = Pubkey::new_unique();
14151+
let account2 = AccountSharedData::new(1, 1, &owner2_key);
14152+
14153+
db.store_cached((0, &[(&account1_key, &account1)][..]), None);
14154+
db.store_cached((1, &[(&account2_key, &account2)][..]), None);
14155+
14156+
db.add_root(0);
14157+
db.add_root(1);
14158+
14159+
// Flush the cache so that the account meta will be read from the storage
14160+
db.flush_accounts_cache(true, None);
14161+
db.clean_accounts_for_tests();
14162+
14163+
let account_meta = db
14164+
.get_account_meta(&Ancestors::default(), &account1_key)
14165+
.unwrap();
14166+
assert_eq!(account_meta.lamports, 321);
14167+
assert_eq!(account_meta.owner, owner1_key);
14168+
14169+
let account_meta = db
14170+
.get_account_meta(&Ancestors::default(), &account2_key)
14171+
.unwrap();
14172+
assert_eq!(account_meta.lamports, 1);
14173+
assert_eq!(account_meta.owner, owner2_key);
14174+
14175+
// Flush the cache and load account1 (so that it's in the cache)
14176+
db.flush_accounts_cache(true, None);
14177+
db.clean_accounts_for_tests();
14178+
let _ = db
14179+
.do_load(
14180+
&Ancestors::default(),
14181+
&account1_key,
14182+
Some(0),
14183+
LoadHint::Unspecified,
14184+
LoadZeroLamports::SomeWithZeroLamportAccountForTests,
14185+
)
14186+
.unwrap();
14187+
14188+
let account_meta = db
14189+
.get_account_meta(&Ancestors::default(), &account1_key)
14190+
.unwrap();
14191+
assert_eq!(account_meta.lamports, 321);
14192+
assert_eq!(account_meta.owner, owner1_key);
14193+
14194+
let account_meta = db
14195+
.get_account_meta(&Ancestors::default(), &account2_key)
14196+
.unwrap();
14197+
assert_eq!(account_meta.lamports, 1);
14198+
assert_eq!(account_meta.owner, owner2_key);
14199+
}
14200+
1408514201
/// a test that will accept either answer
1408614202
const LOAD_ZERO_LAMPORTS_ANY_TESTS: LoadZeroLamports = LoadZeroLamports::None;
1408714203

runtime/src/append_vec.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ impl AppendVec {
572572
Some((unsafe { &*ptr }, next))
573573
}
574574

575-
/// Return account metadata for the account at `offset` if its data doesn't overrun
575+
/// Return stored account metadata for the account at `offset` if its data doesn't overrun
576576
/// the internal buffer. Otherwise return None. Also return the offset of the first byte
577577
/// after the requested data that falls on a 64-byte boundary.
578578
pub fn get_account<'a>(&'a self, offset: usize) -> Option<(StoredAccountMeta<'a>, usize)> {
@@ -594,6 +594,17 @@ impl AppendVec {
594594
))
595595
}
596596

597+
/// Return account metadata for the account at `offset` if its data doesn't overrun
598+
/// the internal buffer. Otherwise return None.
599+
pub fn get_account_meta(&self, offset: usize) -> Option<AccountMeta> {
600+
// Skip over StoredMeta data in the account
601+
let offset = offset.checked_add(mem::size_of::<StoredMeta>())?;
602+
// u64_align! does an unchecked add for alignment. Check that it won't cause an overflow.
603+
offset.checked_add(ALIGN_BOUNDARY_OFFSET - 1)?;
604+
let (account_meta, _): (&AccountMeta, _) = self.get_type(u64_align!(offset))?;
605+
Some(account_meta.clone())
606+
}
607+
597608
#[cfg(test)]
598609
pub fn get_account_test(&self, offset: usize) -> Option<(StoredMeta, AccountSharedData)> {
599610
let (stored_account, _) = self.get_account(offset)?;
@@ -1047,6 +1058,56 @@ pub mod tests {
10471058
assert_eq!(av.get_account_test(index1).unwrap(), account1);
10481059
}
10491060

1061+
#[test]
1062+
fn test_get_account_meta() {
1063+
let path = get_append_vec_path("test_append_data");
1064+
let av = AppendVec::new(&path.path, true, 1024 * 1024);
1065+
let mut account = create_test_account(5);
1066+
1067+
let test_account_meta = AccountMeta {
1068+
lamports: 12345678,
1069+
rent_epoch: 123,
1070+
owner: Pubkey::new_unique(),
1071+
executable: true,
1072+
};
1073+
account.1.set_lamports(test_account_meta.lamports);
1074+
account.1.set_rent_epoch(test_account_meta.rent_epoch);
1075+
account.1.set_owner(test_account_meta.owner);
1076+
account.1.set_executable(test_account_meta.executable);
1077+
1078+
let index = av.append_account_test(&account).unwrap();
1079+
assert_eq!(av.get_account_meta(index), Some(test_account_meta.clone()));
1080+
1081+
let mut account1 = create_test_account(6);
1082+
let test_account_meta1 = AccountMeta {
1083+
lamports: 87654321,
1084+
rent_epoch: 234,
1085+
owner: Pubkey::new_unique(),
1086+
executable: false,
1087+
};
1088+
account1.1.set_lamports(test_account_meta1.lamports);
1089+
account1.1.set_rent_epoch(test_account_meta1.rent_epoch);
1090+
account1.1.set_owner(test_account_meta1.owner);
1091+
account1.1.set_executable(test_account_meta1.executable);
1092+
1093+
let index1 = av.append_account_test(&account1).unwrap();
1094+
assert_eq!(av.get_account_meta(index1), Some(test_account_meta1));
1095+
assert_eq!(av.get_account_meta(index), Some(test_account_meta));
1096+
1097+
// tests for overflow
1098+
assert_eq!(
1099+
av.get_account_meta(usize::MAX - mem::size_of::<StoredMeta>()),
1100+
None
1101+
);
1102+
1103+
assert_eq!(
1104+
av.get_account_meta(
1105+
usize::MAX - mem::size_of::<StoredMeta>() - mem::size_of::<AccountMeta>() + 1
1106+
),
1107+
None
1108+
);
1109+
}
1110+
10501111
#[test]
10511112
fn test_append_vec_append_many() {
10521113
let path = get_append_vec_path("test_append_many");

0 commit comments

Comments
 (0)