66f3c50842
* Revert "fix traces, removed bloomchain crate, closes #7228, closes #7167"
This reverts commit 1bf62038678295e5586f02a38a0c5aab9a9efe62.
* Revert "fixed broken logs (#7934)"
This reverts commit f8a2e53f3e
.
* fixed broken logs
* bring back old lock order
* remove migration v13
* revert CURRENT_VERSION to 12 in migration.rs
159 lines
4.7 KiB
Rust
159 lines
4.7 KiB
Rust
use std::collections::{HashMap, HashSet};
|
|
use std::ops::Range;
|
|
use number::Number;
|
|
use position::{Position, Manager as PositionManager};
|
|
use bloom::Bloom;
|
|
use filter::Filter;
|
|
use config::Config;
|
|
use database::BloomDatabase;
|
|
|
|
/// Prepares all bloom database operations.
|
|
pub struct BloomChain<'a> {
|
|
positioner: PositionManager,
|
|
db: &'a BloomDatabase,
|
|
}
|
|
|
|
impl<'a> BloomChain<'a> {
|
|
/// Creates new bloom chain.
|
|
pub fn new(config: Config, db: &'a BloomDatabase) -> Self {
|
|
let positioner = PositionManager::new(config.elements_per_index, config.levels);
|
|
|
|
BloomChain {
|
|
positioner: positioner,
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
/// Internal function which does bloom search recursively.
|
|
fn blocks(&self, range: &Range<Number>, bloom: &Bloom, level: usize, offset: usize) -> Option<Vec<usize>> {
|
|
let index = self.positioner.position(offset, level);
|
|
|
|
match self.db.bloom_at(&index) {
|
|
None => return None,
|
|
Some(level_bloom) => match level {
|
|
// if we are on the lowest level
|
|
0 if level_bloom.contains_bloom(bloom) => return Some(vec![offset]),
|
|
// return None if current level doesnt contain given bloom
|
|
_ if !level_bloom.contains_bloom(bloom) => return None,
|
|
// continue processing && go down
|
|
_ => ()
|
|
}
|
|
};
|
|
|
|
let level_size = self.positioner.level_size(level - 1);
|
|
let from_position = self.positioner.position(range.start, level - 1);
|
|
let to_position = self.positioner.position(range.end, level - 1);
|
|
let res: Vec<usize> = self.positioner.lower_level_positions(&index).into_iter()
|
|
// chose only blooms in range
|
|
.filter(|li| li.index >= from_position.index && li.index <= to_position.index)
|
|
// map them to offsets
|
|
.map(|li| li.index * level_size)
|
|
// get all blocks that may contain our bloom
|
|
// filter existing ones
|
|
.filter_map(|off| self.blocks(range, bloom, level - 1, off))
|
|
// flatten nested structures
|
|
.flat_map(|v| v)
|
|
.collect();
|
|
Some(res)
|
|
}
|
|
|
|
/// Inserts the bloom at all filter levels.
|
|
pub fn insert(&self, number: Number, bloom: Bloom) -> HashMap<Position, Bloom> {
|
|
let mut result: HashMap<Position, Bloom> = HashMap::new();
|
|
|
|
for level in 0..self.positioner.levels() {
|
|
let position = self.positioner.position(number, level);
|
|
let new_bloom = match self.db.bloom_at(&position) {
|
|
Some(mut old_bloom) => {
|
|
old_bloom.accrue_bloom(&bloom);
|
|
old_bloom
|
|
},
|
|
None => bloom.clone(),
|
|
};
|
|
|
|
result.insert(position, new_bloom);
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
/// Resets data in range.
|
|
/// Inserts new data.
|
|
/// Inserted data may exceed reseted range.
|
|
pub fn replace(&self, range: &Range<Number>, blooms: Vec<Bloom>) -> HashMap<Position, Bloom> {
|
|
let mut result: HashMap<Position, Bloom> = HashMap::new();
|
|
|
|
// insert all new blooms at level 0
|
|
for (i, bloom) in blooms.iter().enumerate() {
|
|
result.insert(self.positioner.position(range.start + i, 0), bloom.clone());
|
|
}
|
|
|
|
// reset the rest of blooms
|
|
for reset_number in range.start + blooms.len()..(range.end + 1) {
|
|
result.insert(self.positioner.position(reset_number, 0), Bloom::default());
|
|
}
|
|
|
|
for level in 1..self.positioner.levels() {
|
|
for i in 0..blooms.len() {
|
|
|
|
let index = self.positioner.position(range.start + i, level);
|
|
let new_bloom = {
|
|
// use new blooms before db blooms where necessary
|
|
let bloom_at = | index | { result.get(&index).cloned().or_else(|| self.db.bloom_at(&index)) };
|
|
|
|
self.positioner.lower_level_positions(&index)
|
|
.into_iter()
|
|
// get blooms
|
|
// filter existing ones
|
|
.filter_map(bloom_at)
|
|
// BitOr all of them
|
|
.fold(Bloom::default(), |mut acc, bloom| {
|
|
acc.accrue_bloom(&bloom);
|
|
acc
|
|
})
|
|
};
|
|
|
|
result.insert(index, new_bloom);
|
|
}
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
/// Returns all numbers with given bloom.
|
|
pub fn with_bloom(&self, range: &Range<Number>, bloom: &Bloom) -> Vec<Number> {
|
|
let mut result = vec![];
|
|
// lets start from highest level
|
|
let max_level = self.positioner.max_level();
|
|
let level_size = self.positioner.level_size(max_level);
|
|
let from_position = self.positioner.position(range.start, max_level);
|
|
let to_position = self.positioner.position(range.end, max_level);
|
|
|
|
for index in from_position.index..to_position.index + 1 {
|
|
// offset will be used to calculate where we are right now
|
|
let offset = level_size * index;
|
|
|
|
// go doooown!
|
|
if let Some(blocks) = self.blocks(range, bloom, max_level, offset) {
|
|
result.extend(blocks);
|
|
}
|
|
}
|
|
|
|
result
|
|
}
|
|
|
|
/// Filter the chain returing all numbers matching the filter.
|
|
pub fn filter(&self, filter: &Filter) -> Vec<Number> {
|
|
let range = filter.range();
|
|
let mut blocks = filter.bloom_possibilities()
|
|
.into_iter()
|
|
.flat_map(|ref bloom| self.with_bloom(&range, bloom))
|
|
.collect::<HashSet<Number>>()
|
|
.into_iter()
|
|
.collect::<Vec<Number>>();
|
|
|
|
blocks.sort();
|
|
blocks
|
|
}
|
|
}
|