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

Commit 400610b

Browse files
author
Tyera Eulberg
authored
v0.16: AccountsDB updates and getProgramAccounts RPC fix (#5044)
* reduce replicode in accounts, fix cast to i64 (#5025) * add accounts_index_scan_accounts (#5020) * Plumb scan_accounts into accounts_db, adding load from storage (#5029) * Fix getProgramAccounts RPC (#5024) * Use scan_accounts to load accounts by program_id * Add bank test * Use get_program_accounts in RPC * Rebase for v0.16
1 parent f759ac3 commit 400610b

File tree

5 files changed

+262
-56
lines changed

5 files changed

+262
-56
lines changed

Diff for: core/src/rpc.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl JsonRpcRequestProcessor {
7373
pub fn get_program_accounts(&self, program_id: &Pubkey) -> Result<Vec<(String, Account)>> {
7474
Ok(self
7575
.bank()
76-
.get_program_accounts_modified_since_parent(&program_id)
76+
.get_program_accounts(&program_id)
7777
.into_iter()
7878
.map(|(pubkey, account)| (pubkey.to_string(), account))
7979
.collect())

Diff for: runtime/src/accounts.rs

+64-36
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use std::collections::{HashMap, HashSet};
2222
use std::env;
2323
use std::fs::remove_dir_all;
2424
use std::io::{BufReader, Read};
25-
use std::ops::Neg;
2625
use std::path::Path;
2726
use std::sync::atomic::{AtomicUsize, Ordering};
2827
use std::sync::{Arc, Mutex};
@@ -294,27 +293,65 @@ impl Accounts {
294293
.filter(|(acc, _)| acc.lamports != 0)
295294
}
296295

297-
pub fn load_by_program(&self, fork: Fork, program_id: &Pubkey) -> Vec<(Pubkey, Account)> {
298-
let accumulator: Vec<Vec<(Pubkey, u64, Account)>> = self.accounts_db.scan_account_storage(
296+
/// scans underlying accounts_db for this delta (fork) with a map function
297+
/// from StoredAccount to B
298+
/// returns only the latest/current version of B for this fork
299+
fn scan_fork<F, B>(&self, fork: Fork, func: F) -> Vec<B>
300+
where
301+
F: Fn(&StoredAccount) -> Option<B>,
302+
F: Send + Sync,
303+
B: Send + Default,
304+
{
305+
let accumulator: Vec<Vec<(Pubkey, u64, B)>> = self.accounts_db.scan_account_storage(
299306
fork,
300307
|stored_account: &StoredAccount,
301308
_id: AppendVecId,
302-
accum: &mut Vec<(Pubkey, u64, Account)>| {
303-
if stored_account.balance.owner == *program_id {
304-
let val = (
309+
accum: &mut Vec<(Pubkey, u64, B)>| {
310+
if let Some(val) = func(stored_account) {
311+
accum.push((
305312
stored_account.meta.pubkey,
306-
stored_account.meta.write_version,
307-
stored_account.clone_account(),
308-
);
309-
accum.push(val)
313+
std::u64::MAX - stored_account.meta.write_version,
314+
val,
315+
));
310316
}
311317
},
312318
);
313-
let mut versions: Vec<(Pubkey, u64, Account)> =
314-
accumulator.into_iter().flat_map(|x| x).collect();
315-
versions.sort_by_key(|s| (s.0, (s.1 as i64).neg()));
319+
320+
let mut versions: Vec<(Pubkey, u64, B)> = accumulator.into_iter().flat_map(|x| x).collect();
321+
versions.sort_by_key(|s| (s.0, s.1));
316322
versions.dedup_by_key(|s| s.0);
317-
versions.into_iter().map(|s| (s.0, s.2)).collect()
323+
versions
324+
.into_iter()
325+
.map(|(_pubkey, _version, val)| val)
326+
.collect()
327+
}
328+
329+
pub fn load_by_program_fork(&self, fork: Fork, program_id: &Pubkey) -> Vec<(Pubkey, Account)> {
330+
self.scan_fork(fork, |stored_account| {
331+
if stored_account.balance.owner == *program_id {
332+
Some((stored_account.meta.pubkey, stored_account.clone_account()))
333+
} else {
334+
None
335+
}
336+
})
337+
}
338+
339+
pub fn load_by_program(
340+
&self,
341+
ancestors: &HashMap<Fork, usize>,
342+
program_id: &Pubkey,
343+
) -> Vec<(Pubkey, Account)> {
344+
self.accounts_db.scan_accounts(
345+
ancestors,
346+
|collector: &mut Vec<(Pubkey, Account)>, option| {
347+
if let Some(data) = option
348+
.filter(|(_, account, _)| account.owner == *program_id && account.lamports != 0)
349+
.map(|(pubkey, account, _fork)| (*pubkey, account))
350+
{
351+
collector.push(data)
352+
}
353+
},
354+
)
318355
}
319356

320357
/// Slow because lock is held for 1 operation instead of many
@@ -362,28 +399,19 @@ impl Accounts {
362399
}
363400

364401
pub fn hash_internal_state(&self, fork_id: Fork) -> Option<Hash> {
365-
let accumulator: Vec<Vec<(Pubkey, u64, Hash)>> = self.accounts_db.scan_account_storage(
366-
fork_id,
367-
|stored_account: &StoredAccount,
368-
_id: AppendVecId,
369-
accum: &mut Vec<(Pubkey, u64, Hash)>| {
370-
if !syscall::check_id(&stored_account.balance.owner) {
371-
accum.push((
372-
stored_account.meta.pubkey,
373-
stored_account.meta.write_version,
374-
Self::hash_account(stored_account),
375-
));
376-
}
377-
},
378-
);
379-
let mut account_hashes: Vec<_> = accumulator.into_iter().flat_map(|x| x).collect();
380-
account_hashes.sort_by_key(|s| (s.0, (s.1 as i64).neg()));
381-
account_hashes.dedup_by_key(|s| s.0);
402+
let account_hashes = self.scan_fork(fork_id, |stored_account| {
403+
if !syscall::check_id(&stored_account.balance.owner) {
404+
Some(Self::hash_account(stored_account))
405+
} else {
406+
None
407+
}
408+
});
409+
382410
if account_hashes.is_empty() {
383411
None
384412
} else {
385413
let mut hasher = Hasher::default();
386-
for (_, _, hash) in account_hashes {
414+
for hash in account_hashes {
387415
hasher.hash(hash.as_ref());
388416
}
389417
Some(hasher.result())
@@ -938,7 +966,7 @@ mod tests {
938966
}
939967

940968
#[test]
941-
fn test_load_by_program() {
969+
fn test_load_by_program_fork() {
942970
let accounts = Accounts::new(None);
943971

944972
// Load accounts owned by various programs into AccountsDB
@@ -952,11 +980,11 @@ mod tests {
952980
let account2 = Account::new(1, 0, &Pubkey::new(&[3; 32]));
953981
accounts.store_slow(0, &pubkey2, &account2);
954982

955-
let loaded = accounts.load_by_program(0, &Pubkey::new(&[2; 32]));
983+
let loaded = accounts.load_by_program_fork(0, &Pubkey::new(&[2; 32]));
956984
assert_eq!(loaded.len(), 2);
957-
let loaded = accounts.load_by_program(0, &Pubkey::new(&[3; 32]));
985+
let loaded = accounts.load_by_program_fork(0, &Pubkey::new(&[3; 32]));
958986
assert_eq!(loaded, vec![(pubkey2, account2)]);
959-
let loaded = accounts.load_by_program(0, &Pubkey::new(&[4; 32]));
987+
let loaded = accounts.load_by_program_fork(0, &Pubkey::new(&[4; 32]));
960988
assert_eq!(loaded, vec![]);
961989
}
962990

Diff for: runtime/src/accounts_db.rs

+72
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,36 @@ impl AccountsDB {
378378
false
379379
}
380380

381+
pub fn scan_accounts<F, A>(&self, ancestors: &HashMap<Fork, usize>, scan_func: F) -> A
382+
where
383+
F: Fn(&mut A, Option<(&Pubkey, Account, Fork)>) -> (),
384+
A: Default,
385+
{
386+
let mut collector = A::default();
387+
let accounts_index = self.accounts_index.read().unwrap();
388+
let storage = self.storage.read().unwrap();
389+
accounts_index.scan_accounts(ancestors, |pubkey, (account_info, fork)| {
390+
scan_func(
391+
&mut collector,
392+
storage
393+
.0
394+
.get(&fork)
395+
.and_then(|storage_map| storage_map.get(&account_info.id))
396+
.and_then(|store| {
397+
Some(
398+
store
399+
.accounts
400+
.get_account(account_info.offset)?
401+
.0
402+
.clone_account(),
403+
)
404+
})
405+
.map(|account| (pubkey, account, fork)),
406+
)
407+
});
408+
collector
409+
}
410+
381411
/// Scan a specific fork through all the account storage in parallel with sequential read
382412
// PERF: Sequentially read each storage entry in parallel
383413
pub fn scan_account_storage<F, B>(&self, fork_id: Fork, scan_func: F) -> Vec<B>
@@ -770,6 +800,14 @@ mod tests {
770800

771801
let ancestors = vec![(1, 1), (0, 0)].into_iter().collect();
772802
assert_eq!(&db.load_slow(&ancestors, &key).unwrap().0, &account1);
803+
804+
let accounts: Vec<Account> =
805+
db.scan_accounts(&ancestors, |accounts: &mut Vec<Account>, option| {
806+
if let Some(data) = option {
807+
accounts.push(data.1);
808+
}
809+
});
810+
assert_eq!(accounts, vec![account1]);
773811
}
774812

775813
#[test]
@@ -1313,4 +1351,38 @@ mod tests {
13131351
t.join().unwrap();
13141352
}
13151353
}
1354+
1355+
#[test]
1356+
fn test_accountsdb_scan_accounts() {
1357+
solana_logger::setup();
1358+
let paths = get_tmp_accounts_path!();
1359+
let db = AccountsDB::new(&paths.paths);
1360+
let key = Pubkey::default();
1361+
let key0 = Pubkey::new_rand();
1362+
let account0 = Account::new(1, 0, &key);
1363+
1364+
db.store(0, &hashmap!(&key0 => (&account0, 0)));
1365+
1366+
let key1 = Pubkey::new_rand();
1367+
let account1 = Account::new(2, 0, &key);
1368+
db.store(1, &hashmap!(&key1 => (&account1, 0)));
1369+
1370+
let ancestors = vec![(0, 0)].into_iter().collect();
1371+
let accounts: Vec<Account> =
1372+
db.scan_accounts(&ancestors, |accounts: &mut Vec<Account>, option| {
1373+
if let Some(data) = option {
1374+
accounts.push(data.1);
1375+
}
1376+
});
1377+
assert_eq!(accounts, vec![account0]);
1378+
1379+
let ancestors = vec![(1, 1), (0, 0)].into_iter().collect();
1380+
let accounts: Vec<Account> =
1381+
db.scan_accounts(&ancestors, |accounts: &mut Vec<Account>, option| {
1382+
if let Some(data) = option {
1383+
accounts.push(data.1);
1384+
}
1385+
});
1386+
assert_eq!(accounts.len(), 2);
1387+
}
13161388
}

Diff for: runtime/src/accounts_index.rs

+69-18
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
use hashbrown::HashMap;
21
use log::*;
32
use solana_sdk::pubkey::Pubkey;
4-
use std::collections;
5-
use std::collections::HashSet;
3+
use std::collections::{HashMap, HashSet};
64

75
pub type Fork = u64;
86

97
#[derive(Debug, Default)]
108
pub struct AccountsIndex<T> {
11-
pub account_maps: HashMap<Pubkey, Vec<(Fork, T)>>,
9+
pub account_maps: hashbrown::HashMap<Pubkey, Vec<(Fork, T)>>,
1210

1311
pub roots: HashSet<Fork>,
1412

@@ -17,26 +15,44 @@ pub struct AccountsIndex<T> {
1715
}
1816

1917
impl<T: Clone> AccountsIndex<T> {
20-
/// Get an account
21-
/// The latest account that appears in `ancestors` or `roots` is returned.
22-
pub fn get(
18+
/// call func with every pubkey and index visible from a given set of ancestors
19+
pub fn scan_accounts<F>(&self, ancestors: &HashMap<Fork, usize>, mut func: F)
20+
where
21+
F: FnMut(&Pubkey, (&T, Fork)) -> (),
22+
{
23+
for (pubkey, list) in self.account_maps.iter() {
24+
if let Some(fork_info) = self.latest_fork(ancestors, list) {
25+
func(pubkey, fork_info);
26+
}
27+
}
28+
}
29+
30+
// find the latest fork and T in a list for a given ancestor
31+
fn latest_fork<'a>(
2332
&self,
24-
pubkey: &Pubkey,
25-
ancestors: &collections::HashMap<Fork, usize>,
26-
) -> Option<(&T, Fork)> {
27-
let list = self.account_maps.get(pubkey)?;
33+
ancestors: &HashMap<Fork, usize>,
34+
list: &'a [(Fork, T)],
35+
) -> Option<(&'a T, Fork)> {
2836
let mut max = 0;
2937
let mut rv = None;
30-
for e in list.iter().rev() {
31-
if e.0 >= max && (ancestors.get(&e.0).is_some() || self.is_root(e.0)) {
32-
trace!("GET {} {:?}", e.0, ancestors);
33-
rv = Some((&e.1, e.0));
34-
max = e.0;
38+
for (fork, t) in list.iter().rev() {
39+
if *fork >= max && (ancestors.get(fork).is_some() || self.is_root(*fork)) {
40+
trace!("GET {} {:?}", fork, ancestors);
41+
rv = Some((t, *fork));
42+
max = *fork;
3543
}
3644
}
3745
rv
3846
}
3947

48+
/// Get an account
49+
/// The latest account that appears in `ancestors` or `roots` is returned.
50+
pub fn get(&self, pubkey: &Pubkey, ancestors: &HashMap<Fork, usize>) -> Option<(&T, Fork)> {
51+
self.account_maps
52+
.get(pubkey)
53+
.and_then(|list| self.latest_fork(ancestors, list))
54+
}
55+
4056
pub fn get_max_root(roots: &HashSet<Fork>, fork_vec: &[(Fork, T)]) -> Fork {
4157
let mut max_root = 0;
4258
for (f, _) in fork_vec.iter() {
@@ -119,8 +135,12 @@ mod tests {
119135
fn test_get_empty() {
120136
let key = Keypair::new();
121137
let index = AccountsIndex::<bool>::default();
122-
let ancestors = collections::HashMap::new();
138+
let ancestors = HashMap::new();
123139
assert_eq!(index.get(&key.pubkey(), &ancestors), None);
140+
141+
let mut num = 0;
142+
index.scan_accounts(&ancestors, |_pubkey, _index| num += 1);
143+
assert_eq!(num, 0);
124144
}
125145

126146
#[test]
@@ -131,8 +151,12 @@ mod tests {
131151
index.insert(0, &key.pubkey(), true, &mut gc);
132152
assert!(gc.is_empty());
133153

134-
let ancestors = collections::HashMap::new();
154+
let ancestors = HashMap::new();
135155
assert_eq!(index.get(&key.pubkey(), &ancestors), None);
156+
157+
let mut num = 0;
158+
index.scan_accounts(&ancestors, |_pubkey, _index| num += 1);
159+
assert_eq!(num, 0);
136160
}
137161

138162
#[test]
@@ -145,6 +169,10 @@ mod tests {
145169

146170
let ancestors = vec![(1, 1)].into_iter().collect();
147171
assert_eq!(index.get(&key.pubkey(), &ancestors), None);
172+
173+
let mut num = 0;
174+
index.scan_accounts(&ancestors, |_pubkey, _index| num += 1);
175+
assert_eq!(num, 0);
148176
}
149177

150178
#[test]
@@ -157,6 +185,17 @@ mod tests {
157185

158186
let ancestors = vec![(0, 0)].into_iter().collect();
159187
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&true, 0)));
188+
189+
let mut num = 0;
190+
let mut found_key = false;
191+
index.scan_accounts(&ancestors, |pubkey, _index| {
192+
if pubkey == &key.pubkey() {
193+
found_key = true
194+
};
195+
num += 1
196+
});
197+
assert_eq!(num, 1);
198+
assert!(found_key);
160199
}
161200

162201
#[test]
@@ -272,5 +311,17 @@ mod tests {
272311
assert_eq!(gc, vec![(0, true), (1, false), (2, true)]);
273312
let ancestors = vec![].into_iter().collect();
274313
assert_eq!(index.get(&key.pubkey(), &ancestors), Some((&true, 3)));
314+
315+
let mut num = 0;
316+
let mut found_key = false;
317+
index.scan_accounts(&ancestors, |pubkey, _index| {
318+
if pubkey == &key.pubkey() {
319+
found_key = true;
320+
assert_eq!(_index, (&true, 3));
321+
};
322+
num += 1
323+
});
324+
assert_eq!(num, 1);
325+
assert!(found_key);
275326
}
276327
}

0 commit comments

Comments
 (0)