1use {
3 crate::{
4 account_storage::meta::StoredAccountMeta,
5 accounts_db::{AccountFromStorage, AccountStorageEntry, AccountsDb},
6 accounts_index::ZeroLamport,
7 },
8 solana_sdk::{
9 account::{AccountSharedData, ReadableAccount},
10 clock::{Epoch, Slot},
11 pubkey::Pubkey,
12 },
13 std::sync::{Arc, RwLock},
14};
15
16#[derive(Debug, Copy, Clone)]
18pub enum AccountForStorage<'a> {
19 AddressAndAccount((&'a Pubkey, &'a AccountSharedData)),
20 StoredAccountMeta(&'a StoredAccountMeta<'a>),
21}
22
23impl<'a> From<(&'a Pubkey, &'a AccountSharedData)> for AccountForStorage<'a> {
24 fn from(source: (&'a Pubkey, &'a AccountSharedData)) -> Self {
25 Self::AddressAndAccount(source)
26 }
27}
28
29impl<'a> From<&'a StoredAccountMeta<'a>> for AccountForStorage<'a> {
30 fn from(source: &'a StoredAccountMeta<'a>) -> Self {
31 Self::StoredAccountMeta(source)
32 }
33}
34
35impl<'a> ZeroLamport for AccountForStorage<'a> {
36 fn is_zero_lamport(&self) -> bool {
37 self.lamports() == 0
38 }
39}
40
41impl<'a> AccountForStorage<'a> {
42 pub fn pubkey(&self) -> &'a Pubkey {
43 match self {
44 AccountForStorage::AddressAndAccount((pubkey, _account)) => pubkey,
45 AccountForStorage::StoredAccountMeta(account) => account.pubkey(),
46 }
47 }
48}
49
50impl<'a> ReadableAccount for AccountForStorage<'a> {
51 fn lamports(&self) -> u64 {
52 match self {
53 AccountForStorage::AddressAndAccount((_pubkey, account)) => account.lamports(),
54 AccountForStorage::StoredAccountMeta(account) => account.lamports(),
55 }
56 }
57 fn data(&self) -> &[u8] {
58 match self {
59 AccountForStorage::AddressAndAccount((_pubkey, account)) => account.data(),
60 AccountForStorage::StoredAccountMeta(account) => account.data(),
61 }
62 }
63 fn owner(&self) -> &Pubkey {
64 match self {
65 AccountForStorage::AddressAndAccount((_pubkey, account)) => account.owner(),
66 AccountForStorage::StoredAccountMeta(account) => account.owner(),
67 }
68 }
69 fn executable(&self) -> bool {
70 match self {
71 AccountForStorage::AddressAndAccount((_pubkey, account)) => account.executable(),
72 AccountForStorage::StoredAccountMeta(account) => account.executable(),
73 }
74 }
75 fn rent_epoch(&self) -> Epoch {
76 match self {
77 AccountForStorage::AddressAndAccount((_pubkey, account)) => account.rent_epoch(),
78 AccountForStorage::StoredAccountMeta(account) => account.rent_epoch(),
79 }
80 }
81 fn to_account_shared_data(&self) -> AccountSharedData {
82 match self {
83 AccountForStorage::AddressAndAccount((_pubkey, account)) => {
84 account.to_account_shared_data()
85 }
86 AccountForStorage::StoredAccountMeta(account) => account.to_account_shared_data(),
87 }
88 }
89}
90
91lazy_static! {
92 static ref DEFAULT_ACCOUNT_SHARED_DATA: AccountSharedData = AccountSharedData::default();
93}
94
95#[derive(Default, Debug)]
96pub struct StorableAccountsCacher {
97 slot: Slot,
98 storage: Option<Arc<AccountStorageEntry>>,
99}
100
101pub trait StorableAccounts<'a>: Sync {
107 fn account<Ret>(
109 &self,
110 index: usize,
111 callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
112 ) -> Ret;
113 fn account_default_if_zero_lamport<Ret>(
115 &self,
116 index: usize,
117 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
118 ) -> Ret {
119 self.account(index, |account| {
120 callback(if account.lamports() != 0 {
121 account
122 } else {
123 AccountForStorage::AddressAndAccount((
125 account.pubkey(),
126 &DEFAULT_ACCOUNT_SHARED_DATA,
127 ))
128 })
129 })
130 }
131 fn slot(&self, index: usize) -> Slot;
133 fn target_slot(&self) -> Slot;
135 fn is_empty(&self) -> bool {
137 self.len() == 0
138 }
139 fn len(&self) -> usize;
141 fn contains_multiple_slots(&self) -> bool {
144 false
145 }
146}
147
148impl<'a: 'b, 'b> StorableAccounts<'a> for (Slot, &'b [(&'a Pubkey, &'a AccountSharedData)]) {
149 fn account<Ret>(
150 &self,
151 index: usize,
152 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
153 ) -> Ret {
154 callback((self.1[index].0, self.1[index].1).into())
155 }
156 fn slot(&self, _index: usize) -> Slot {
157 self.target_slot()
159 }
160 fn target_slot(&self) -> Slot {
161 self.0
162 }
163 fn len(&self) -> usize {
164 self.1.len()
165 }
166}
167
168pub struct StorableAccountsBySlot<'a> {
170 target_slot: Slot,
171 slots_and_accounts: &'a [(Slot, &'a [&'a AccountFromStorage])],
173
174 starting_offsets: Vec<usize>,
179 contains_multiple_slots: bool,
181 len: usize,
183 db: &'a AccountsDb,
184 cached_storage: RwLock<StorableAccountsCacher>,
186}
187
188impl<'a> StorableAccountsBySlot<'a> {
189 pub fn new(
191 target_slot: Slot,
192 slots_and_accounts: &'a [(Slot, &'a [&'a AccountFromStorage])],
193 db: &'a AccountsDb,
194 ) -> Self {
195 let mut cumulative_len = 0usize;
196 let mut starting_offsets = Vec::with_capacity(slots_and_accounts.len());
197 let first_slot = slots_and_accounts
198 .first()
199 .map(|(slot, _)| *slot)
200 .unwrap_or_default();
201 let mut contains_multiple_slots = false;
202 for (slot, accounts) in slots_and_accounts {
203 cumulative_len = cumulative_len.saturating_add(accounts.len());
204 starting_offsets.push(cumulative_len);
205 contains_multiple_slots |= &first_slot != slot;
206 }
207 Self {
208 target_slot,
209 slots_and_accounts,
210 starting_offsets,
211 contains_multiple_slots,
212 len: cumulative_len,
213 db,
214 cached_storage: RwLock::default(),
215 }
216 }
217 fn find_internal_index(&self, index: usize) -> (usize, usize) {
220 for (offset_index, next_offset) in self.starting_offsets.iter().enumerate() {
223 if next_offset > &index {
224 let prior_offset = if offset_index > 0 {
226 self.starting_offsets[offset_index.saturating_sub(1)]
227 } else {
228 0
229 };
230 return (offset_index, index - prior_offset);
231 }
232 }
233 panic!("failed");
234 }
235}
236
237impl<'a> StorableAccounts<'a> for StorableAccountsBySlot<'a> {
238 fn account<Ret>(
239 &self,
240 index: usize,
241 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
242 ) -> Ret {
243 let indexes = self.find_internal_index(index);
244 let slot = self.slots_and_accounts[indexes.0].0;
245 let data = self.slots_and_accounts[indexes.0].1[indexes.1];
246 let offset = data.index_info.offset();
247 let mut call_callback = |storage: &AccountStorageEntry| {
248 storage
249 .accounts
250 .get_stored_account_meta_callback(offset, |account: StoredAccountMeta| {
251 callback((&account).into())
252 })
253 .expect("account has to exist to be able to store it")
254 };
255 {
256 let reader = self.cached_storage.read().unwrap();
257 if reader.slot == slot {
258 if let Some(storage) = reader.storage.as_ref() {
259 return call_callback(storage);
260 }
261 }
262 }
263 let storage = self
266 .db
267 .storage
268 .get_slot_storage_entry_shrinking_in_progress_ok(slot)
269 .expect("source slot has to have a storage to be able to store accounts");
270 let ret = call_callback(&storage);
271 let mut writer = self.cached_storage.write().unwrap();
272 writer.slot = slot;
273 writer.storage = Some(storage);
274 ret
275 }
276 fn slot(&self, index: usize) -> Slot {
277 let indexes = self.find_internal_index(index);
278 self.slots_and_accounts[indexes.0].0
279 }
280 fn target_slot(&self) -> Slot {
281 self.target_slot
282 }
283 fn len(&self) -> usize {
284 self.len
285 }
286 fn contains_multiple_slots(&self) -> bool {
287 self.contains_multiple_slots
288 }
289}
290
291#[cfg(test)]
292pub mod tests {
293 use {
294 super::*,
295 crate::{
296 account_info::{AccountInfo, StorageLocation},
297 account_storage::meta::{AccountMeta, StoredAccountMeta, StoredMeta},
298 accounts_db::{get_temp_accounts_paths, AccountStorageEntry},
299 accounts_file::AccountsFileProvider,
300 accounts_hash::AccountHash,
301 append_vec::AppendVecStoredAccountMeta,
302 },
303 solana_sdk::{
304 account::{accounts_equal, AccountSharedData, WritableAccount},
305 hash::Hash,
306 },
307 std::sync::Arc,
308 };
309
310 impl<'a> StorableAccounts<'a> for (Slot, &'a [&'a StoredAccountMeta<'a>]) {
314 fn account<Ret>(
315 &self,
316 index: usize,
317 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
318 ) -> Ret {
319 callback(self.1[index].into())
320 }
321 fn slot(&self, _index: usize) -> Slot {
322 self.0
324 }
325 fn target_slot(&self) -> Slot {
326 self.0
327 }
328 fn len(&self) -> usize {
329 self.1.len()
330 }
331 }
332
333 impl<'a, T: ReadableAccount + Sync> StorableAccounts<'a> for (Slot, &'a [&'a (Pubkey, T)])
335 where
336 AccountForStorage<'a>: From<(&'a Pubkey, &'a T)>,
337 {
338 fn account<Ret>(
339 &self,
340 index: usize,
341 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
342 ) -> Ret {
343 callback((&self.1[index].0, &self.1[index].1).into())
344 }
345 fn slot(&self, _index: usize) -> Slot {
346 self.target_slot()
348 }
349 fn target_slot(&self) -> Slot {
350 self.0
351 }
352 fn len(&self) -> usize {
353 self.1.len()
354 }
355 }
356
357 impl<'a> StorableAccounts<'a> for (Slot, &'a [&'a StoredAccountMeta<'a>], Slot) {
361 fn account<Ret>(
362 &self,
363 index: usize,
364 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
365 ) -> Ret {
366 callback(self.1[index].into())
367 }
368 fn slot(&self, _index: usize) -> Slot {
369 self.2
371 }
372 fn target_slot(&self) -> Slot {
373 self.0
374 }
375 fn len(&self) -> usize {
376 self.1.len()
377 }
378 }
379
380 fn compare<'a>(a: &impl StorableAccounts<'a>, b: &impl StorableAccounts<'a>) {
381 assert_eq!(a.target_slot(), b.target_slot());
382 assert_eq!(a.len(), b.len());
383 assert_eq!(a.is_empty(), b.is_empty());
384 (0..a.len()).for_each(|i| {
385 b.account(i, |account| {
386 a.account(i, |account_a| {
387 assert_eq!(account_a.pubkey(), account.pubkey());
388 assert!(accounts_equal(&account_a, &account));
389 });
390 });
391 })
392 }
393
394 #[test]
395 fn test_contains_multiple_slots() {
396 let db = AccountsDb::new_single_for_tests();
397 let pk = Pubkey::from([1; 32]);
398 let slot = 0;
399 let lamports = 1;
400 let owner = Pubkey::default();
401 let executable = false;
402 let rent_epoch = 0;
403 let meta = StoredMeta {
404 write_version_obsolete: 5,
405 pubkey: pk,
406 data_len: 7,
407 };
408 let account_meta = AccountMeta {
409 lamports,
410 owner,
411 executable,
412 rent_epoch,
413 };
414 let data = Vec::default();
415 let offset = 99 * std::mem::size_of::<u64>(); let stored_size = 101;
417 let hash = AccountHash(Hash::new_unique());
418 let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
419 meta: &meta,
420 account_meta: &account_meta,
421 data: &data,
422 offset,
423 stored_size,
424 hash: &hash,
425 });
426
427 let account_from_storage = AccountFromStorage::new(&stored_account);
428
429 let accounts = [&account_from_storage, &account_from_storage];
430 let accounts2 = [(slot, &accounts[..])];
431 let test3 = StorableAccountsBySlot::new(slot, &accounts2[..], &db);
432 assert!(!test3.contains_multiple_slots());
433 }
434
435 pub fn build_accounts_from_storage<'a>(
436 accounts: impl Iterator<Item = &'a StoredAccountMeta<'a>>,
437 ) -> Vec<AccountFromStorage> {
438 accounts
439 .map(|account| AccountFromStorage::new(account))
440 .collect()
441 }
442
443 #[test]
444 fn test_storable_accounts() {
445 let max_slots = 3_u64;
446 for target_slot in 0..max_slots {
447 for entries in 0..2 {
448 for starting_slot in 0..max_slots {
449 let db = AccountsDb::new_single_for_tests();
450 let data = Vec::default();
451 let hash = AccountHash(Hash::new_unique());
452 let mut raw = Vec::new();
453 let mut raw2 = Vec::new();
454 let mut raw4 = Vec::new();
455 for entry in 0..entries {
456 let pk = Pubkey::from([entry; 32]);
457 let account = AccountSharedData::create(
458 (entry as u64) * starting_slot,
459 Vec::default(),
460 Pubkey::default(),
461 false,
462 0,
463 );
464
465 raw.push((
466 pk,
467 account.clone(),
468 starting_slot % max_slots,
469 StoredMeta {
470 write_version_obsolete: 0, pubkey: pk,
472 data_len: u64::MAX, },
474 AccountMeta {
475 lamports: account.lamports(),
476 owner: *account.owner(),
477 executable: account.executable(),
478 rent_epoch: account.rent_epoch(),
479 },
480 ));
481 }
482 for entry in 0..entries {
483 let offset = 99 * std::mem::size_of::<u64>(); let stored_size = 101;
485 let raw = &raw[entry as usize];
486 raw2.push(StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
487 meta: &raw.3,
488 account_meta: &raw.4,
489 data: &data,
490 offset,
491 stored_size,
492 hash: &hash,
493 }));
494 raw4.push((raw.0, raw.1.clone()));
495 }
496 let raw2_accounts_from_storage = build_accounts_from_storage(raw2.iter());
497
498 let mut two = Vec::new();
499 let mut three = Vec::new();
500 let mut three_accounts_from_storage_byval = Vec::new();
501 let mut four_pubkey_and_account_value = Vec::new();
502 raw.iter()
503 .zip(
504 raw2.iter()
505 .zip(raw4.iter().zip(raw2_accounts_from_storage.iter())),
506 )
507 .for_each(|(raw, (raw2, (raw4, raw2_accounts_from_storage)))| {
508 two.push((&raw.0, &raw.1)); three.push(raw2);
510 three_accounts_from_storage_byval.push(*raw2_accounts_from_storage);
511 four_pubkey_and_account_value.push(raw4);
512 });
513 let test2 = (target_slot, &two[..]);
514 let test4 = (target_slot, &four_pubkey_and_account_value[..]);
515
516 let source_slot = starting_slot % max_slots;
517
518 let storage = setup_sample_storage(&db, source_slot);
519 if let Some(offsets) = storage
522 .accounts
523 .append_accounts(&(source_slot, &three[..]), 0)
524 {
525 three_accounts_from_storage_byval
526 .iter_mut()
527 .zip(offsets.offsets.iter())
528 .for_each(|(account, offset)| {
529 account.index_info = AccountInfo::new(
530 StorageLocation::AppendVec(0, *offset),
531 if account.is_zero_lamport() { 0 } else { 1 },
532 )
533 });
534 }
535 let three_accounts_from_storage =
536 three_accounts_from_storage_byval.iter().collect::<Vec<_>>();
537
538 let accounts_with_slots = vec![(source_slot, &three_accounts_from_storage[..])];
539 let test3 = StorableAccountsBySlot::new(target_slot, &accounts_with_slots, &db);
540 let old_slot = starting_slot;
541 let for_slice = [(old_slot, &three_accounts_from_storage[..])];
542 let test_moving_slots2 =
543 StorableAccountsBySlot::new(target_slot, &for_slice, &db);
544 compare(&test2, &test3);
545 compare(&test2, &test4);
546 compare(&test2, &test_moving_slots2);
547 for (i, raw) in raw.iter().enumerate() {
548 test3.account(i, |account| {
549 assert_eq!(raw.0, *account.pubkey());
550 assert!(accounts_equal(&raw.1, &account));
551 });
552 assert_eq!(raw.2, test3.slot(i));
553 assert_eq!(target_slot, test4.slot(i));
554 assert_eq!(target_slot, test2.slot(i));
555 assert_eq!(old_slot, test_moving_slots2.slot(i));
556 }
557 assert_eq!(target_slot, test3.target_slot());
558 assert_eq!(target_slot, test4.target_slot());
559 assert_eq!(target_slot, test_moving_slots2.target_slot());
560 assert!(!test2.contains_multiple_slots());
561 assert!(!test4.contains_multiple_slots());
562 assert_eq!(test3.contains_multiple_slots(), entries > 1);
563 }
564 }
565 }
566 }
567
568 fn setup_sample_storage(db: &AccountsDb, slot: Slot) -> Arc<AccountStorageEntry> {
569 let id = 2;
570 let file_size = 10_000;
571 let (_temp_dirs, paths) = get_temp_accounts_paths(1).unwrap();
572 let data = AccountStorageEntry::new(
573 &paths[0],
574 slot,
575 id,
576 file_size,
577 AccountsFileProvider::AppendVec,
578 );
579 let storage = Arc::new(data);
580 db.storage.insert(slot, storage.clone());
581 storage
582 }
583
584 #[test]
585 fn test_storable_accounts_by_slot() {
586 for entries in 0..6 {
587 let data = Vec::default();
588 let hashes = (0..entries)
589 .map(|_| AccountHash(Hash::new_unique()))
590 .collect::<Vec<_>>();
591 let mut raw = Vec::new();
592 let mut raw2 = Vec::new();
593 for entry in 0..entries {
594 let pk = Pubkey::from([entry; 32]);
595 let account = AccountSharedData::create(
596 entry as u64,
597 Vec::default(),
598 Pubkey::default(),
599 false,
600 0,
601 );
602 raw.push((
603 pk,
604 account.clone(),
605 StoredMeta {
606 write_version_obsolete: 500 + (entry * 3) as u64, pubkey: pk,
608 data_len: (entry * 2) as u64, },
610 AccountMeta {
611 lamports: account.lamports(),
612 owner: *account.owner(),
613 executable: account.executable(),
614 rent_epoch: account.rent_epoch(),
615 },
616 ));
617 }
618
619 for entry in 0..entries {
620 let offset = 99 * std::mem::size_of::<u64>(); let stored_size = 101;
622 raw2.push(StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
623 meta: &raw[entry as usize].2,
624 account_meta: &raw[entry as usize].3,
625 data: &data,
626 offset,
627 stored_size,
628 hash: &hashes[entry as usize],
629 }));
630 }
631
632 let raw2_account_from_storage = raw2
633 .iter()
634 .map(|account| AccountFromStorage::new(account))
635 .collect::<Vec<_>>();
636 let raw2_refs = raw2.iter().collect::<Vec<_>>();
637
638 for entries0 in 0..=entries {
640 let remaining1 = entries.saturating_sub(entries0);
641 for entries1 in 0..=remaining1 {
642 let remaining2 = entries.saturating_sub(entries0 + entries1);
643 for entries2 in 0..=remaining2 {
644 let db = AccountsDb::new_single_for_tests();
645 let remaining3 = entries.saturating_sub(entries0 + entries1 + entries2);
646 let entries_by_level = [entries0, entries1, entries2, remaining3];
647 let mut overall_index = 0;
648 let mut expected_slots = Vec::default();
649 let slots_and_accounts_byval = entries_by_level
650 .iter()
651 .enumerate()
652 .filter_map(|(slot, count)| {
653 let slot = slot as Slot;
654 let count = *count as usize;
655 (overall_index < raw2.len()).then(|| {
656 let range = overall_index..(overall_index + count);
657 let mut result =
658 raw2_account_from_storage[range.clone()].to_vec();
659 let storage = setup_sample_storage(&db, slot);
662 if let Some(offsets) = storage
663 .accounts
664 .append_accounts(&(slot, &raw2_refs[range.clone()]), 0)
665 {
666 result.iter_mut().zip(offsets.offsets.iter()).for_each(
667 |(account, offset)| {
668 account.index_info = AccountInfo::new(
669 StorageLocation::AppendVec(0, *offset),
670 if account.is_zero_lamport() { 0 } else { 1 },
671 )
672 },
673 );
674 }
675
676 range.for_each(|_| expected_slots.push(slot));
677 overall_index += count;
678 (slot, result)
679 })
680 })
681 .collect::<Vec<_>>();
682 let slots_and_accounts_ref1 = slots_and_accounts_byval
683 .iter()
684 .map(|(slot, accounts)| (*slot, accounts.iter().collect::<Vec<_>>()))
685 .collect::<Vec<_>>();
686 let slots_and_accounts = slots_and_accounts_ref1
687 .iter()
688 .map(|(slot, accounts)| (*slot, &accounts[..]))
689 .collect::<Vec<_>>();
690
691 let storable =
692 StorableAccountsBySlot::new(99, &slots_and_accounts[..], &db);
693 assert_eq!(99, storable.target_slot());
694 assert_eq!(entries0 != entries, storable.contains_multiple_slots());
695 (0..entries).for_each(|index| {
696 let index = index as usize;
697 let mut called = false;
698 storable.account(index, |account| {
699 called = true;
700 assert!(accounts_equal(&account, &raw2[index]));
701 assert_eq!(account.pubkey(), raw2[index].pubkey());
702 });
703 assert!(called);
704 assert_eq!(storable.slot(index), expected_slots[index]);
705 })
706 }
707 }
708 }
709 }
710 }
711}