-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Change forks pruning algorithm. #3962
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9decf7b
64094f2
62ab0aa
962b5d3
d325870
7e05f0d
4aeeeb6
27fcc5f
57816e9
6fbc756
af6afe4
75ad220
027739f
cdd7aaf
99b87a3
0ea2dfb
98e47bd
f76be38
e56eed6
c875bd2
bc5290c
7e769f6
95c1d7d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| title: Change fork calculation algorithm. | ||
|
|
||
| doc: | ||
| - audience: Node Dev | ||
| description: | | ||
| This PR changes the fork calculation and pruning algorithm to enable future block header pruning. | ||
| During the finalization of the block we prune known stale forks, so forks are pruned faster. | ||
|
|
||
| crates: | ||
| - name: sc-client-api | ||
| - name: sc-client-db | ||
| - name: sp-blockchain | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,7 +49,7 @@ pub struct FinalizationOutcome<H, N> { | |
| removed: BTreeMap<Reverse<N>, Vec<H>>, | ||
| } | ||
|
|
||
| impl<H, N: Ord> FinalizationOutcome<H, N> { | ||
| impl<H: Copy, N: Ord> FinalizationOutcome<H, N> { | ||
| /// Merge with another. This should only be used for displaced items that | ||
| /// are produced within one transaction of each other. | ||
| pub fn merge(&mut self, mut other: Self) { | ||
|
|
@@ -63,6 +63,16 @@ impl<H, N: Ord> FinalizationOutcome<H, N> { | |
| pub fn leaves(&self) -> impl Iterator<Item = &H> { | ||
| self.removed.values().flatten() | ||
| } | ||
|
|
||
| /// Constructor | ||
| pub fn new(new_displaced: impl Iterator<Item = (H, N)>) -> Self { | ||
| let mut removed = BTreeMap::<Reverse<N>, Vec<H>>::new(); | ||
| for (hash, number) in new_displaced { | ||
| removed.entry(Reverse(number)).or_default().push(hash); | ||
| } | ||
|
|
||
| FinalizationOutcome { removed } | ||
| } | ||
| } | ||
|
|
||
| /// list of leaf hashes ordered by number (descending). | ||
|
|
@@ -151,39 +161,12 @@ where | |
| Some(RemoveOutcome { inserted, removed: LeafSetItem { hash, number } }) | ||
| } | ||
|
|
||
| /// Note a block height finalized, displacing all leaves with number less than the finalized | ||
| /// block's. | ||
| /// | ||
| /// Although it would be more technically correct to also prune out leaves at the | ||
| /// same number as the finalized block, but with different hashes, the current behavior | ||
| /// is simpler and our assumptions about how finalization works means that those leaves | ||
| /// will be pruned soon afterwards anyway. | ||
| pub fn finalize_height(&mut self, number: N) -> FinalizationOutcome<H, N> { | ||
| let boundary = if number == N::zero() { | ||
| return FinalizationOutcome { removed: BTreeMap::new() } | ||
| } else { | ||
| number - N::one() | ||
| }; | ||
|
|
||
| let below_boundary = self.storage.split_off(&Reverse(boundary)); | ||
| FinalizationOutcome { removed: below_boundary } | ||
| } | ||
|
|
||
| /// The same as [`Self::finalize_height`], but it only simulates the operation. | ||
| /// | ||
| /// This means that no changes are done. | ||
| /// | ||
| /// Returns the leaves that would be displaced by finalizing the given block. | ||
| pub fn displaced_by_finalize_height(&self, number: N) -> FinalizationOutcome<H, N> { | ||
| let boundary = if number == N::zero() { | ||
| return FinalizationOutcome { removed: BTreeMap::new() } | ||
| } else { | ||
| number - N::one() | ||
| }; | ||
|
|
||
| let below_boundary = self.storage.range(&Reverse(boundary)..); | ||
| FinalizationOutcome { | ||
| removed: below_boundary.map(|(k, v)| (k.clone(), v.clone())).collect(), | ||
| /// Remove all leaves displaced by the last block finalization. | ||
| pub fn remove_displaced_leaves(&mut self, displaced_leaves: &FinalizationOutcome<H, N>) { | ||
| for (number, hashes) in &displaced_leaves.removed { | ||
| for hash in hashes.iter() { | ||
| self.remove_leaf(number, hash); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -420,32 +403,6 @@ mod tests { | |
| assert!(set.contains(11, 11_2)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn finalization_works() { | ||
| let mut set = LeafSet::new(); | ||
| set.import(9_1u32, 9u32, 0u32); | ||
| set.import(10_1, 10, 9_1); | ||
| set.import(10_2, 10, 9_1); | ||
| set.import(11_1, 11, 10_1); | ||
| set.import(11_2, 11, 10_1); | ||
| set.import(12_1, 12, 11_2); | ||
|
|
||
| let outcome = set.finalize_height(11); | ||
| assert_eq!(set.count(), 2); | ||
| assert!(set.contains(11, 11_1)); | ||
| assert!(set.contains(12, 12_1)); | ||
| assert_eq!( | ||
| outcome.removed, | ||
| [(Reverse(10), vec![10_2])].into_iter().collect::<BTreeMap<_, _>>(), | ||
| ); | ||
|
|
||
| set.undo().undo_finalization(outcome); | ||
| assert_eq!(set.count(), 3); | ||
| assert!(set.contains(11, 11_1)); | ||
| assert!(set.contains(12, 12_1)); | ||
| assert!(set.contains(10, 10_2)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn flush_to_disk() { | ||
| const PREFIX: &[u8] = b"abcdefg"; | ||
|
|
@@ -479,35 +436,4 @@ mod tests { | |
| assert!(set.contains(10, 1_2)); | ||
| assert!(!set.contains(10, 1_3)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn finalization_consistent_with_disk() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you remove this test?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| const PREFIX: &[u8] = b"prefix"; | ||
| let db = Arc::new(sp_database::MemDb::default()); | ||
|
|
||
| let mut set = LeafSet::new(); | ||
| set.import(10_1u32, 10u32, 0u32); | ||
| set.import(11_1, 11, 10_2); | ||
| set.import(11_2, 11, 10_2); | ||
| set.import(12_1, 12, 11_123); | ||
|
|
||
| assert!(set.contains(10, 10_1)); | ||
|
|
||
| let mut tx = Transaction::new(); | ||
| set.prepare_transaction(&mut tx, 0, PREFIX); | ||
| db.commit(tx).unwrap(); | ||
|
|
||
| let _ = set.finalize_height(11); | ||
| let mut tx = Transaction::new(); | ||
| set.prepare_transaction(&mut tx, 0, PREFIX); | ||
| db.commit(tx).unwrap(); | ||
|
|
||
| assert!(set.contains(11, 11_1)); | ||
| assert!(set.contains(11, 11_2)); | ||
| assert!(set.contains(12, 12_1)); | ||
| assert!(!set.contains(10, 10_1)); | ||
|
|
||
| let set2 = LeafSet::read_from_db(&*db, 0, PREFIX).unwrap(); | ||
| assert_eq!(set, set2); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.