1use {
4 crate::accounts_db::{AccountStorageEntry, AccountsFileId},
5 dashmap::DashMap,
6 solana_clock::Slot,
7 solana_nohash_hasher::BuildNoHashHasher,
8 std::sync::Arc,
9};
10
11pub mod meta;
12
13#[derive(Clone, Debug)]
14pub struct AccountStorageReference {
15 pub storage: Arc<AccountStorageEntry>,
17 pub id: AccountsFileId,
20}
21
22pub type AccountStorageMap = DashMap<Slot, AccountStorageReference, BuildNoHashHasher<Slot>>;
23
24#[derive(Default, Debug)]
25pub struct AccountStorage {
26 map: AccountStorageMap,
28 shrink_in_progress_map: DashMap<Slot, Arc<AccountStorageEntry>, BuildNoHashHasher<Slot>>,
32}
33
34impl AccountStorage {
35 pub(crate) fn get_account_storage_entry(
54 &self,
55 slot: Slot,
56 store_id: AccountsFileId,
57 ) -> Option<Arc<AccountStorageEntry>> {
58 let lookup_in_map = || {
59 self.map
60 .get(&slot)
61 .and_then(|r| (r.id == store_id).then_some(Arc::clone(&r.storage)))
62 };
63
64 lookup_in_map()
65 .or_else(|| {
66 self.shrink_in_progress_map.get(&slot).and_then(|entry| {
67 (entry.value().id() == store_id).then(|| Arc::clone(entry.value()))
68 })
69 })
70 .or_else(lookup_in_map)
71 }
72
73 pub(crate) fn no_shrink_in_progress(&self) -> bool {
75 self.shrink_in_progress_map.is_empty()
76 }
77
78 pub fn get_slot_storage_entry(&self, slot: Slot) -> Option<Arc<AccountStorageEntry>> {
81 assert!(
82 self.no_shrink_in_progress(),
83 "self.no_shrink_in_progress(): {slot}"
84 );
85 self.get_slot_storage_entry_shrinking_in_progress_ok(slot)
86 }
87
88 pub(crate) fn replace_storage_with_equivalent(
89 &self,
90 slot: Slot,
91 storage: Arc<AccountStorageEntry>,
92 ) {
93 assert_eq!(storage.slot(), slot);
94 if let Some(mut existing_storage) = self.map.get_mut(&slot) {
95 assert_eq!(slot, existing_storage.value().storage.slot());
96 existing_storage.value_mut().storage = storage;
97 }
98 }
99
100 pub(crate) fn get_slot_storage_entry_shrinking_in_progress_ok(
102 &self,
103 slot: Slot,
104 ) -> Option<Arc<AccountStorageEntry>> {
105 self.map.get(&slot).map(|entry| Arc::clone(&entry.storage))
106 }
107
108 pub(crate) fn all_slots(&self) -> Vec<Slot> {
109 assert!(self.no_shrink_in_progress());
110 self.map.iter().map(|iter_item| *iter_item.key()).collect()
111 }
112
113 #[cfg(test)]
115 pub(crate) fn is_empty_entry(&self, slot: Slot) -> bool {
116 assert!(
117 self.no_shrink_in_progress(),
118 "self.no_shrink_in_progress(): {slot}"
119 );
120 self.map.get(&slot).is_none()
121 }
122
123 pub fn initialize(&mut self, all_storages: AccountStorageMap) {
125 assert!(self.map.is_empty());
126 assert!(self.no_shrink_in_progress());
127 self.map.extend(all_storages)
128 }
129
130 pub(crate) fn remove(
133 &self,
134 slot: &Slot,
135 shrink_can_be_active: bool,
136 ) -> Option<Arc<AccountStorageEntry>> {
137 assert!(shrink_can_be_active || self.shrink_in_progress_map.is_empty());
138 self.map.remove(slot).map(|(_, entry)| entry.storage)
139 }
140
141 pub(crate) fn iter(&self) -> AccountStorageIter<'_> {
143 assert!(self.no_shrink_in_progress());
144 AccountStorageIter::new(self)
145 }
146
147 pub(crate) fn insert(&self, slot: Slot, store: Arc<AccountStorageEntry>) {
148 assert!(
149 self.no_shrink_in_progress(),
150 "self.no_shrink_in_progress(): {slot}"
151 );
152 assert!(self
153 .map
154 .insert(
155 slot,
156 AccountStorageReference {
157 id: store.id(),
158 storage: store,
159 }
160 )
161 .is_none());
162 }
163
164 pub(crate) fn shrinking_in_progress(
171 &self,
172 slot: Slot,
173 new_store: Arc<AccountStorageEntry>,
174 ) -> ShrinkInProgress<'_> {
175 let shrinking_store = Arc::clone(
176 &self
177 .map
178 .get(&slot)
179 .expect("no pre-existing storage for shrinking slot")
180 .value()
181 .storage,
182 );
183
184 assert!(
186 self.shrink_in_progress_map
187 .insert(slot, Arc::clone(&new_store))
188 .is_none(),
189 "duplicate call"
190 );
191
192 ShrinkInProgress {
193 storage: self,
194 slot,
195 new_store,
196 old_store: shrinking_store,
197 }
198 }
199
200 #[cfg(test)]
201 pub(crate) fn len(&self) -> usize {
202 self.map.len()
203 }
204
205 pub fn get_if(
214 &self,
215 predicate: impl Fn(&Slot, &AccountStorageEntry) -> bool,
216 ) -> Box<[(Slot, Arc<AccountStorageEntry>)]> {
217 assert!(self.no_shrink_in_progress());
218 self.map
219 .iter()
220 .filter_map(|entry| {
221 let slot = entry.key();
222 let storage = &entry.value().storage;
223 predicate(slot, storage).then(|| (*slot, Arc::clone(storage)))
224 })
225 .collect()
226 }
227}
228
229pub struct AccountStorageIter<'a> {
231 iter: dashmap::iter::Iter<'a, Slot, AccountStorageReference, BuildNoHashHasher<Slot>>,
232}
233
234impl<'a> AccountStorageIter<'a> {
235 pub fn new(storage: &'a AccountStorage) -> Self {
236 Self {
237 iter: storage.map.iter(),
238 }
239 }
240}
241
242impl Iterator for AccountStorageIter<'_> {
243 type Item = (Slot, Arc<AccountStorageEntry>);
244
245 fn next(&mut self) -> Option<Self::Item> {
246 if let Some(entry) = self.iter.next() {
247 let slot = entry.key();
248 let store = entry.value();
249 return Some((*slot, Arc::clone(&store.storage)));
250 }
251 None
252 }
253}
254
255#[derive(Debug)]
258pub struct ShrinkInProgress<'a> {
259 storage: &'a AccountStorage,
260 old_store: Arc<AccountStorageEntry>,
262 new_store: Arc<AccountStorageEntry>,
264 slot: Slot,
265}
266
267impl Drop for ShrinkInProgress<'_> {
269 fn drop(&mut self) {
270 assert_eq!(
271 self.storage
272 .map
273 .insert(
274 self.slot,
275 AccountStorageReference {
276 storage: Arc::clone(&self.new_store),
277 id: self.new_store.id()
278 }
279 )
280 .map(|store| store.id),
281 Some(self.old_store.id())
282 );
283
284 assert!(self
286 .storage
287 .shrink_in_progress_map
288 .remove(&self.slot)
289 .is_some());
290 }
291}
292
293impl ShrinkInProgress<'_> {
294 pub fn new_storage(&self) -> &Arc<AccountStorageEntry> {
295 &self.new_store
296 }
297 pub(crate) fn old_storage(&self) -> &Arc<AccountStorageEntry> {
298 &self.old_store
299 }
300}
301
302#[cfg_attr(feature = "frozen-abi", derive(AbiExample, AbiEnumVisitor))]
303#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize, Serialize)]
304pub enum AccountStorageStatus {
305 Available = 0,
306 Full = 1,
307 Candidate = 2,
308}
309
310impl Default for AccountStorageStatus {
311 fn default() -> Self {
312 Self::Available
313 }
314}
315
316#[cfg(test)]
317pub(crate) mod tests {
318 use {
319 super::*,
320 crate::accounts_file::AccountsFileProvider,
321 std::{iter, path::Path},
322 };
323
324 #[test]
325 fn test_shrink_in_progress() {
326 let storage = AccountStorage::default();
328 let slot = 0;
329 let id = 0;
330 assert!(storage.get_account_storage_entry(slot, id).is_none());
332
333 let common_store_path = Path::new("");
335 let store_file_size = 4000;
336 let store_file_size2 = store_file_size * 2;
337 let entry = Arc::new(AccountStorageEntry::new(
339 common_store_path,
340 slot,
341 id,
342 store_file_size,
343 AccountsFileProvider::AppendVec,
344 ));
345 let entry2 = Arc::new(AccountStorageEntry::new(
346 common_store_path,
347 slot,
348 id,
349 store_file_size2,
350 AccountsFileProvider::AppendVec,
351 ));
352 storage
353 .map
354 .insert(slot, AccountStorageReference { id, storage: entry });
355
356 assert_eq!(
358 store_file_size,
359 storage
360 .get_account_storage_entry(slot, id)
361 .map(|entry| entry.accounts.capacity())
362 .unwrap_or_default()
363 );
364
365 storage.shrink_in_progress_map.insert(slot, entry2);
367
368 assert_eq!(
370 store_file_size,
371 storage
372 .get_account_storage_entry(slot, id)
373 .map(|entry| entry.accounts.capacity())
374 .unwrap_or_default()
375 );
376
377 storage.map.remove(&slot).unwrap();
379
380 assert_eq!(
382 store_file_size2,
383 storage
384 .get_account_storage_entry(slot, id)
385 .map(|entry| entry.accounts.capacity())
386 .unwrap_or_default()
387 );
388 }
389
390 impl AccountStorage {
391 fn get_test_storage_with_id(&self, id: AccountsFileId) -> Arc<AccountStorageEntry> {
392 let slot = 0;
393 let common_store_path = Path::new("");
395 let store_file_size = 4000;
396 Arc::new(AccountStorageEntry::new(
397 common_store_path,
398 slot,
399 id,
400 store_file_size,
401 AccountsFileProvider::AppendVec,
402 ))
403 }
404 fn get_test_storage(&self) -> Arc<AccountStorageEntry> {
405 self.get_test_storage_with_id(0)
406 }
407 }
408
409 #[test]
410 #[should_panic(expected = "self.no_shrink_in_progress()")]
411 fn test_get_slot_storage_entry_fail() {
412 let storage = AccountStorage::default();
413 storage
414 .shrink_in_progress_map
415 .insert(0, storage.get_test_storage());
416 storage.get_slot_storage_entry(0);
417 }
418
419 #[test]
420 #[should_panic(expected = "self.no_shrink_in_progress()")]
421 fn test_all_slots_fail() {
422 let storage = AccountStorage::default();
423 storage
424 .shrink_in_progress_map
425 .insert(0, storage.get_test_storage());
426 storage.all_slots();
427 }
428
429 #[test]
430 #[should_panic(expected = "self.no_shrink_in_progress()")]
431 fn test_initialize_fail() {
432 let mut storage = AccountStorage::default();
433 storage
434 .shrink_in_progress_map
435 .insert(0, storage.get_test_storage());
436 storage.initialize(AccountStorageMap::default());
437 }
438
439 #[test]
440 #[should_panic(expected = "shrink_can_be_active || self.shrink_in_progress_map.is_empty()")]
441 fn test_remove_fail() {
442 let storage = AccountStorage::default();
443 storage
444 .shrink_in_progress_map
445 .insert(0, storage.get_test_storage());
446 storage.remove(&0, false);
447 }
448
449 #[test]
450 #[should_panic(expected = "self.no_shrink_in_progress()")]
451 fn test_iter_fail() {
452 let storage = AccountStorage::default();
453 storage
454 .shrink_in_progress_map
455 .insert(0, storage.get_test_storage());
456 storage.iter();
457 }
458
459 #[test]
460 #[should_panic(expected = "self.no_shrink_in_progress()")]
461 fn test_insert_fail() {
462 let storage = AccountStorage::default();
463 let sample = storage.get_test_storage();
464 storage.shrink_in_progress_map.insert(0, sample.clone());
465 storage.insert(0, sample);
466 }
467
468 #[test]
469 #[should_panic(expected = "duplicate call")]
470 fn test_shrinking_in_progress_fail3() {
471 let storage = AccountStorage::default();
473 let sample = storage.get_test_storage();
474 storage.map.insert(
475 0,
476 AccountStorageReference {
477 id: 0,
478 storage: sample.clone(),
479 },
480 );
481 storage.shrink_in_progress_map.insert(0, sample.clone());
482 storage.shrinking_in_progress(0, sample);
483 }
484
485 #[test]
486 #[should_panic(expected = "duplicate call")]
487 fn test_shrinking_in_progress_fail4() {
488 let storage = AccountStorage::default();
490 let sample_to_shrink = storage.get_test_storage();
491 let sample = storage.get_test_storage();
492 storage.map.insert(
493 0,
494 AccountStorageReference {
495 id: 0,
496 storage: sample_to_shrink,
497 },
498 );
499 let _shrinking_in_progress = storage.shrinking_in_progress(0, sample.clone());
500 storage.shrinking_in_progress(0, sample);
501 }
502
503 #[test]
504 fn test_shrinking_in_progress_second_call() {
505 let storage = AccountStorage::default();
508 let slot = 0;
509 let id_to_shrink = 1;
510 let id_shrunk = 0;
511 let sample_to_shrink = storage.get_test_storage_with_id(id_to_shrink);
512 let sample = storage.get_test_storage();
513 storage.map.insert(
514 slot,
515 AccountStorageReference {
516 id: id_to_shrink,
517 storage: sample_to_shrink,
518 },
519 );
520 let shrinking_in_progress = storage.shrinking_in_progress(slot, sample.clone());
521 assert!(storage.map.contains_key(&slot));
522 assert_eq!(id_to_shrink, storage.map.get(&slot).unwrap().storage.id());
523 assert_eq!(
524 (slot, id_shrunk),
525 storage
526 .shrink_in_progress_map
527 .iter()
528 .next()
529 .map(|r| (*r.key(), r.value().id()))
530 .unwrap()
531 );
532 drop(shrinking_in_progress);
533 assert!(storage.map.contains_key(&slot));
534 assert_eq!(id_shrunk, storage.map.get(&slot).unwrap().storage.id());
535 assert!(storage.shrink_in_progress_map.is_empty());
536 storage.shrinking_in_progress(slot, sample);
537 }
538
539 #[test]
540 #[should_panic(expected = "no pre-existing storage for shrinking slot")]
541 fn test_shrinking_in_progress_fail1() {
542 let storage = AccountStorage::default();
544 let sample = storage.get_test_storage();
545 storage.shrinking_in_progress(0, sample);
546 }
547
548 #[test]
549 #[should_panic(expected = "no pre-existing storage for shrinking slot")]
550 fn test_shrinking_in_progress_fail2() {
551 let storage = AccountStorage::default();
553 let sample = storage.get_test_storage();
554 storage.shrinking_in_progress(0, sample);
555 }
556
557 #[test]
558 fn test_missing() {
559 let storage = AccountStorage::default();
562 let sample = storage.get_test_storage();
563 let id = sample.id();
564 let missing_id = 9999;
565 let slot = sample.slot();
566 assert!(storage.get_account_storage_entry(slot, id).is_none());
568 assert!(storage
570 .get_account_storage_entry(slot, missing_id)
571 .is_none());
572 storage.map.insert(
573 slot,
574 AccountStorageReference {
575 id,
576 storage: sample.clone(),
577 },
578 );
579 assert!(storage.get_account_storage_entry(slot, id).is_some());
581 assert!(storage
582 .get_account_storage_entry(slot, missing_id)
583 .is_none());
584 storage
585 .shrink_in_progress_map
586 .insert(slot, Arc::clone(&sample));
587 assert!(storage
589 .get_account_storage_entry(slot, missing_id)
590 .is_none());
591 assert!(storage.get_account_storage_entry(slot, id).is_some());
592 storage.map.remove(&slot);
593 assert!(storage
595 .get_account_storage_entry(slot, missing_id)
596 .is_none());
597 assert!(storage.get_account_storage_entry(slot, id).is_some());
598 }
599
600 #[test]
601 fn test_get_if() {
602 let storage = AccountStorage::default();
603 assert!(storage.get_if(|_, _| true).is_empty());
604
605 let ids = [123, 456, 789];
607 for id in ids {
608 let slot = id as Slot;
609 let entry = AccountStorageEntry::new(
610 Path::new(""),
611 slot,
612 id,
613 5000,
614 AccountsFileProvider::AppendVec,
615 );
616 storage.map.insert(
617 slot,
618 AccountStorageReference {
619 id,
620 storage: entry.into(),
621 },
622 );
623 }
624
625 for id in ids {
627 let found = storage.get_if(|slot, _| *slot == id as Slot);
628 assert!(found
629 .iter()
630 .map(|(slot, _)| *slot)
631 .eq(iter::once(id as Slot)));
632 }
633
634 assert!(storage.get_if(|_, _| false).is_empty());
635 assert_eq!(storage.get_if(|_, _| true).len(), ids.len());
636 }
637
638 #[test]
639 #[should_panic(expected = "self.no_shrink_in_progress()")]
640 fn test_get_if_fail() {
641 let storage = AccountStorage::default();
642 storage
643 .shrink_in_progress_map
644 .insert(0, storage.get_test_storage());
645 storage.get_if(|_, _| true);
646 }
647}