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

Commit 59b5903

Browse files
authored
Fix state-db pinning (#12927)
* Pin all canonicalized blocks * Added a test * Docs
1 parent b65c9f0 commit 59b5903

File tree

3 files changed

+58
-18
lines changed

3 files changed

+58
-18
lines changed

client/db/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2002,6 +2002,7 @@ impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
20022002
.map_err(sp_blockchain::Error::from_state_db)?;
20032003
Err(e)
20042004
} else {
2005+
self.storage.state_db.sync();
20052006
Ok(())
20062007
}
20072008
}

client/state-db/src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@ impl<BlockHash: Hash, Key: Hash, D: MetaDb> StateDbSync<BlockHash, Key, D> {
470470
}
471471
}
472472

473+
fn sync(&mut self) {
474+
self.non_canonical.sync();
475+
}
476+
473477
pub fn get<DB: NodeDb, Q: ?Sized>(
474478
&self,
475479
key: &Q,
@@ -573,6 +577,12 @@ impl<BlockHash: Hash, Key: Hash, D: MetaDb> StateDb<BlockHash, Key, D> {
573577
self.db.write().unpin(hash)
574578
}
575579

580+
/// Confirm that all changes made to commit sets are on disk. Allows for temporarily pinned
581+
/// blocks to be released.
582+
pub fn sync(&self) {
583+
self.db.write().sync()
584+
}
585+
576586
/// Get a value from non-canonical/pruning overlay or the backing DB.
577587
pub fn get<DB: NodeDb, Q: ?Sized>(
578588
&self,

client/state-db/src/noncanonical.rs

+47-18
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub struct NonCanonicalOverlay<BlockHash: Hash, Key: Hash> {
3838
// would be deleted but kept around because block is pinned, ref counted.
3939
pinned: HashMap<BlockHash, u32>,
4040
pinned_insertions: HashMap<BlockHash, (Vec<Key>, u32)>,
41-
last_canon_pinned: Option<BlockHash>,
41+
pinned_canonincalized: Vec<BlockHash>,
4242
}
4343

4444
#[cfg_attr(test, derive(PartialEq, Debug))]
@@ -226,7 +226,7 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
226226
pinned: Default::default(),
227227
pinned_insertions: Default::default(),
228228
values,
229-
last_canon_pinned: None,
229+
pinned_canonincalized: Default::default(),
230230
})
231231
}
232232

@@ -350,6 +350,18 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
350350
self.last_canonicalized.as_ref().map(|&(_, n)| n)
351351
}
352352

353+
/// Confirm that all changes made to commit sets are on disk. Allows for temporarily pinned
354+
/// blocks to be released.
355+
pub fn sync(&mut self) {
356+
let mut pinned = std::mem::take(&mut self.pinned_canonincalized);
357+
for hash in pinned.iter() {
358+
self.unpin(hash)
359+
}
360+
pinned.clear();
361+
// Reuse the same memory buffer
362+
self.pinned_canonincalized = pinned;
363+
}
364+
353365
/// Select a top-level root and canonicalized it. Discards all sibling subtrees and the root.
354366
/// Add a set of changes of the canonicalized block to `CommitSet`
355367
/// Return the block number of the canonicalized block
@@ -371,13 +383,9 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
371383

372384
// No failures are possible beyond this point.
373385

374-
// Unpin previously canonicalized block
375-
if let Some(prev_hash) = self.last_canon_pinned.take() {
376-
self.unpin(&prev_hash);
377-
}
378386
// Force pin canonicalized block so that it is no discarded immediately
379387
self.pin(hash);
380-
self.last_canon_pinned = Some(hash.clone());
388+
self.pinned_canonincalized.push(hash.clone());
381389

382390
let mut discarded_journals = Vec::new();
383391
let mut discarded_blocks = Vec::new();
@@ -720,16 +728,17 @@ mod tests {
720728
let mut commit = CommitSet::default();
721729
overlay.canonicalize(&h1, &mut commit).unwrap();
722730
db.commit(&commit);
723-
assert!(contains(&overlay, 5));
731+
overlay.sync();
732+
assert!(!contains(&overlay, 5));
724733
assert!(contains(&overlay, 7));
725734
assert_eq!(overlay.levels.len(), 1);
726-
assert_eq!(overlay.parents.len(), 2);
735+
assert_eq!(overlay.parents.len(), 1);
727736
let mut commit = CommitSet::default();
728737
overlay.canonicalize(&h2, &mut commit).unwrap();
729-
assert!(!contains(&overlay, 5));
730738
db.commit(&commit);
739+
overlay.sync();
731740
assert_eq!(overlay.levels.len(), 0);
732-
assert_eq!(overlay.parents.len(), 1);
741+
assert_eq!(overlay.parents.len(), 0);
733742
assert!(db.data_eq(&make_db(&[1, 4, 6, 7, 8])));
734743
}
735744

