solana_accounts_db/
obsolete_accounts.rs1use {crate::account_info::Offset, solana_clock::Slot};
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct ObsoleteAccountItem {
5 pub offset: Offset,
7 pub data_len: usize,
9 pub slot: Slot,
11}
12
13#[derive(Debug, Clone, PartialEq, Default)]
14pub struct ObsoleteAccounts {
15 pub accounts: Vec<ObsoleteAccountItem>,
16}
17
18impl ObsoleteAccounts {
19 pub fn mark_accounts_obsolete(
21 &mut self,
22 newly_obsolete_accounts: impl ExactSizeIterator<Item = (Offset, usize)>,
23 slot: Slot,
24 ) {
25 self.accounts.reserve(newly_obsolete_accounts.len());
26
27 for (offset, data_len) in newly_obsolete_accounts {
28 self.accounts.push(ObsoleteAccountItem {
29 offset,
30 data_len,
31 slot,
32 });
33 }
34 }
35
36 pub fn filter_obsolete_accounts(
40 &self,
41 slot: Option<Slot>,
42 ) -> impl Iterator<Item = (Offset, usize)> + '_ {
43 self.accounts
44 .iter()
45 .filter(move |obsolete_account| slot.is_none_or(|s| obsolete_account.slot <= s))
46 .map(|obsolete_account| (obsolete_account.offset, obsolete_account.data_len))
47 }
48
49 pub fn obsolete_accounts_for_snapshots(&self, slot: Slot) -> ObsoleteAccounts {
53 let filtered_accounts = self
54 .accounts
55 .iter()
56 .filter(|account| account.slot <= slot)
57 .cloned()
58 .collect();
59
60 ObsoleteAccounts {
61 accounts: filtered_accounts,
62 }
63 }
64}
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_mark_accounts_obsolete() {
71 let mut obsolete_accounts = ObsoleteAccounts::default();
72 let new_accounts = vec![(10, 100), (20, 200), (30, 300)];
73 let slot: Slot = 42;
74
75 obsolete_accounts.mark_accounts_obsolete(new_accounts.into_iter(), slot);
76
77 let expected_accounts = vec![(10, 100), (20, 200), (30, 300)];
78
79 let actual_accounts: Vec<_> = obsolete_accounts
80 .accounts
81 .iter()
82 .map(|item| (item.offset, item.data_len))
83 .collect();
84
85 assert_eq!(actual_accounts, expected_accounts);
86 }
87
88 #[test]
89 fn test_filter_obsolete_accounts() {
90 let mut obsolete_accounts = ObsoleteAccounts::default();
91 let new_accounts = vec![(10, 100, 40), (20, 200, 42), (30, 300, 44)]
92 .into_iter()
93 .map(|(offset, data_len, slot)| ObsoleteAccountItem {
94 offset,
95 data_len,
96 slot,
97 })
98 .collect::<Vec<_>>();
99
100 new_accounts.into_iter().for_each(|item| {
102 obsolete_accounts
103 .mark_accounts_obsolete([(item.offset, item.data_len)].into_iter(), item.slot)
104 });
105
106 let filtered_accounts: Vec<_> = obsolete_accounts
108 .filter_obsolete_accounts(Some(42))
109 .collect();
110
111 assert_eq!(filtered_accounts, vec![(10, 100), (20, 200)]);
112
113 let filtered_accounts: Vec<_> = obsolete_accounts.filter_obsolete_accounts(None).collect();
115
116 assert_eq!(filtered_accounts, vec![(10, 100), (20, 200), (30, 300)]);
117 }
118
119 #[test]
120 fn test_obsolete_accounts_for_snapshots() {
121 let mut obsolete_accounts = ObsoleteAccounts::default();
122 let new_accounts = vec![(10, 100, 40), (20, 200, 42), (30, 300, 44)]
123 .into_iter()
124 .map(|(offset, data_len, slot)| ObsoleteAccountItem {
125 offset,
126 data_len,
127 slot,
128 })
129 .collect::<Vec<_>>();
130
131 new_accounts.iter().for_each(|item| {
133 obsolete_accounts
134 .mark_accounts_obsolete([(item.offset, item.data_len)].into_iter(), item.slot)
135 });
136
137 let obsolete_accounts_for_snapshots = obsolete_accounts.obsolete_accounts_for_snapshots(42);
139
140 let expected_accounts: Vec<_> = new_accounts
141 .iter()
142 .filter(|account| account.slot <= 42)
143 .cloned()
144 .collect();
145
146 assert_eq!(obsolete_accounts_for_snapshots.accounts, expected_accounts);
147
148 let obsolete_accounts_for_snapshots =
150 obsolete_accounts.obsolete_accounts_for_snapshots(100);
151
152 assert_eq!(obsolete_accounts_for_snapshots.accounts, new_accounts);
153 }
154}