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