rpc: performance fix for getProgramAccounts (#19941) (#19950)

* rpc: performance fix for getProgramAccounts

The accounts were gradually pushed into a vector, which produced
significant slowdowns for very large responses.

* rpc: rewrite loops using iterators

Co-authored-by: Christian Kamm <ckamm@delightful-solutions.de>
(cherry picked from commit f1bbf1d8b0)

Co-authored-by: Christian Kamm <mail@ckamm.de>
This commit is contained in:
mergify[bot]
2021-09-16 23:26:21 +00:00
committed by GitHub
parent 70d556782b
commit c85816c44e

View File

@ -339,18 +339,15 @@ impl JsonRpcRequestProcessor {
pubkeys: Vec<Pubkey>, pubkeys: Vec<Pubkey>,
config: Option<RpcAccountInfoConfig>, config: Option<RpcAccountInfoConfig>,
) -> Result<RpcResponse<Vec<Option<UiAccount>>>> { ) -> Result<RpcResponse<Vec<Option<UiAccount>>>> {
let mut accounts: Vec<Option<UiAccount>> = vec![];
let config = config.unwrap_or_default(); let config = config.unwrap_or_default();
let bank = self.bank(config.commitment); let bank = self.bank(config.commitment);
let encoding = config.encoding.unwrap_or(UiAccountEncoding::Base64); let encoding = config.encoding.unwrap_or(UiAccountEncoding::Base64);
check_slice_and_encoding(&encoding, config.data_slice.is_some())?; check_slice_and_encoding(&encoding, config.data_slice.is_some())?;
for pubkey in pubkeys { let accounts = pubkeys
let response_account = .into_iter()
get_encoded_account(&bank, &pubkey, encoding, config.data_slice)?; .map(|pubkey| get_encoded_account(&bank, &pubkey, encoding, config.data_slice))
accounts.push(response_account) .collect::<Result<Vec<_>>>()?;
}
Ok(new_response(&bank, accounts)) Ok(new_response(&bank, accounts))
} }
@ -384,19 +381,21 @@ impl JsonRpcRequestProcessor {
self.get_filtered_program_accounts(&bank, program_id, filters)? self.get_filtered_program_accounts(&bank, program_id, filters)?
} }
}; };
let result = let result = if program_id == &spl_token_id_v2_0()
if program_id == &spl_token_id_v2_0() && encoding == UiAccountEncoding::JsonParsed { && encoding == UiAccountEncoding::JsonParsed
get_parsed_token_accounts(bank.clone(), keyed_accounts.into_iter()).collect() {
} else { get_parsed_token_accounts(bank.clone(), keyed_accounts.into_iter()).collect()
let mut encoded_accounts = vec![]; } else {
for (pubkey, account) in keyed_accounts { keyed_accounts
encoded_accounts.push(RpcKeyedAccount { .into_iter()
.map(|(pubkey, account)| {
Ok(RpcKeyedAccount {
pubkey: pubkey.to_string(), pubkey: pubkey.to_string(),
account: encode_account(&account, &pubkey, encoding, data_slice_config)?, account: encode_account(&account, &pubkey, encoding, data_slice_config)?,
}); })
} })
encoded_accounts .collect::<Result<Vec<_>>>()?
}; };
Ok(result).map(|result| match with_context { Ok(result).map(|result| match with_context {
true => OptionalContext::Context(new_response(&bank, result)), true => OptionalContext::Context(new_response(&bank, result)),
false => OptionalContext::NoContext(result), false => OptionalContext::NoContext(result),
@ -2728,10 +2727,10 @@ pub mod rpc_full {
max_multiple_accounts max_multiple_accounts
))); )));
} }
let mut pubkeys: Vec<Pubkey> = vec![]; let pubkeys = pubkey_strs
for pubkey_str in pubkey_strs { .into_iter()
pubkeys.push(verify_pubkey(&pubkey_str)?); .map(|pubkey_str| verify_pubkey(&pubkey_str))
} .collect::<Result<Vec<_>>>()?;
meta.get_multiple_accounts(pubkeys, config) meta.get_multiple_accounts(pubkeys, config)
} }