Add range lookups for erasure set indexes (#5612)

This commit is contained in:
Pankaj Garg 2019-08-22 16:32:38 -07:00 committed by GitHub
parent 1207664bbb
commit aeaa0feb61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 94 additions and 2 deletions

View File

@ -1,6 +1,7 @@
use crate::erasure::ErasureConfig;
use solana_metrics::datapoint;
use std::{collections::BTreeSet, ops::RangeBounds};
use std::cmp::Ordering;
use std::{collections::BTreeSet, ops::Range, ops::RangeBounds};
#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
// The Meta column family
@ -27,6 +28,51 @@ pub struct SlotMeta {
pub is_connected: bool,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)]
pub struct ErasureSetRanges {
r: Vec<Range<u64>>,
}
impl ErasureSetRanges {
pub fn insert(&mut self, start: u64, end: u64) -> Result<usize, Range<u64>> {
let range = if start < end {
(start..end)
} else {
(end..start)
};
match self.pos(range.start) {
Ok(pos) => Err(self.r[pos].clone()),
Err(pos) => {
self.r.insert(pos, range);
Ok(pos)
}
}
}
fn pos(&self, seek: u64) -> Result<usize, usize> {
self.r.binary_search_by(|probe| {
if probe.contains(&seek) {
Ordering::Equal
} else {
probe.start.cmp(&seek)
}
})
}
pub fn lookup(&self, seek: u64) -> Result<Range<u64>, usize> {
self.pos(seek)
.map(|pos| self.r[pos].clone())
.or_else(|epos| {
if epos < self.r.len() && self.r[epos].contains(&seek) {
Ok(self.r[epos].clone())
} else {
Err(epos)
}
})
}
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)]
/// Index recording presence/absence of blobs
pub struct Index {
@ -56,7 +102,7 @@ pub struct ErasureMeta {
/// Size of shards in this erasure set
pub size: usize,
/// Erasure configuration for this erasure set
config: ErasureConfig,
pub config: ErasureConfig,
}
#[derive(Debug, PartialEq)]
@ -300,4 +346,50 @@ mod test {
assert_eq!(e_meta.status(&index), DataFull);
}
}
#[test]
fn test_erasure_set_ranges() {
let mut ranges = ErasureSetRanges::default();
// Test empty ranges
(0..100 as u64).for_each(|i| {
assert_eq!(ranges.lookup(i), Err(0));
});
// Test adding one range and all boundary condition lookups
assert_eq!(ranges.insert(5, 13), Ok(0));
assert_eq!(ranges.lookup(0), Err(0));
assert_eq!(ranges.lookup(4), Err(0));
assert_eq!(ranges.lookup(5), Ok(5..13));
assert_eq!(ranges.lookup(12), Ok(5..13));
assert_eq!(ranges.lookup(13), Err(1));
assert_eq!(ranges.lookup(100), Err(1));
// Test adding second range (with backwards values) and all boundary condition lookups
assert_eq!(ranges.insert(55, 33), Ok(1));
assert_eq!(ranges.lookup(0), Err(0));
assert_eq!(ranges.lookup(4), Err(0));
assert_eq!(ranges.lookup(5), Ok(5..13));
assert_eq!(ranges.lookup(12), Ok(5..13));
assert_eq!(ranges.lookup(13), Err(1));
assert_eq!(ranges.lookup(32), Err(1));
assert_eq!(ranges.lookup(33), Ok(33..55));
assert_eq!(ranges.lookup(54), Ok(33..55));
assert_eq!(ranges.lookup(55), Err(2));
// Add a third range between previous two ranges
assert_eq!(ranges.insert(23, 30), Ok(1));
assert_eq!(ranges.lookup(0), Err(0));
assert_eq!(ranges.lookup(4), Err(0));
assert_eq!(ranges.lookup(5), Ok(5..13));
assert_eq!(ranges.lookup(12), Ok(5..13));
assert_eq!(ranges.lookup(13), Err(1));
assert_eq!(ranges.lookup(23), Ok(23..30));
assert_eq!(ranges.lookup(29), Ok(23..30));
assert_eq!(ranges.lookup(30), Err(2));
assert_eq!(ranges.lookup(32), Err(2));
assert_eq!(ranges.lookup(33), Ok(33..55));
assert_eq!(ranges.lookup(54), Ok(33..55));
assert_eq!(ranges.lookup(55), Err(3));
}
}