Skip to content

Commit 75ef646

Browse files
committed
Optimize pruning during batch finalization of blocks
1 parent 160bdc0 commit 75ef646

File tree

2 files changed

+45
-40
lines changed

2 files changed

+45
-40
lines changed

substrate/client/api/src/backend.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ pub trait BlockImportOperation<Block: BlockT> {
217217
where
218218
I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>;
219219

220-
/// Mark a block as finalized.
220+
/// Mark a block as finalized, if multiple blocks are finalized in the same operation then they
221+
/// must be marked in ascending order.
221222
fn mark_finalized(
222223
&mut self,
223224
hash: Block::Hash,

substrate/client/db/src/lib.rs

+43-39
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,8 @@ impl<Block: BlockT> Backend<Block> {
13691369
Ok(())
13701370
}
13711371

1372+
/// `remove_displaced` can be set to `false` if this is not the last of many subsequent calls
1373+
/// for performance reasons.
13721374
fn finalize_block_with_transaction(
13731375
&self,
13741376
transaction: &mut Transaction<DbHash>,
@@ -1377,6 +1379,7 @@ impl<Block: BlockT> Backend<Block> {
13771379
last_finalized: Option<Block::Hash>,
13781380
justification: Option<Justification>,
13791381
current_transaction_justifications: &mut HashMap<Block::Hash, Justification>,
1382+
remove_displaced: bool,
13801383
) -> ClientResult<MetaUpdate<Block>> {
13811384
// TODO: ensure best chain contains this block.
13821385
let number = *header.number();
@@ -1389,6 +1392,7 @@ impl<Block: BlockT> Backend<Block> {
13891392
hash,
13901393
with_state,
13911394
current_transaction_justifications,
1395+
remove_displaced,
13921396
)?;
13931397

13941398
if let Some(justification) = justification {
@@ -1466,7 +1470,8 @@ impl<Block: BlockT> Backend<Block> {
14661470

14671471
let mut current_transaction_justifications: HashMap<Block::Hash, Justification> =
14681472
HashMap::new();
1469-
for (block_hash, justification) in operation.finalized_blocks {
1473+
let mut finalized_blocks = operation.finalized_blocks.into_iter().peekable();
1474+
while let Some((block_hash, justification)) = finalized_blocks.next() {
14701475
let block_header = self.blockchain.expect_header(block_hash)?;
14711476
meta_updates.push(self.finalize_block_with_transaction(
14721477
&mut transaction,
@@ -1475,6 +1480,7 @@ impl<Block: BlockT> Backend<Block> {
14751480
Some(last_finalized_hash),
14761481
justification,
14771482
&mut current_transaction_justifications,
1483+
finalized_blocks.peek().is_none(),
14781484
)?);
14791485
last_finalized_hash = block_hash;
14801486
last_finalized_num = *block_header.number();
@@ -1654,6 +1660,7 @@ impl<Block: BlockT> Backend<Block> {
16541660
hash,
16551661
operation.commit_state,
16561662
&mut current_transaction_justifications,
1663+
true,
16571664
)?;
16581665
} else {
16591666
// canonicalize blocks which are old enough, regardless of finality.
@@ -1779,16 +1786,18 @@ impl<Block: BlockT> Backend<Block> {
17791786
Ok(())
17801787
}
17811788

1782-
// write stuff to a transaction after a new block is finalized.
1783-
// this canonicalizes finalized blocks. Fails if called with a block which
1784-
// was not a child of the last finalized block.
1789+
// Write stuff to a transaction after a new block is finalized. This canonicalizes finalized
1790+
// blocks. Fails if called with a block which was not a child of the last finalized block.
1791+
/// `remove_displaced` can be set to `false` if this is not the last of many subsequent calls
1792+
/// for performance reasons.
17851793
fn note_finalized(
17861794
&self,
17871795
transaction: &mut Transaction<DbHash>,
17881796
f_header: &Block::Header,
17891797
f_hash: Block::Hash,
17901798
with_state: bool,
17911799
current_transaction_justifications: &mut HashMap<Block::Hash, Justification>,
1800+
remove_displaced: bool,
17921801
) -> ClientResult<()> {
17931802
let f_num = *f_header.number();
17941803

@@ -1813,13 +1822,17 @@ impl<Block: BlockT> Backend<Block> {
18131822
apply_state_commit(transaction, commit);
18141823
}
18151824

1816-
let new_displaced = self.blockchain.displaced_leaves_after_finalizing(f_hash, f_num)?;
1825+
if remove_displaced && !matches!(self.blocks_pruning, BlocksPruning::KeepAll) {
1826+
let new_displaced = self.blockchain.displaced_leaves_after_finalizing(f_hash, f_num)?;
18171827

1818-
self.blockchain.leaves.write().remove_displaced_leaves(FinalizationOutcome::new(
1819-
new_displaced.displaced_leaves.iter().copied(),
1820-
));
1828+
self.blockchain.leaves.write().remove_displaced_leaves(FinalizationOutcome::new(
1829+
new_displaced.displaced_leaves.iter().copied(),
1830+
));
1831+
1832+
self.prune_displaced_branches(transaction, &new_displaced)?;
1833+
}
18211834

1822-
self.prune_blocks(transaction, f_num, &new_displaced, current_transaction_justifications)?;
1835+
self.prune_blocks(transaction, f_num, current_transaction_justifications)?;
18231836

18241837
Ok(())
18251838
}
@@ -1828,39 +1841,29 @@ impl<Block: BlockT> Backend<Block> {
18281841
&self,
18291842
transaction: &mut Transaction<DbHash>,
18301843
finalized_number: NumberFor<Block>,
1831-
displaced: &DisplacedLeavesAfterFinalization<Block>,
18321844
current_transaction_justifications: &mut HashMap<Block::Hash, Justification>,
18331845
) -> ClientResult<()> {
1834-
match self.blocks_pruning {
1835-
BlocksPruning::KeepAll => {},
1836-
BlocksPruning::Some(blocks_pruning) => {
1837-
// Always keep the last finalized block
1838-
let keep = std::cmp::max(blocks_pruning, 1);
1839-
if finalized_number >= keep.into() {
1840-
let number = finalized_number.saturating_sub(keep.into());
1841-
1842-
// Before we prune a block, check if it is pinned
1843-
if let Some(hash) = self.blockchain.hash(number)? {
1844-
self.blockchain.insert_persisted_body_if_pinned(hash)?;
1845-
1846-
// If the block was finalized in this transaction, it will not be in the db
1847-
// yet.
1848-
if let Some(justification) =
1849-
current_transaction_justifications.remove(&hash)
1850-
{
1851-
self.blockchain.insert_justifications_if_pinned(hash, justification);
1852-
} else {
1853-
self.blockchain.insert_persisted_justifications_if_pinned(hash)?;
1854-
}
1855-
};
1846+
if let BlocksPruning::Some(blocks_pruning) = self.blocks_pruning {
1847+
// Always keep the last finalized block
1848+
let keep = std::cmp::max(blocks_pruning, 1);
1849+
if finalized_number >= keep.into() {
1850+
let number = finalized_number.saturating_sub(keep.into());
1851+
1852+
// Before we prune a block, check if it is pinned
1853+
if let Some(hash) = self.blockchain.hash(number)? {
1854+
self.blockchain.insert_persisted_body_if_pinned(hash)?;
1855+
1856+
// If the block was finalized in this transaction, it will not be in the db
1857+
// yet.
1858+
if let Some(justification) = current_transaction_justifications.remove(&hash) {
1859+
self.blockchain.insert_justifications_if_pinned(hash, justification);
1860+
} else {
1861+
self.blockchain.insert_persisted_justifications_if_pinned(hash)?;
1862+
}
1863+
};
18561864

1857-
self.prune_block(transaction, BlockId::<Block>::number(number))?;
1858-
}
1859-
self.prune_displaced_branches(transaction, displaced)?;
1860-
},
1861-
BlocksPruning::KeepFinalized => {
1862-
self.prune_displaced_branches(transaction, displaced)?;
1863-
},
1865+
self.prune_block(transaction, BlockId::<Block>::number(number))?;
1866+
}
18641867
}
18651868
Ok(())
18661869
}
@@ -2121,6 +2124,7 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
21212124
None,
21222125
justification,
21232126
&mut current_transaction_justifications,
2127+
true,
21242128
)?;
21252129

21262130
self.storage.db.commit(transaction)?;

0 commit comments

Comments
 (0)