Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Limit number of blocks per level (2nd attempt) #1559

Merged
merged 68 commits into from
Dec 20, 2022
Merged
Changes from 1 commit
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
b1db89b
Temporary hack to fetch leaves from parachain block import
davxy Jul 28, 2022
c211faa
Merge branch 'master' into davxy/remove-leaves
davxy Aug 1, 2022
e9bd438
Working temporary PoC implementation
davxy Aug 1, 2022
8aaf2e8
Merge branch 'master' into davxy/remove-leaves
davxy Aug 10, 2022
e0a7da1
TEMPORARY COMMIT
davxy Aug 10, 2022
48367c6
Test excercising leaves pruning feature
davxy Aug 11, 2022
0613b3b
Removed global backend hack and introduced configurable leaves level …
davxy Aug 12, 2022
0ddaedc
Cleanup
davxy Aug 12, 2022
e811887
Nitpicks
davxy Aug 12, 2022
be75d7b
Removed debug logs
davxy Aug 12, 2022
bd8852b
Adjust leaves per level default value to be equal to the substrate ba…
davxy Aug 12, 2022
5b299dd
Better docs
davxy Aug 12, 2022
6e3cef9
Don't rely on the backend implementation order for the leaves
davxy Aug 19, 2022
7437611
Merge branch 'master' into davxy/remove-leaves-portable
davxy Aug 19, 2022
7453fe0
Leaves monitoring code encapsulation
davxy Aug 19, 2022
45fc0d1
Fix panic for unsigned subtraction underflow
davxy Aug 19, 2022
12427d5
Cargo fmt
davxy Aug 19, 2022
b2c197f
Improval leaves cache insertion/deletion strategy
davxy Aug 21, 2022
0c81d6b
Apply suggestions from code review
davxy Aug 22, 2022
aabc69a
Fix to default level limit
davxy Aug 22, 2022
55e598e
Remove redundant type
davxy Aug 23, 2022
d939757
Allow removal of non-leaves blocks and restore from backend
davxy Aug 30, 2022
ca4b383
Encapsulate limit monitor in its own module
davxy Aug 30, 2022
9c13d60
Proper cleanup for descendants
davxy Aug 31, 2022
765b59a
Apply suggestions from code review
davxy Sep 1, 2022
ffeeb22
Optimization
davxy Sep 1, 2022
7e6ed47
Fix
davxy Sep 1, 2022
5dbfe14
Fix typo
davxy Sep 1, 2022
2d9242c
Nit. Rename some fresher to freshest
davxy Sep 1, 2022
eff06c5
Dedicated ParachainBlockImport constructor with explicit LevelLimit
davxy Sep 8, 2022
7a8d663
Apply suggestions from code review
davxy Sep 14, 2022
4f15278
Fmt
davxy Sep 14, 2022
cc60027
Fix typo
davxy Sep 14, 2022
48e0cc9
Apply suggestions from code review
davxy Sep 14, 2022
7b51bb0
Use block number instead of u64 for import counter
davxy Sep 14, 2022
a9d0b1e
Separate target find and removal logic
davxy Sep 14, 2022
27e8f04
Code adjustments
davxy Sep 14, 2022
b675d48
Refactory to reduce cognitive complexity
davxy Sep 15, 2022
5b5f1d0
Merge branch 'master' into davxy/remove-leaves-portable
davxy Sep 15, 2022
1029cff
Apply suggestions from code review
davxy Sep 28, 2022
1bc4e61
Fix type
davxy Sep 28, 2022
d8f1c84
Restore monitor within the constructor
davxy Sep 28, 2022
9766f86
Rename Monitor 'update' to 'block_imported'
davxy Sep 28, 2022
19695b4
Keep track of invalidated leaves
davxy Oct 1, 2022
77e2549
Check import before add block to the monitor
davxy Oct 1, 2022
8ecb772
Update test
davxy Oct 1, 2022
3d86b2e
Adjust log levels
davxy Oct 1, 2022
59fcb7a
[ci] Apply cargo-fmt
Oct 1, 2022
283d33b
Extra debugging logs
davxy Oct 5, 2022
fd939e9
Added target to debug logs
davxy Oct 5, 2022
bbde030
Report errors as such
davxy Oct 7, 2022
7dd4ebe
Added extra log to the monitor restore method
davxy Oct 13, 2022
c89b2c2
Merge branch 'master' into davxy/remove-leaves-portable
davxy Oct 13, 2022
f08c6e4
Fix after master merge
davxy Oct 13, 2022
3cd5d31
Bugfix: level monitor cache should use block 'post-hash'
davxy Oct 13, 2022
f0c18c1
TEMPORARY
davxy Oct 18, 2022
d945832
Merge branch 'master' into davxy/remove-leaves-portable
davxy Oct 21, 2022
01c37b7
Minor tweaks
davxy Oct 21, 2022
70c7c7e
Merge branch 'master' into davxy/remove-leaves-portable
davxy Nov 10, 2022
61304ec
Small code refactory
davxy Nov 11, 2022
e92d651
Invalidate leaf only on removal
davxy Nov 11, 2022
bc1643d
Removed temporary logs
davxy Nov 16, 2022
408580e
Explicit recovery for announced candidate blocks (#1891)
davxy Dec 9, 2022
f396157
Merge branch 'master' into davxy/remove-leaves-portable
davxy Dec 9, 2022
92bb6ac
Fix after master merge
davxy Dec 9, 2022
819ade6
Merge branch 'master' into davxy/remove-leaves-portable
davxy Dec 20, 2022
8886f67
Moved block recovery related types in pov-recovery crate
davxy Dec 20, 2022
0eff586
Fix after refactory
davxy Dec 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Improval leaves cache insertion/deletion strategy
  • Loading branch information
davxy committed Aug 21, 2022
commit b2c197fa40eda547c3f42bd1cf9bd2d1ace45d68
46 changes: 30 additions & 16 deletions client/consensus/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,33 +108,37 @@ type BlockHash<Block> = <<Block as BlockT>::Header as HeaderT>::Hash;
struct LeavesLevelMonitor<Block: BlockT, BE> {
// Max number of leaves for each level.
level_limit: usize,
// Monotonic counter used to keep track of block age (bigger is younger).
// Monotonic counter used to keep track of block import age (bigger is younger).
import_counter: u64,
// Map between block hash and age.
import_map: HashMap<BlockHash<Block>, u64>,
leaves_cache: HashMap<BlockHash<Block>, u64>,
davxy marked this conversation as resolved.
Show resolved Hide resolved
// Backend reference to remove leaves on level saturation.
backend: Arc<BE>,
}

// Threshold after which we are going to cleanup our internal map by removing hashes that
// doesn't belong to leaves anymore.
// Threshold after which we are going to cleanup our internal leaves cache by removing hashes that
// doesn't belong to leaf blocks anymore.
// This is a farly arbitrary value that can be changed in the future without breaking anything.
const CLEANUP_THRESHOLD: usize = 64;

impl<Block: BlockT, BE: Backend<Block>> LeavesLevelMonitor<Block, BE> {
fn update(&mut self, hash: BlockHash<Block>, number: NumberFor<Block>) {
fn update(&mut self, hash: BlockHash<Block>, parent_hash: BlockHash<Block>) {
self.import_counter += 1;
self.leaves_cache.insert(hash, self.import_counter);
self.leaves_cache.remove(&parent_hash);
}

fn check(&mut self, number: NumberFor<Block>) {
davxy marked this conversation as resolved.
Show resolved Hide resolved
let blockchain = self.backend.blockchain();
let mut leaves = blockchain.leaves().unwrap_or_default();

if self.import_map.len().saturating_sub(leaves.len()) >= CLEANUP_THRESHOLD {
// Using a temporary HashSet we allegedly reduce iterations from O(n^2) to O(2n)
if self.leaves_cache.len().saturating_sub(leaves.len()) >= CLEANUP_THRESHOLD {
// Update the cache once in a while by using the leaves set returned by the backend.
// Using a temporary HashSet we reduce iterations from O(n^2) to O(2n)
let leaves_set: HashSet<_> = leaves.iter().collect();
self.import_map.retain(|hash, _| leaves_set.contains(hash));
self.leaves_cache.retain(|hash, _| leaves_set.contains(hash));
}

self.import_counter += 1;
self.import_map.insert(hash, self.import_counter);

// First cheap check: the number of leaves at level `number` is always less than the total.
if leaves.len() < self.level_limit {
return
Expand All @@ -158,14 +162,15 @@ impl<Block: BlockT, BE: Backend<Block>> LeavesLevelMonitor<Block, BE> {
let mut remove_count = leaves.len() - self.level_limit + 1;

// Sort leaves by import chronological order
leaves.sort_unstable_by(|a, b| self.import_map.get(a).cmp(&self.import_map.get(b)));
leaves.sort_unstable_by(|a, b| self.leaves_cache.get(a).cmp(&self.leaves_cache.get(b)));

for hash in leaves.into_iter().filter(|hash| *hash != best) {
log::debug!(target: "parachain", "Removing block {}", hash);
if self.backend.remove_leaf_block(&hash).is_err() {
log::warn!(target: "parachain", "Unable to remove block {}, skipping it...", hash);
continue
}
self.leaves_cache.remove(&hash);
remove_count -= 1;
if remove_count == 0 {
break
Expand Down Expand Up @@ -194,7 +199,7 @@ impl<Block: BlockT, BI, BE> ParachainBlockImport<Block, BI, BE> {
};
let leaves_monitor = level_limit.map(|limit| LeavesLevelMonitor {
level_limit: limit,
import_map: HashMap::new(),
leaves_cache: HashMap::new(),
import_counter: 0,
backend,
});
Expand Down Expand Up @@ -224,8 +229,11 @@ where
mut params: sc_consensus::BlockImportParams<Block, Self::Transaction>,
cache: std::collections::HashMap<sp_consensus::CacheKeyId, Vec<u8>>,
) -> Result<sc_consensus::ImportResult, Self::Error> {
if let Some(ref mut leaves_monitor) = self.leaves_monitor {
leaves_monitor.update(params.header.hash(), *params.header.number());
let hash = params.header.hash();
let parent = *params.header.parent_hash();

if let Some(ref mut monitor) = self.leaves_monitor {
monitor.check(*params.header.number());
}

// Best block is determined by the relay chain, or if we are doing the initial sync
Expand All @@ -234,6 +242,12 @@ where
params.origin == sp_consensus::BlockOrigin::NetworkInitialSync,
));

self.inner.import_block(params, cache).await
let res = self.inner.import_block(params, cache).await?;

if let Some(ref mut monitor) = self.leaves_monitor {
monitor.update(hash, parent);
}

Ok(res)
}
}