2021-12-09 16:36:13 -08:00
|
|
|
use {
|
2022-03-25 08:37:00 -07:00
|
|
|
crate::rolling_bit_field::RollingBitField,
|
2021-12-09 16:36:13 -08:00
|
|
|
core::fmt::{Debug, Formatter},
|
|
|
|
solana_sdk::clock::Slot,
|
|
|
|
std::collections::HashMap,
|
|
|
|
};
|
2021-05-19 09:50:34 -07:00
|
|
|
|
2021-05-20 08:11:56 -07:00
|
|
|
pub type AncestorsForSerialization = HashMap<Slot, usize>;
|
|
|
|
|
2021-12-09 16:36:13 -08:00
|
|
|
#[derive(Clone, PartialEq, AbiExample)]
|
2021-05-20 08:11:56 -07:00
|
|
|
pub struct Ancestors {
|
2021-06-02 07:32:32 -07:00
|
|
|
ancestors: RollingBitField,
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
|
2021-12-09 16:36:13 -08:00
|
|
|
impl Debug for Ancestors {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
|
|
|
write!(f, "{:?}", self.keys())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-20 08:11:56 -07:00
|
|
|
// some tests produce ancestors ranges that are too large such
|
|
|
|
// that we prefer to implement them in a sparse HashMap
|
2021-06-02 07:32:32 -07:00
|
|
|
const ANCESTORS_HASH_MAP_SIZE: u64 = 8192;
|
|
|
|
|
|
|
|
impl Default for Ancestors {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
ancestors: RollingBitField::new(ANCESTORS_HASH_MAP_SIZE),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-20 08:11:56 -07:00
|
|
|
|
2021-05-25 09:01:11 -07:00
|
|
|
impl From<Vec<Slot>> for Ancestors {
|
2021-06-02 07:32:32 -07:00
|
|
|
fn from(mut source: Vec<Slot>) -> Ancestors {
|
|
|
|
// bitfield performs optimally when we insert the minimum value first so that it knows the correct start/end values
|
|
|
|
source.sort_unstable();
|
2021-05-20 08:11:56 -07:00
|
|
|
let mut result = Ancestors::default();
|
2021-06-02 07:32:32 -07:00
|
|
|
source.into_iter().for_each(|slot| {
|
|
|
|
result.ancestors.insert(slot);
|
|
|
|
});
|
2021-05-20 08:11:56 -07:00
|
|
|
|
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&HashMap<Slot, usize>> for Ancestors {
|
|
|
|
fn from(source: &HashMap<Slot, usize>) -> Ancestors {
|
2021-06-02 07:32:32 -07:00
|
|
|
let vec = source.iter().map(|(slot, _)| *slot).collect::<Vec<_>>();
|
|
|
|
Ancestors::from(vec)
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<&Ancestors> for HashMap<Slot, usize> {
|
|
|
|
fn from(source: &Ancestors) -> HashMap<Slot, usize> {
|
|
|
|
let mut result = HashMap::with_capacity(source.len());
|
|
|
|
source.keys().iter().for_each(|slot| {
|
2021-05-24 15:01:02 -07:00
|
|
|
result.insert(*slot, 0);
|
2021-05-20 08:11:56 -07:00
|
|
|
});
|
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ancestors {
|
|
|
|
pub fn keys(&self) -> Vec<Slot> {
|
2021-06-02 07:32:32 -07:00
|
|
|
self.ancestors.get_all()
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove(&mut self, slot: &Slot) {
|
2021-06-02 07:32:32 -07:00
|
|
|
self.ancestors.remove(slot);
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn contains_key(&self, slot: &Slot) -> bool {
|
2021-06-02 07:32:32 -07:00
|
|
|
self.ancestors.contains(slot)
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
2021-06-02 07:32:32 -07:00
|
|
|
self.ancestors.len()
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.len() == 0
|
|
|
|
}
|
2021-06-14 21:04:01 -07:00
|
|
|
|
2022-03-30 06:52:45 -07:00
|
|
|
pub fn min_slot(&self) -> Slot {
|
|
|
|
self.ancestors.min().unwrap_or_default()
|
|
|
|
}
|
|
|
|
|
2021-06-14 21:04:01 -07:00
|
|
|
pub fn max_slot(&self) -> Slot {
|
2022-02-07 11:40:31 -08:00
|
|
|
self.ancestors.max_exclusive().saturating_sub(1)
|
2021-06-14 21:04:01 -07:00
|
|
|
}
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
#[cfg(test)]
|
|
|
|
pub mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*, crate::contains::Contains, log::*, solana_measure::measure::Measure,
|
|
|
|
std::collections::HashSet,
|
|
|
|
};
|
2021-05-20 08:11:56 -07:00
|
|
|
|
|
|
|
impl std::iter::FromIterator<(Slot, usize)> for Ancestors {
|
|
|
|
fn from_iter<I>(iter: I) -> Self
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item = (Slot, usize)>,
|
|
|
|
{
|
|
|
|
let mut data = Vec::new();
|
|
|
|
for i in iter {
|
|
|
|
data.push(i);
|
|
|
|
}
|
|
|
|
Ancestors::from(data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-25 09:01:11 -07:00
|
|
|
impl From<Vec<(Slot, usize)>> for Ancestors {
|
|
|
|
fn from(source: Vec<(Slot, usize)>) -> Ancestors {
|
|
|
|
Ancestors::from(source.into_iter().map(|(slot, _)| slot).collect::<Vec<_>>())
|
|
|
|
}
|
|
|
|
}
|
2021-05-20 08:11:56 -07:00
|
|
|
impl Ancestors {
|
2021-06-02 07:32:32 -07:00
|
|
|
pub fn insert(&mut self, slot: Slot, _size: usize) {
|
|
|
|
self.ancestors.insert(slot);
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ancestors_permutations() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let mut ancestors = Ancestors::default();
|
|
|
|
let mut hash = HashMap::new();
|
|
|
|
|
|
|
|
let min = 101_000;
|
|
|
|
let width = 400_000;
|
|
|
|
let dead = 19;
|
|
|
|
|
|
|
|
let mut slot = min;
|
|
|
|
while hash.len() < width {
|
|
|
|
slot += 1;
|
|
|
|
if slot % dead == 0 {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
hash.insert(slot, 0);
|
|
|
|
ancestors.insert(slot, 0);
|
|
|
|
}
|
|
|
|
compare_ancestors(&hash, &ancestors);
|
|
|
|
|
|
|
|
let max = slot + 1;
|
|
|
|
|
|
|
|
let mut time = Measure::start("");
|
|
|
|
let mut count = 0;
|
|
|
|
for slot in (min - 10)..max + 100 {
|
|
|
|
if hash.contains(&slot) {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
time.stop();
|
|
|
|
|
|
|
|
let mut time2 = Measure::start("");
|
|
|
|
let mut count2 = 0;
|
|
|
|
for slot in (min - 10)..max + 100 {
|
|
|
|
if ancestors.contains_key(&slot) {
|
|
|
|
count2 += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
time2.stop();
|
|
|
|
info!(
|
|
|
|
"{}ms, {}ms, {} ratio",
|
|
|
|
time.as_ms(),
|
|
|
|
time2.as_ms(),
|
|
|
|
time.as_ns() / time2.as_ns()
|
|
|
|
);
|
|
|
|
assert_eq!(count, count2);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn compare_ancestors(hashset: &HashMap<u64, usize>, ancestors: &Ancestors) {
|
|
|
|
assert_eq!(hashset.len(), ancestors.len());
|
|
|
|
assert_eq!(hashset.is_empty(), ancestors.is_empty());
|
|
|
|
let mut min = u64::MAX;
|
|
|
|
let mut max = 0;
|
|
|
|
for item in hashset.iter() {
|
|
|
|
let key = item.0;
|
|
|
|
min = std::cmp::min(min, *key);
|
|
|
|
max = std::cmp::max(max, *key);
|
2022-08-16 10:06:52 -07:00
|
|
|
assert!(ancestors.contains_key(key));
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
for slot in min - 1..max + 2 {
|
2022-08-16 10:06:52 -07:00
|
|
|
assert_eq!(ancestors.contains_key(&slot), hashset.contains(&slot));
|
2021-05-20 08:11:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ancestors_smaller() {
|
|
|
|
solana_logger::setup();
|
|
|
|
|
|
|
|
for width in 0..34 {
|
|
|
|
let mut hash = HashSet::new();
|
|
|
|
|
|
|
|
let min = 1_010_000;
|
|
|
|
let dead = 19;
|
|
|
|
|
|
|
|
let mut slot = min;
|
|
|
|
let mut slots = Vec::new();
|
|
|
|
while hash.len() < width {
|
|
|
|
slot += 1;
|
|
|
|
if slot % dead == 0 {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
hash.insert(slot);
|
|
|
|
slots.push((slot, 0));
|
|
|
|
}
|
|
|
|
let ancestors = Ancestors::from(slots);
|
|
|
|
|
|
|
|
let max = slot + 1;
|
|
|
|
let passes = 1;
|
|
|
|
let mut time = Measure::start("");
|
|
|
|
let mut count = 0;
|
|
|
|
for _pass in 0..passes {
|
|
|
|
for slot in (min - 10)..max + 100 {
|
|
|
|
if hash.contains(&slot) {
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
time.stop();
|
|
|
|
|
|
|
|
let mut time2 = Measure::start("");
|
|
|
|
let mut count2 = 0;
|
|
|
|
for _pass in 0..passes {
|
|
|
|
for slot in (min - 10)..max + 100 {
|
|
|
|
if ancestors.contains_key(&slot) {
|
|
|
|
count2 += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
time2.stop();
|
|
|
|
info!(
|
|
|
|
"{}, {}, {}",
|
|
|
|
time.as_ms(),
|
|
|
|
time2.as_ms(),
|
|
|
|
time.as_ns() / time2.as_ns()
|
|
|
|
);
|
|
|
|
assert_eq!(count, count2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|