1use {
3 crate::{
4 account_storage::meta::StoredAccountMeta,
5 accounts_db::{AccountFromStorage, AccountStorageEntry, AccountsDb},
6 accounts_index::ZeroLamport,
7 },
8 solana_pubkey::Pubkey,
9 solana_sdk::{
10 account::{AccountSharedData, ReadableAccount},
11 clock::{Epoch, Slot},
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 ZeroLamport for AccountForStorage<'_> {
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 ReadableAccount for AccountForStorage<'_> {
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 {
108 fn account<Ret>(
110 &self,
111 index: usize,
112 callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
113 ) -> Ret;
114 fn account_default_if_zero_lamport<Ret>(
116 &self,
117 index: usize,
118 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
119 ) -> Ret {
120 self.account(index, |account| {
121 callback(if account.lamports() != 0 {
122 account
123 } else {
124 AccountForStorage::AddressAndAccount((
126 account.pubkey(),
127 &DEFAULT_ACCOUNT_SHARED_DATA,
128 ))
129 })
130 })
131 }
132 fn slot(&self, index: usize) -> Slot;
134 fn target_slot(&self) -> Slot;
136 fn is_empty(&self) -> bool {
138 self.len() == 0
139 }
140 fn len(&self) -> usize;
142 fn contains_multiple_slots(&self) -> bool {
145 false
146 }
147}
148
149impl<'a: 'b, 'b> StorableAccounts<'a> for (Slot, &'b [(&'a Pubkey, &'a AccountSharedData)]) {
150 fn account<Ret>(
151 &self,
152 index: usize,
153 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
154 ) -> Ret {
155 callback((self.1[index].0, self.1[index].1).into())
156 }
157 fn slot(&self, _index: usize) -> Slot {
158 self.target_slot()
160 }
161 fn target_slot(&self) -> Slot {
162 self.0
163 }
164 fn len(&self) -> usize {
165 self.1.len()
166 }
167}
168
169impl<'a: 'b, 'b> StorableAccounts<'a> for (Slot, &'b [(Pubkey, AccountSharedData)]) {
170 fn account<Ret>(
171 &self,
172 index: usize,
173 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
174 ) -> Ret {
175 callback((&self.1[index].0, &self.1[index].1).into())
176 }
177 fn slot(&self, _index: usize) -> Slot {
178 self.target_slot()
180 }
181 fn target_slot(&self) -> Slot {
182 self.0
183 }
184 fn len(&self) -> usize {
185 self.1.len()
186 }
187}
188
189pub struct StorableAccountsBySlot<'a> {
191 target_slot: Slot,
192 slots_and_accounts: &'a [(Slot, &'a [&'a AccountFromStorage])],
194
195 starting_offsets: Vec<usize>,
200 contains_multiple_slots: bool,
202 len: usize,
204 db: &'a AccountsDb,
205 cached_storage: RwLock<StorableAccountsCacher>,
207}
208
209impl<'a> StorableAccountsBySlot<'a> {
210 pub fn new(
212 target_slot: Slot,
213 slots_and_accounts: &'a [(Slot, &'a [&'a AccountFromStorage])],
214 db: &'a AccountsDb,
215 ) -> Self {
216 let mut cumulative_len = 0usize;
217 let mut starting_offsets = Vec::with_capacity(slots_and_accounts.len());
218 let first_slot = slots_and_accounts
219 .first()
220 .map(|(slot, _)| *slot)
221 .unwrap_or_default();
222 let mut contains_multiple_slots = false;
223 for (slot, accounts) in slots_and_accounts {
224 cumulative_len = cumulative_len.saturating_add(accounts.len());
225 starting_offsets.push(cumulative_len);
226 contains_multiple_slots |= &first_slot != slot;
227 }
228 Self {
229 target_slot,
230 slots_and_accounts,
231 starting_offsets,
232 contains_multiple_slots,
233 len: cumulative_len,
234 db,
235 cached_storage: RwLock::default(),
236 }
237 }
238 fn find_internal_index(&self, index: usize) -> (usize, usize) {
241 for (offset_index, next_offset) in self.starting_offsets.iter().enumerate() {
244 if next_offset > &index {
245 let prior_offset = if offset_index > 0 {
247 self.starting_offsets[offset_index.saturating_sub(1)]
248 } else {
249 0
250 };
251 return (offset_index, index - prior_offset);
252 }
253 }
254 panic!("failed");
255 }
256}
257
258impl<'a> StorableAccounts<'a> for StorableAccountsBySlot<'a> {
259 fn account<Ret>(
260 &self,
261 index: usize,
262 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
263 ) -> Ret {
264 let indexes = self.find_internal_index(index);
265 let slot = self.slots_and_accounts[indexes.0].0;
266 let data = self.slots_and_accounts[indexes.0].1[indexes.1];
267 let offset = data.index_info.offset();
268 let mut call_callback = |storage: &AccountStorageEntry| {
269 storage
270 .accounts
271 .get_stored_account_meta_callback(offset, |account: StoredAccountMeta| {
272 callback((&account).into())
273 })
274 .expect("account has to exist to be able to store it")
275 };
276 {
277 let reader = self.cached_storage.read().unwrap();
278 if reader.slot == slot {
279 if let Some(storage) = reader.storage.as_ref() {
280 return call_callback(storage);
281 }
282 }
283 }
284 let storage = self
287 .db
288 .storage
289 .get_slot_storage_entry_shrinking_in_progress_ok(slot)
290 .expect("source slot has to have a storage to be able to store accounts");
291 let ret = call_callback(&storage);
292 let mut writer = self.cached_storage.write().unwrap();
293 writer.slot = slot;
294 writer.storage = Some(storage);
295 ret
296 }
297 fn slot(&self, index: usize) -> Slot {
298 let indexes = self.find_internal_index(index);
299 self.slots_and_accounts[indexes.0].0
300 }
301 fn target_slot(&self) -> Slot {
302 self.target_slot
303 }
304 fn len(&self) -> usize {
305 self.len
306 }
307 fn contains_multiple_slots(&self) -> bool {
308 self.contains_multiple_slots
309 }
310}
311
312#[cfg(test)]
313pub mod tests {
314 use {
315 super::*,
316 crate::{
317 account_info::{AccountInfo, StorageLocation},
318 account_storage::meta::{AccountMeta, StoredAccountMeta, StoredMeta},
319 accounts_db::{get_temp_accounts_paths, AccountStorageEntry},
320 accounts_file::AccountsFileProvider,
321 accounts_hash::AccountHash,
322 append_vec::AppendVecStoredAccountMeta,
323 },
324 solana_sdk::{
325 account::{accounts_equal, AccountSharedData, WritableAccount},
326 hash::Hash,
327 },
328 std::sync::Arc,
329 };
330
331 impl<'a> StorableAccounts<'a> for (Slot, &'a [&'a StoredAccountMeta<'a>]) {
335 fn account<Ret>(
336 &self,
337 index: usize,
338 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
339 ) -> Ret {
340 callback(self.1[index].into())
341 }
342 fn slot(&self, _index: usize) -> Slot {
343 self.0
345 }
346 fn target_slot(&self) -> Slot {
347 self.0
348 }
349 fn len(&self) -> usize {
350 self.1.len()
351 }
352 }
353
354 impl<'a, T: ReadableAccount + Sync> StorableAccounts<'a> for (Slot, &'a [&'a (Pubkey, T)])
356 where
357 AccountForStorage<'a>: From<(&'a Pubkey, &'a T)>,
358 {
359 fn account<Ret>(
360 &self,
361 index: usize,
362 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
363 ) -> Ret {
364 callback((&self.1[index].0, &self.1[index].1).into())
365 }
366 fn slot(&self, _index: usize) -> Slot {
367 self.target_slot()
369 }
370 fn target_slot(&self) -> Slot {
371 self.0
372 }
373 fn len(&self) -> usize {
374 self.1.len()
375 }
376 }
377
378 impl<'a> StorableAccounts<'a> for (Slot, &'a [&'a StoredAccountMeta<'a>], Slot) {
382 fn account<Ret>(
383 &self,
384 index: usize,
385 mut callback: impl for<'local> FnMut(AccountForStorage<'local>) -> Ret,
386 ) -> Ret {
387 callback(self.1[index].into())
388 }
389 fn slot(&self, _index: usize) -> Slot {
390 self.2
392 }
393 fn target_slot(&self) -> Slot {
394 self.0
395 }
396 fn len(&self) -> usize {
397 self.1.len()
398 }
399 }
400
401 fn compare<'a>(a: &impl StorableAccounts<'a>, b: &impl StorableAccounts<'a>) {
402 assert_eq!(a.target_slot(), b.target_slot());
403 assert_eq!(a.len(), b.len());
404 assert_eq!(a.is_empty(), b.is_empty());
405 (0..a.len()).for_each(|i| {
406 b.account(i, |account| {
407 a.account(i, |account_a| {
408 assert_eq!(account_a.pubkey(), account.pubkey());
409 assert!(accounts_equal(&account_a, &account));
410 });
411 });
412 })
413 }
414
415 #[test]
416 fn test_contains_multiple_slots() {
417 let db = AccountsDb::new_single_for_tests();
418 let pk = Pubkey::from([1; 32]);
419 let slot = 0;
420 let lamports = 1;
421 let owner = Pubkey::default();
422 let executable = false;
423 let rent_epoch = 0;
424 let meta = StoredMeta {
425 write_version_obsolete: 5,
426 pubkey: pk,
427 data_len: 7,
428 };
429 let account_meta = AccountMeta {
430 lamports,
431 owner,
432 executable,
433 rent_epoch,
434 };
435 let data = Vec::default();
436 let offset = 99 * std::mem::size_of::<u64>(); let stored_size = 101;
438 let hash = AccountHash(Hash::new_unique());
439 let stored_account = StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
440 meta: &meta,
441 account_meta: &account_meta,
442 data: &data,
443 offset,
444 stored_size,
445 hash: &hash,
446 });
447
448 let account_from_storage = AccountFromStorage::new(&stored_account);
449
450 let accounts = [&account_from_storage, &account_from_storage];
451 let accounts2 = [(slot, &accounts[..])];
452 let test3 = StorableAccountsBySlot::new(slot, &accounts2[..], &db);
453 assert!(!test3.contains_multiple_slots());
454 }
455
456 pub fn build_accounts_from_storage<'a>(
457 accounts: impl Iterator<Item = &'a StoredAccountMeta<'a>>,
458 ) -> Vec<AccountFromStorage> {
459 accounts
460 .map(|account| AccountFromStorage::new(account))
461 .collect()
462 }
463
464 #[test]
465 fn test_storable_accounts() {
466 let max_slots = 3_u64;
467 for target_slot in 0..max_slots {
468 for entries in 0..2 {
469 for starting_slot in 0..max_slots {
470 let db = AccountsDb::new_single_for_tests();
471 let data = Vec::default();
472 let hash = AccountHash(Hash::new_unique());
473 let mut raw = Vec::new();
474 let mut raw2 = Vec::new();
475 let mut raw4 = Vec::new();
476 for entry in 0..entries {
477 let pk = Pubkey::from([entry; 32]);
478 let account = AccountSharedData::create(
479 (entry as u64) * starting_slot,
480 Vec::default(),
481 Pubkey::default(),
482 false,
483 0,
484 );
485
486 raw.push((
487 pk,
488 account.clone(),
489 starting_slot % max_slots,
490 StoredMeta {
491 write_version_obsolete: 0, pubkey: pk,
493 data_len: u64::MAX, },
495 AccountMeta {
496 lamports: account.lamports(),
497 owner: *account.owner(),
498 executable: account.executable(),
499 rent_epoch: account.rent_epoch(),
500 },
501 ));
502 }
503 for entry in 0..entries {
504 let offset = 99 * std::mem::size_of::<u64>(); let stored_size = 101;
506 let raw = &raw[entry as usize];
507 raw2.push(StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
508 meta: &raw.3,
509 account_meta: &raw.4,
510 data: &data,
511 offset,
512 stored_size,
513 hash: &hash,
514 }));
515 raw4.push((raw.0, raw.1.clone()));
516 }
517 let raw2_accounts_from_storage = build_accounts_from_storage(raw2.iter());
518
519 let mut two = Vec::new();
520 let mut three = Vec::new();
521 let mut three_accounts_from_storage_byval = Vec::new();
522 let mut four_pubkey_and_account_value = Vec::new();
523 raw.iter()
524 .zip(
525 raw2.iter()
526 .zip(raw4.iter().zip(raw2_accounts_from_storage.iter())),
527 )
528 .for_each(|(raw, (raw2, (raw4, raw2_accounts_from_storage)))| {
529 two.push((&raw.0, &raw.1)); three.push(raw2);
531 three_accounts_from_storage_byval.push(*raw2_accounts_from_storage);
532 four_pubkey_and_account_value.push(raw4);
533 });
534 let test2 = (target_slot, &two[..]);
535 let test4 = (target_slot, &four_pubkey_and_account_value[..]);
536
537 let source_slot = starting_slot % max_slots;
538
539 let storage = setup_sample_storage(&db, source_slot);
540 if let Some(offsets) = storage
543 .accounts
544 .append_accounts(&(source_slot, &three[..]), 0)
545 {
546 three_accounts_from_storage_byval
547 .iter_mut()
548 .zip(offsets.offsets.iter())
549 .for_each(|(account, offset)| {
550 account.index_info = AccountInfo::new(
551 StorageLocation::AppendVec(0, *offset),
552 if account.is_zero_lamport() { 0 } else { 1 },
553 )
554 });
555 }
556 let three_accounts_from_storage =
557 three_accounts_from_storage_byval.iter().collect::<Vec<_>>();
558
559 let accounts_with_slots = vec![(source_slot, &three_accounts_from_storage[..])];
560 let test3 = StorableAccountsBySlot::new(target_slot, &accounts_with_slots, &db);
561 let old_slot = starting_slot;
562 let for_slice = [(old_slot, &three_accounts_from_storage[..])];
563 let test_moving_slots2 =
564 StorableAccountsBySlot::new(target_slot, &for_slice, &db);
565 compare(&test2, &test3);
566 compare(&test2, &test4);
567 compare(&test2, &test_moving_slots2);
568 for (i, raw) in raw.iter().enumerate() {
569 test3.account(i, |account| {
570 assert_eq!(raw.0, *account.pubkey());
571 assert!(accounts_equal(&raw.1, &account));
572 });
573 assert_eq!(raw.2, test3.slot(i));
574 assert_eq!(target_slot, test4.slot(i));
575 assert_eq!(target_slot, test2.slot(i));
576 assert_eq!(old_slot, test_moving_slots2.slot(i));
577 }
578 assert_eq!(target_slot, test3.target_slot());
579 assert_eq!(target_slot, test4.target_slot());
580 assert_eq!(target_slot, test_moving_slots2.target_slot());
581 assert!(!test2.contains_multiple_slots());
582 assert!(!test4.contains_multiple_slots());
583 assert_eq!(test3.contains_multiple_slots(), entries > 1);
584 }
585 }
586 }
587 }
588
589 fn setup_sample_storage(db: &AccountsDb, slot: Slot) -> Arc<AccountStorageEntry> {
590 let id = 2;
591 let file_size = 10_000;
592 let (_temp_dirs, paths) = get_temp_accounts_paths(1).unwrap();
593 let data = AccountStorageEntry::new(
594 &paths[0],
595 slot,
596 id,
597 file_size,
598 AccountsFileProvider::AppendVec,
599 );
600 let storage = Arc::new(data);
601 db.storage.insert(slot, storage.clone());
602 storage
603 }
604
605 #[test]
606 fn test_storable_accounts_by_slot() {
607 for entries in 0..6 {
608 let data = Vec::default();
609 let hashes = (0..entries)
610 .map(|_| AccountHash(Hash::new_unique()))
611 .collect::<Vec<_>>();
612 let mut raw = Vec::new();
613 let mut raw2 = Vec::new();
614 for entry in 0..entries {
615 let pk = Pubkey::from([entry; 32]);
616 let account = AccountSharedData::create(
617 entry as u64,
618 Vec::default(),
619 Pubkey::default(),
620 false,
621 0,
622 );
623 raw.push((
624 pk,
625 account.clone(),
626 StoredMeta {
627 write_version_obsolete: 500 + (entry * 3) as u64, pubkey: pk,
629 data_len: (entry * 2) as u64, },
631 AccountMeta {
632 lamports: account.lamports(),
633 owner: *account.owner(),
634 executable: account.executable(),
635 rent_epoch: account.rent_epoch(),
636 },
637 ));
638 }
639
640 for entry in 0..entries {
641 let offset = 99 * std::mem::size_of::<u64>(); let stored_size = 101;
643 raw2.push(StoredAccountMeta::AppendVec(AppendVecStoredAccountMeta {
644 meta: &raw[entry as usize].2,
645 account_meta: &raw[entry as usize].3,
646 data: &data,
647 offset,
648 stored_size,
649 hash: &hashes[entry as usize],
650 }));
651 }
652
653 let raw2_account_from_storage = raw2
654 .iter()
655 .map(|account| AccountFromStorage::new(account))
656 .collect::<Vec<_>>();
657 let raw2_refs = raw2.iter().collect::<Vec<_>>();
658
659 for entries0 in 0..=entries {
661 let remaining1 = entries.saturating_sub(entries0);
662 for entries1 in 0..=remaining1 {
663 let remaining2 = entries.saturating_sub(entries0 + entries1);
664 for entries2 in 0..=remaining2 {
665 let db = AccountsDb::new_single_for_tests();
666 let remaining3 = entries.saturating_sub(entries0 + entries1 + entries2);
667 let entries_by_level = [entries0, entries1, entries2, remaining3];
668 let mut overall_index = 0;
669 let mut expected_slots = Vec::default();
670 let slots_and_accounts_byval = entries_by_level
671 .iter()
672 .enumerate()
673 .filter_map(|(slot, count)| {
674 let slot = slot as Slot;
675 let count = *count as usize;
676 (overall_index < raw2.len()).then(|| {
677 let range = overall_index..(overall_index + count);
678 let mut result =
679 raw2_account_from_storage[range.clone()].to_vec();
680 let storage = setup_sample_storage(&db, slot);
683 if let Some(offsets) = storage
684 .accounts
685 .append_accounts(&(slot, &raw2_refs[range.clone()]), 0)
686 {
687 result.iter_mut().zip(offsets.offsets.iter()).for_each(
688 |(account, offset)| {
689 account.index_info = AccountInfo::new(
690 StorageLocation::AppendVec(0, *offset),
691 if account.is_zero_lamport() { 0 } else { 1 },
692 )
693 },
694 );
695 }
696
697 range.for_each(|_| expected_slots.push(slot));
698 overall_index += count;
699 (slot, result)
700 })
701 })
702 .collect::<Vec<_>>();
703 let slots_and_accounts_ref1 = slots_and_accounts_byval
704 .iter()
705 .map(|(slot, accounts)| (*slot, accounts.iter().collect::<Vec<_>>()))
706 .collect::<Vec<_>>();
707 let slots_and_accounts = slots_and_accounts_ref1
708 .iter()
709 .map(|(slot, accounts)| (*slot, &accounts[..]))
710 .collect::<Vec<_>>();
711
712 let storable =
713 StorableAccountsBySlot::new(99, &slots_and_accounts[..], &db);
714 assert_eq!(99, storable.target_slot());
715 assert_eq!(entries0 != entries, storable.contains_multiple_slots());
716 (0..entries).for_each(|index| {
717 let index = index as usize;
718 let mut called = false;
719 storable.account(index, |account| {
720 called = true;
721 assert!(accounts_equal(&account, &raw2[index]));
722 assert_eq!(account.pubkey(), raw2[index].pubkey());
723 });
724 assert!(called);
725 assert_eq!(storable.slot(index), expected_slots[index]);
726 })
727 }
728 }
729 }
730 }
731 }
732}