@@ -746,8 +755,7 @@ mod tests {
746755
let mut commit = CommitSet::default();
747756
overlay.canonicalize(&h_1, &mut commit).unwrap();
748757
db.commit(&commit);
749-
// explicitly unpin last block
750-
overlay.unpin(&h_1);
758+
overlay.sync();
751759
assert!(!contains(&overlay, 1));
752760
}
753761

@@ -834,9 +842,8 @@ mod tests {
834842
// canonicalize 1. 2 and all its children should be discarded
835843
let mut commit = CommitSet::default();
836844
overlay.canonicalize(&h_1, &mut commit).unwrap();
837-
// explicitly unpin last block
838-
overlay.unpin(&h_1);
839845
db.commit(&commit);
846+
overlay.sync();
840847
assert_eq!(overlay.levels.len(), 2);
841848
assert_eq!(overlay.parents.len(), 6);
842849
assert!(!contains(&overlay, 1));
@@ -856,8 +863,8 @@ mod tests {
856863
// canonicalize 1_2. 1_1 and all its children should be discarded
857864
let mut commit = CommitSet::default();
858865
overlay.canonicalize(&h_1_2, &mut commit).unwrap();
859-
overlay.unpin(&h_1_2);
860866
db.commit(&commit);
867+
overlay.sync();
861868
assert_eq!(overlay.levels.len(), 1);
862869
assert_eq!(overlay.parents.len(), 3);
863870
assert!(!contains(&overlay, 11));
@@ -873,8 +880,8 @@ mod tests {
873880
// canonicalize 1_2_2
874881
let mut commit = CommitSet::default();
875882
overlay.canonicalize(&h_1_2_2, &mut commit).unwrap();
876-
overlay.unpin(&h_1_2_2);
877883
db.commit(&commit);
884+
overlay.sync();
878885
assert_eq!(overlay.levels.len(), 0);
879886
assert_eq!(overlay.parents.len(), 0);
880887
assert!(db.data_eq(&make_db(&[1, 12, 122])));
@@ -958,6 +965,28 @@ mod tests {
958965
assert!(!contains(&overlay, 1));
959966
}
960967

968+
#[test]
969+
fn pins_canonicalized() {
970+
let mut db = make_db(&[]);
971+
972+
let (h_1, c_1) = (H256::random(), make_changeset(&[1], &[]));
973+
let (h_2, c_2) = (H256::random(), make_changeset(&[2], &[]));
974+
975+
let mut overlay = NonCanonicalOverlay::<H256, H256>::new(&db).unwrap();
976+
db.commit(&overlay.insert(&h_1, 1, &H256::default(), c_1).unwrap());
977+
db.commit(&overlay.insert(&h_2, 2, &h_1, c_2).unwrap());
978+
979+
let mut commit = CommitSet::default();
980+
overlay.canonicalize(&h_1, &mut commit).unwrap();
981+
overlay.canonicalize(&h_2, &mut commit).unwrap();
982+
assert!(contains(&overlay, 1));
983+
assert!(contains(&overlay, 2));
984+
db.commit(&commit);
985+
overlay.sync();
986+
assert!(!contains(&overlay, 1));
987+
assert!(!contains(&overlay, 2));
988+
}
989+
961990
#[test]
962991
fn pin_keeps_parent() {
963992
let mut db = make_db(&[]);
@@ -1019,8 +1048,8 @@ mod tests {
10191048

10201049
let mut commit = CommitSet::default();
10211050
overlay.canonicalize(&h21, &mut commit).unwrap(); // h11 should stay in the DB
1022-
overlay.unpin(&h21);
10231051
db.commit(&commit);
1052+
overlay.sync();
10241053
assert!(!contains(&overlay, 21));
10251054
}
10261055

0 commit comments

Comments
 (0)