solana_accounts_db/
ancestors.rs

1use {
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
22// some tests produce ancestors ranges that are too large such
23// that we prefer to implement them in a sparse HashMap
24const 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        // bitfield performs optimally when we insert the minimum value first so that it knows the correct start/end values
37        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// These functions/fields are only usable from a dev context (i.e. tests and benches)
95#[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}