solana_accounts_db/
ancestors.rs1use {
2 crate::rolling_bit_field::RollingBitField,
3 core::fmt::{Debug, Formatter},
4 solana_clock::Slot,
5 std::collections::HashMap,
6};
7
8pub type AncestorsForSerialization = HashMap<Slot, usize>;
9
10#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
11#[derive(Clone, PartialEq)]
12pub struct Ancestors {
13 ancestors: RollingBitField,
14}
15
16impl Debug for Ancestors {
17 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
18 write!(f, "{:?}", self.keys())
19 }
20}
21
22const ANCESTORS_HASH_MAP_SIZE: u64 = 8192;
25
26impl Default for Ancestors {
27 fn default() -> Self {
28 Self {
29 ancestors: RollingBitField::new(ANCESTORS_HASH_MAP_SIZE),
30 }
31 }
32}
33
34impl From<Vec<Slot>> for Ancestors {
35 fn from(mut source: Vec<Slot>) -> Ancestors {
36 source.sort_unstable();
38 let mut result = Ancestors::default();
39 source.into_iter().for_each(|slot| {
40 result.ancestors.insert(slot);
41 });
42
43 result
44 }
45}
46
47impl From<&HashMap<Slot, usize>> for Ancestors {
48 fn from(source: &HashMap<Slot, usize>) -> Ancestors {
49 let vec = source.iter().map(|(slot, _)| *slot).collect::<Vec<_>>();
50 Ancestors::from(vec)
51 }
52}
53
54impl From<&Ancestors> for HashMap<Slot, usize> {
55 fn from(source: &Ancestors) -> HashMap<Slot, usize> {
56 let mut result = HashMap::with_capacity(source.len());
57 source.keys().iter().for_each(|slot| {
58 result.insert(*slot, 0);
59 });
60 result
61 }
62}
63
64impl Ancestors {
65 pub fn keys(&self) -> Vec<Slot> {
66 self.ancestors.get_all()
67 }
68
69 pub fn remove(&mut self, slot: &Slot) {
70 self.ancestors.remove(slot);
71 }
72
73 pub fn contains_key(&self, slot: &Slot) -> bool {
74 self.ancestors.contains(slot)
75 }
76
77 pub fn len(&self) -> usize {
78 self.ancestors.len()
79 }
80
81 pub fn is_empty(&self) -> bool {
82 self.len() == 0
83 }
84
85 pub fn min_slot(&self) -> Slot {
86 self.ancestors.min().unwrap_or_default()
87 }
88
89 pub fn max_slot(&self) -> Slot {
90 self.ancestors.max_exclusive().saturating_sub(1)
91 }
92}
93
94#[cfg(feature = "dev-context-only-utils")]
96impl std::iter::FromIterator<(Slot, usize)> for Ancestors {
97 fn from_iter<I>(iter: I) -> Self
98 where
99 I: IntoIterator<Item = (Slot, usize)>,
100 {
101 let mut data = Vec::new();
102 for i in iter {
103 data.push(i);
104 }
105 Ancestors::from(data)
106 }
107}
108
109#[cfg(feature = "dev-context-only-utils")]
110impl From<Vec<(Slot, usize)>> for Ancestors {
111 fn from(source: Vec<(Slot, usize)>) -> Ancestors {
112 Ancestors::from(source.into_iter().map(|(slot, _)| slot).collect::<Vec<_>>())
113 }
114}
115
116#[cfg(feature = "dev-context-only-utils")]
117impl Ancestors {
118 pub fn insert(&mut self, slot: Slot, _size: usize) {
119 self.ancestors.insert(slot);
120 }
121}
122
123#[cfg(test)]
124pub mod tests {
125 use {
126 super::*, crate::contains::Contains, log::*, solana_measure::measure::Measure,
127 std::collections::HashSet,
128 };
129
130 #[test]
131 fn test_ancestors_permutations() {
132 solana_logger::setup();
133 let mut ancestors = Ancestors::default();
134 let mut hash = HashMap::new();
135
136 let min = 101_000;
137 let width = 400_000;
138 let dead = 19;
139
140 let mut slot = min;
141 while hash.len() < width {
142 slot += 1;
143 if slot % dead == 0 {
144 continue;
145 }
146 hash.insert(slot, 0);
147 ancestors.insert(slot, 0);
148 }
149 compare_ancestors(&hash, &ancestors);
150
151 let max = slot + 1;
152
153 let mut time = Measure::start("");
154 let mut count = 0;
155 for slot in (min - 10)..max + 100 {
156 if hash.contains(&slot) {
157 count += 1;
158 }
159 }
160 time.stop();
161
162 let mut time2 = Measure::start("");
163 let mut count2 = 0;
164 for slot in (min - 10)..max + 100 {
165 if ancestors.contains_key(&slot) {
166 count2 += 1;
167 }
168 }
169 time2.stop();
170 info!(
171 "{}ms, {}ms, {} ratio",
172 time.as_ms(),
173 time2.as_ms(),
174 time.as_ns() / time2.as_ns()
175 );
176 assert_eq!(count, count2);
177 }
178
179 fn compare_ancestors(hashset: &HashMap<u64, usize>, ancestors: &Ancestors) {
180 assert_eq!(hashset.len(), ancestors.len());
181 assert_eq!(hashset.is_empty(), ancestors.is_empty());
182 let mut min = u64::MAX;
183 let mut max = 0;
184 for item in hashset.iter() {
185 let key = item.0;
186 min = std::cmp::min(min, *key);
187 max = std::cmp::max(max, *key);
188 assert!(ancestors.contains_key(key));
189 }
190 for slot in min - 1..max + 2 {
191 assert_eq!(ancestors.contains_key(&slot), hashset.contains(&slot));
192 }
193 }
194
195 #[test]
196 fn test_ancestors_smaller() {
197 solana_logger::setup();
198
199 for width in 0..34 {
200 let mut hash = HashSet::new();
201
202 let min = 1_010_000;
203 let dead = 19;
204
205 let mut slot = min;
206 let mut slots = Vec::new();
207 while hash.len() < width {
208 slot += 1;
209 if slot % dead == 0 {
210 continue;
211 }
212 hash.insert(slot);
213 slots.push((slot, 0));
214 }
215 let ancestors = Ancestors::from(slots);
216
217 let max = slot + 1;
218 let passes = 1;
219 let mut time = Measure::start("");
220 let mut count = 0;
221 for _pass in 0..passes {
222 for slot in (min - 10)..max + 100 {
223 if hash.contains(&slot) {
224 count += 1;
225 }
226 }
227 }
228 time.stop();
229
230 let mut time2 = Measure::start("");
231 let mut count2 = 0;
232 for _pass in 0..passes {
233 for slot in (min - 10)..max + 100 {
234 if ancestors.contains_key(&slot) {
235 count2 += 1;
236 }
237 }
238 }
239 time2.stop();
240 info!(
241 "{}, {}, {}",
242 time.as_ms(),
243 time2.as_ms(),
244 time.as_ns() / time2.as_ns()
245 );
246 assert_eq!(count, count2);
247 }
248 }
249}