|
18 | 18 | //! tracks the number of commits to the entire data store. So the latest
|
19 | 19 | //! commit for each slot entry would be indexed.
|
20 | 20 |
|
| 21 | +use crate::append_vec::AccountMeta; |
21 | 22 | use {
|
22 | 23 | crate::{
|
23 | 24 | account_info::{AccountInfo, Offset, StorageLocation, StoredSize},
|
@@ -809,6 +810,29 @@ impl<'a> LoadedAccountAccessor<'a> {
|
809 | 810 | }
|
810 | 811 | }
|
811 | 812 | }
|
| 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 | + } |
812 | 836 | }
|
813 | 837 |
|
814 | 838 | pub enum LoadedAccount<'a> {
|
@@ -4913,6 +4937,33 @@ impl AccountsDb {
|
4913 | 4937 | self.do_load(ancestors, pubkey, None, load_hint, LoadZeroLamports::None)
|
4914 | 4938 | }
|
4915 | 4939 |
|
| 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 | + |
4916 | 4967 | pub fn load_account_into_read_cache(&self, ancestors: &Ancestors, pubkey: &Pubkey) {
|
4917 | 4968 | self.do_load_with_populate_read_cache(
|
4918 | 4969 | ancestors,
|
@@ -14082,6 +14133,71 @@ pub mod tests {
|
14082 | 14133 | assert_eq!(db.read_only_accounts_cache.cache_len(), 1);
|
14083 | 14134 | }
|
14084 | 14135 |
|
| 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 | + |
14085 | 14201 | /// a test that will accept either answer
|
14086 | 14202 | const LOAD_ZERO_LAMPORTS_ANY_TESTS: LoadZeroLamports = LoadZeroLamports::None;
|
14087 | 14203 |
|
|
0 commit comments