From 8f0f6d9efdd10e1bb5d35e285a129fdce74536d1 Mon Sep 17 00:00:00 2001 From: David Palm Date: Sun, 13 Oct 2019 22:13:18 +0200 Subject: [PATCH 01/18] WIP. Typos and logging. --- ethcore/snapshot/src/consensus/work.rs | 2 +- ethcore/snapshot/src/lib.rs | 16 +++++++++++---- ethcore/snapshot/src/service.rs | 5 +++-- ethcore/snapshot/src/traits.rs | 2 +- ethcore/snapshot/src/watcher.rs | 28 +++++++++++++++++--------- ethcore/src/client/client.rs | 18 ++++++++++------- parity/run.rs | 4 ++-- util/journaldb/src/lib.rs | 4 ++-- 8 files changed, 51 insertions(+), 28 deletions(-) diff --git a/ethcore/snapshot/src/consensus/work.rs b/ethcore/snapshot/src/consensus/work.rs index eb035fb7734..ba685d9d270 100644 --- a/ethcore/snapshot/src/consensus/work.rs +++ b/ethcore/snapshot/src/consensus/work.rs @@ -178,7 +178,7 @@ impl<'a> PowWorker<'a> { let parent_hash = last_header.parent_hash(); let parent_total_difficulty = last_details.total_difficulty - last_header.difficulty(); - trace!(target: "snapshot", "parent last written block: {}", parent_hash); + trace!(target: "snapshot", "parent last written block: #{}/{}", parent_number, parent_hash); let num_entries = self.rlps.len(); let mut rlp_stream = RlpStream::new_list(3 + num_entries); diff --git a/ethcore/snapshot/src/lib.rs b/ethcore/snapshot/src/lib.rs index e6797a661a9..464586d4690 100644 --- a/ethcore/snapshot/src/lib.rs +++ b/ethcore/snapshot/src/lib.rs @@ -129,7 +129,7 @@ pub fn take_snapshot( let state_root = start_header.state_root(); let block_number = start_header.number(); - info!("Taking snapshot starting at block {}", block_number); + info!("Taking snapshot starting at block #{}/{:?}", block_number, block_hash); let version = chunker.current_version(); let writer = Mutex::new(writer); @@ -141,10 +141,10 @@ pub fn take_snapshot( // The number of threads must be between 1 and SNAPSHOT_SUBPARTS assert!(processing_threads >= 1, "Cannot use less than 1 threads for creating snapshots"); - let num_threads: usize = cmp::min(processing_threads, SNAPSHOT_SUBPARTS); + let num_threads = cmp::min(processing_threads, SNAPSHOT_SUBPARTS); info!(target: "snapshot", "Using {} threads for Snapshot creation.", num_threads); - let mut state_guards = Vec::with_capacity(num_threads as usize); + let mut state_guards = Vec::with_capacity(num_threads); for thread_idx in 0..num_threads { let state_guard = scope.spawn(move |_| -> Result, Error> { @@ -349,7 +349,15 @@ pub fn chunk_state<'a>( let account = ::rlp::decode(&*account_data)?; let account_db = AccountDB::from_hash(db, account_key_hash); - let fat_rlps = account::to_fat_rlps(&account_key_hash, &account, &account_db, &mut used_code, PREFERRED_CHUNK_SIZE - chunker.chunk_size(), PREFERRED_CHUNK_SIZE, progress)?; + let fat_rlps = account::to_fat_rlps( + &account_key_hash, + &account, + &account_db, + &mut used_code, + PREFERRED_CHUNK_SIZE - chunker.chunk_size(), + PREFERRED_CHUNK_SIZE, + progress + )?; for (i, fat_rlp) in fat_rlps.into_iter().enumerate() { if i > 0 { chunker.write_chunk()?; diff --git a/ethcore/snapshot/src/service.rs b/ethcore/snapshot/src/service.rs index 141a32360c9..283f01c8432 100644 --- a/ethcore/snapshot/src/service.rs +++ b/ethcore/snapshot/src/service.rs @@ -483,11 +483,11 @@ impl Service where C: SnapshotClient + ChainInfo { if self.progress.done() || !self.taking_snapshot.load(Ordering::SeqCst) { return } let p = &self.progress; - info!("Snapshot: {} accounts {} blocks {} bytes", p.accounts(), p.blocks(), p.size()); + info!("Snapshot: {} accounts, {} blocks, {} bytes", p.accounts(), p.blocks(), p.size()); } /// Take a snapshot at the block with the given number. - /// calling this while a restoration is in progress or vice versa + /// Calling this while a restoration is in progress or vice versa /// will lead to a race condition where the first one to finish will /// have their produced snapshot overwritten. pub fn take_snapshot(&self, client: &C, num: u64) -> Result<(), Error> { @@ -506,6 +506,7 @@ impl Service where C: SnapshotClient + ChainInfo { let writer = LooseWriter::new(temp_dir.clone())?; + let guard = Guard::new(temp_dir.clone()); let res = client.take_snapshot(writer, BlockId::Number(num), &self.progress); self.taking_snapshot.store(false, Ordering::SeqCst); diff --git a/ethcore/snapshot/src/traits.rs b/ethcore/snapshot/src/traits.rs index b72d6b7afe0..c8b227e5745 100644 --- a/ethcore/snapshot/src/traits.rs +++ b/ethcore/snapshot/src/traits.rs @@ -136,7 +136,7 @@ pub trait SnapshotComponents: Send { /// Snapshot related functionality pub trait SnapshotClient: BlockChainClient + BlockInfo + DatabaseRestore + BlockChainReset { /// Take a snapshot at the given block. - /// If the ID given is "latest", this will default to 1000 blocks behind. + /// If the BlockId is 'Latest', this will default to 1000 blocks behind. fn take_snapshot( &self, writer: W, diff --git a/ethcore/snapshot/src/watcher.rs b/ethcore/snapshot/src/watcher.rs index d6d9bcef8c0..b550ea777ab 100644 --- a/ethcore/snapshot/src/watcher.rs +++ b/ethcore/snapshot/src/watcher.rs @@ -55,10 +55,12 @@ impl Broadcast for Mutex>> { None => return, }; - trace!(target: "snapshot_watcher", "Snapshot requested at block #{}", num); + trace!(target: "snapshot_watcher", "Requesting snapshot at block #{}", num); if let Err(e) = self.lock().send(ClientIoMessage::TakeSnapshot(num)) { - warn!("Snapshot watcher disconnected from IoService: {}", e); + warn!(target: "snapshot_watcher", "Snapshot watcher disconnected from IoService: {}", e); + } else { + trace!(target: "snapshot_watcher", "Snapshot requested at block #{}", num); } } } @@ -68,7 +70,9 @@ impl Broadcast for Mutex>> { pub struct Watcher { oracle: Box, broadcast: Box, + // how often to take periodic snapshots. period: u64, + // how many blocks to wait before starting a periodic snapshot. history: u64, } @@ -104,16 +108,22 @@ impl Watcher { impl ChainNotify for Watcher { fn new_blocks(&self, new_blocks: NewBlocks) { - if self.oracle.is_major_importing() || new_blocks.has_more_blocks_to_import { return } + if self.oracle.is_major_importing() { + trace!(target: "snapshot_watcher", "Is major importing; not taking snapshot"); + } else if new_blocks.has_more_blocks_to_import { + trace!(target: "snapshot_watcher", "Has more blocks to import; not taking snapshot"); + return + } - trace!(target: "snapshot_watcher", "{} imported", new_blocks.imported.len()); + trace!(target: "snapshot_watcher", "{} blocks imported", new_blocks.imported.len()); + // Decide if the imported blocks is the new "best block" let highest = new_blocks.imported.into_iter() - .filter_map(|h| self.oracle.to_number(h)) - .filter(|&num| num >= self.period + self.history) - .map(|num| num - self.history) - .filter(|num| num % self.period == 0) - .fold(0, ::std::cmp::max); + .filter_map(|h| self.oracle.to_number(h)) // convert block hashes to block numbers for all newly imported blocks + .filter(|&num| num >= self.period + self.history) // …only keep the new blocks that have numbers bigger than period + history (todo: this seems nonsensical: period is always 5000 and history is always 100, so this filters out blocknumbers that are lower than 5100; what's the point of that?) + .map(|num| num - self.history) // subtract history (todo: why? Here we back off 100 blocks such that the final block number from which we start the snapshot is "(new) best block" - 100) + .filter(|num| num % self.period == 0) // …filter out blocks that do not fall on the a multiple of `period` (todo: why? it means we only ever start a snapshot on blocks that are multiples of 5000 but I fail to see the point of that.) + .fold(0, ::std::cmp::max); // Pick biggest block number of the candidates: this is where we want to snapshot from. match highest { 0 => self.broadcast.take_at(None), diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 04e7074f1d2..6aaf562f1a5 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2521,7 +2521,7 @@ impl ProvingBlockChainClient for Client { self.chain.read().get_pending_transition(hash).map(|pending| pending.proof) } } - +// todo[dvdplm]: move snapshotting code to own module? impl SnapshotClient for Client { fn take_snapshot( &self, @@ -2533,39 +2533,43 @@ impl SnapshotClient for Client { return Err(EthcoreError::Snapshot(SnapshotError::SnapshotsUnsupported)); } let db = self.state_db.read().journal_db().boxed_clone(); - let best_block_number = self.chain_info().best_block_number; + let block_number = self.block_number(at).ok_or_else(|| SnapshotError::InvalidStartingBlock(at))?; if db.is_prunable() && self.pruning_info().earliest_state > block_number { return Err(SnapshotError::OldBlockPrunedDB.into()); } - let history = cmp::min(self.history, 1000); + let history = cmp::min(self.history, 1000); // `history`: number of eras kept in the journal before they are pruned - let start_hash = match at { + let (actual_block_nr, block_hash) = match at { BlockId::Latest => { + let best_block_number = self.chain_info().best_block_number; let start_num = match db.earliest_era() { Some(era) => cmp::max(era, best_block_number.saturating_sub(history)), None => best_block_number.saturating_sub(history), }; match self.block_hash(BlockId::Number(start_num)) { - Some(h) => h, + Some(hash) => (start_num, hash), None => return Err(SnapshotError::InvalidStartingBlock(at).into()), } } _ => match self.block_hash(at) { - Some(hash) => hash, + Some(hash) => (block_number, hash), None => return Err(SnapshotError::InvalidStartingBlock(at).into()), }, }; let processing_threads = self.config.snapshot.processing_threads; + trace!(target: "snapshot", "Snapshot requested at block {:?}. Using block #{}/{:?}. Earliest block: #{}, earliest state era #{}. Using {} threads.", + at, actual_block_nr, block_hash, self.pruning_info().earliest_chain, self.pruning_info().earliest_state, processing_threads, + ); let chunker = snapshot::chunker(self.engine.snapshot_mode()).ok_or_else(|| SnapshotError::SnapshotsUnsupported)?; snapshot::take_snapshot( chunker, &self.chain.read(), - start_hash, + block_hash, db.as_hash_db(), writer, p, diff --git a/parity/run.rs b/parity/run.rs index 891424eebb2..c0076c3aa2b 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -69,10 +69,10 @@ use db; use registrar::RegistrarClient; // how often to take periodic snapshots. -const SNAPSHOT_PERIOD: u64 = 5000; +const SNAPSHOT_PERIOD: u64 = 50; // how many blocks to wait before starting a periodic snapshot. -const SNAPSHOT_HISTORY: u64 = 100; +const SNAPSHOT_HISTORY: u64 = 10; // Number of minutes before a given gas price corpus should expire. // Light client only. diff --git a/util/journaldb/src/lib.rs b/util/journaldb/src/lib.rs index 0024b3638c0..739c25807a1 100644 --- a/util/journaldb/src/lib.rs +++ b/util/journaldb/src/lib.rs @@ -84,8 +84,8 @@ pub trait JournalDB: HashDB { /// Get backing database. fn backing(&self) -> &Arc; - /// Clear internal strucutres. This should called after changes have been written - /// to the backing strage + /// Clear internal structure. This should be called after changes have been written + /// to the backing storage. fn flush(&self) {} /// Consolidate all the insertions and deletions in the given memory overlay. From e73458e694f09d574a7b8413a1d09559468cb013 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 14 Oct 2019 11:12:39 +0200 Subject: [PATCH 02/18] Format todos --- ethcore/snapshot/src/watcher.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/ethcore/snapshot/src/watcher.rs b/ethcore/snapshot/src/watcher.rs index b550ea777ab..d5a834ca94c 100644 --- a/ethcore/snapshot/src/watcher.rs +++ b/ethcore/snapshot/src/watcher.rs @@ -117,13 +117,24 @@ impl ChainNotify for Watcher { trace!(target: "snapshot_watcher", "{} blocks imported", new_blocks.imported.len()); - // Decide if the imported blocks is the new "best block" + // Decide if the imported blocks is the new "best block". let highest = new_blocks.imported.into_iter() - .filter_map(|h| self.oracle.to_number(h)) // convert block hashes to block numbers for all newly imported blocks - .filter(|&num| num >= self.period + self.history) // …only keep the new blocks that have numbers bigger than period + history (todo: this seems nonsensical: period is always 5000 and history is always 100, so this filters out blocknumbers that are lower than 5100; what's the point of that?) - .map(|num| num - self.history) // subtract history (todo: why? Here we back off 100 blocks such that the final block number from which we start the snapshot is "(new) best block" - 100) - .filter(|num| num % self.period == 0) // …filter out blocks that do not fall on the a multiple of `period` (todo: why? it means we only ever start a snapshot on blocks that are multiples of 5000 but I fail to see the point of that.) - .fold(0, ::std::cmp::max); // Pick biggest block number of the candidates: this is where we want to snapshot from. + // Convert block hashes to block numbers for all newly imported blocks + .filter_map(|h| self.oracle.to_number(h)) + // …only keep the new blocks that have numbers bigger than period + history + // todo: this seems nonsensical: period is always 5000 and history is always 100, so + // this filters out blocknumbers that are lower than 5100; what's the point of that? + .filter(|&num| num >= self.period + self.history) + // Subtract `history` (i.e. `SNAPSHOT_HISTORY`, i.e. 100) from the block numbers. + // todo: why? Here we back off 100 blocks such that the final block + // number from which we start the snapshot is "(new) best block" - 100) + .map(|num| num - self.history) + // …filter out blocks that do not fall on the a multiple of `period` + // todo: why? it means we only ever start a snapshot on blocks that are multiples of + // 5000 but I fail to see the point of that. + .filter(|num| num % self.period == 0) + // Pick biggest block number of the candidates: this is where we want to snapshot from. + .fold(0, ::std::cmp::max); match highest { 0 => self.broadcast.take_at(None), From ccf3a2920f82668bbdcc96ec593b35c6f6305235 Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Oct 2019 19:44:39 +0200 Subject: [PATCH 03/18] Pause pruning while a snapshot is under way Logs, docs and todos --- Cargo.lock | 114 +++++++++++++++++--------- ethcore/Cargo.toml | 1 + ethcore/service/src/service.rs | 1 - ethcore/snapshot/src/lib.rs | 8 +- ethcore/snapshot/src/service.rs | 52 +++++++----- ethcore/snapshot/src/watcher.rs | 28 +++---- ethcore/src/client/client.rs | 77 ++++++++++------- parity/run.rs | 7 +- parity/snapshot_cmd.rs | 2 +- util/journaldb/src/overlayrecentdb.rs | 11 ++- 10 files changed, 185 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3c465b998c..bc939ca9b24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ name = "account-db" version = "0.1.0" dependencies = [ "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", "kvdb 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -20,7 +20,7 @@ dependencies = [ "common-types 0.1.0", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", @@ -37,7 +37,7 @@ dependencies = [ "rlp_compress 0.1.0", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "trace 0.1.0", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-vm-factories 0.1.0", ] @@ -82,6 +82,14 @@ dependencies = [ "stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ahash" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "aho-corasick" version = "0.6.8" @@ -602,6 +610,24 @@ dependencies = [ "vm 0.1.0", ] +[[package]] +name = "const-random" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "const-random-macro" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "criterion" version = "0.3.0" @@ -1050,7 +1076,7 @@ dependencies = [ "executive-state 0.1.0", "fetch 0.1.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1072,6 +1098,7 @@ dependencies = [ "registrar 0.0.1", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1082,7 +1109,7 @@ dependencies = [ "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "trace 0.1.0", "trace-time 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-standardmap 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "trie-vm-factories 0.1.0", "triehash-ethereum 0.2.0", @@ -1221,7 +1248,7 @@ dependencies = [ "failsafe 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fastmap 0.1.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", @@ -1244,7 +1271,7 @@ dependencies = [ "spec 0.1.0", "stats 0.1.0", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "triehash-ethereum 0.2.0", "verification 0.1.0", "vm 0.1.0", @@ -1376,7 +1403,7 @@ dependencies = [ "ethkey 0.3.0", "fetch 0.1.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", @@ -1401,7 +1428,7 @@ dependencies = [ "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "trace 0.1.0", "transaction-pool 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", ] @@ -1682,7 +1709,7 @@ dependencies = [ "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", "evm 0.1.0", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", "kvdb 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1694,7 +1721,7 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "spec 0.1.0", "trace 0.1.0", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-vm-factories 0.1.0", "vm 0.1.0", ] @@ -1917,7 +1944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hash-db" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1928,6 +1955,15 @@ dependencies = [ "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hashbrown" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ahash 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hashmap_core" version = "0.1.10" @@ -2232,7 +2268,7 @@ dependencies = [ "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fastmap 0.1.0", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", "kvdb 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2360,7 +2396,7 @@ name = "keccak-hasher" version = "0.1.1" dependencies = [ "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "plain_hasher 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2370,7 +2406,7 @@ name = "keccak-hasher" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "hash256-std-hasher 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2618,7 +2654,7 @@ name = "memory-db" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "parity-util-mem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3388,14 +3424,14 @@ version = "0.1.0" dependencies = [ "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", "memory-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3481,7 +3517,7 @@ dependencies = [ "common-types 0.1.0", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethjson 0.1.0", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", @@ -3493,7 +3529,7 @@ dependencies = [ "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "triehash-ethereum 0.2.0", ] @@ -3722,7 +3758,7 @@ name = "rand_chacha" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3761,7 +3797,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3803,7 +3839,7 @@ name = "rand_xorshift" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4199,7 +4235,7 @@ dependencies = [ "ethcore-io 1.12.0", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4221,7 +4257,7 @@ dependencies = [ "spec 0.1.0", "state-db 0.1.0", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-standardmap 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "triehash-ethereum 0.2.0", ] @@ -4246,7 +4282,7 @@ dependencies = [ "ethcore-io 1.12.0", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethkey 0.3.0", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", @@ -4264,7 +4300,7 @@ dependencies = [ "snapshot 0.1.0", "spec 0.1.0", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-standardmap 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "triehash-ethereum 0.2.0", ] @@ -4299,7 +4335,7 @@ dependencies = [ "ethjson 0.1.0", "evm 0.1.0", "executive-state 0.1.0", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "instant-seal 0.1.0", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4337,7 +4373,7 @@ dependencies = [ "ethcore-bloom-journal 0.1.0", "ethcore-db 0.1.0", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "journaldb 0.2.0", "keccak-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.1.1", @@ -4831,12 +4867,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "trie-db" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4846,7 +4882,7 @@ name = "trie-standardmap" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "keccak-hasher 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4858,7 +4894,7 @@ dependencies = [ "evm 0.1.0", "keccak-hasher 0.1.1", "patricia-trie-ethereum 0.1.0", - "trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", "wasm 0.1.0", ] @@ -4868,7 +4904,7 @@ name = "triehash" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -5313,6 +5349,7 @@ dependencies = [ "checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" "checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" "checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" +"checksum ahash 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "b35dfc96a657c1842b4eb73180b65e37152d4b94d0eb5cb51708aee7826950b4" "checksum aho-corasick 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68f56c7353e5a9547cbd76ed90f7bb5ffc3ba09d4ea9bd1d8c06c8b1142eeb5a" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" @@ -5358,6 +5395,8 @@ dependencies = [ "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" "checksum combine 3.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc1d011beeed29187b8db2ac3925c8dd4d3e87db463dc9d2d2833985388fc5bc" +"checksum const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b641a8c9867e341f3295564203b1c250eb8ce6cb6126e007941f78c4d2ed7fe" +"checksum const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c750ec12b83377637110d5a57f5ae08e895b06c4b16e2bdbf1a94ef717428c59" "checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" "checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" @@ -5415,8 +5454,9 @@ dependencies = [ "checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865" "checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" "checksum hamming 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65043da274378d68241eb9a8f8f8aa54e349136f7b8e12f63e3ef44043cc30e1" -"checksum hash-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32c87fec93c4a2d264483ef843ac1930ae7c7999d97d73721305a5188b4c23a4" +"checksum hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" "checksum hash256-std-hasher 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16293646125e09e5bc216d9f73fa81ab31c4f97007d56c036bbf15a58e970540" +"checksum hashbrown 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6587d09be37fb98a11cb08b9000a3f592451c1b1b613ca69d949160e313a430a" "checksum hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8e04cb7a5051270ef3fa79f8c7604d581ecfa73d520e74f554e45541c4b5881a" "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" "checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82" @@ -5663,7 +5703,7 @@ dependencies = [ "checksum trace-time 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe82f2f0bf1991e163e757baf044282823155dd326e70f44ce2186c3c320cc9" "checksum transaction-pool 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "454adc482e32785c3beab9415dd0f3c689f29cc2d16717eb62f6a784d53544b4" "checksum transient-hashmap 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aeb4b191d033a35edfce392a38cdcf9790b6cebcb30fa690c312c29da4dc433e" -"checksum trie-db 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b65d609ae631d808c6c1cc23a622733d5a0b66a7d67e9f5cd5171562a1f4cb5" +"checksum trie-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b62d27e8aa1c07414549ac872480ac82380bab39e730242ab08d82d7cc098a" "checksum trie-standardmap 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "64fda153c00484d640bc91334624be22ead0e5baca917d9fd53ff29bdebcf9b2" "checksum triehash 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "61d0a66fa2412c7eb7816640e8ea14cf6bd63b6c824e72315b6ca76d33851134" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 97c1e8f1aa1..8fc2e072e44 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -50,6 +50,7 @@ rayon = "1.1" registrar = { path = "../util/registrar" } rlp = "0.4.0" rustc-hex = "2" +scopeguard = "1.0.0" serde = "1.0" serde_derive = "1.0" snapshot = { path = "snapshot" } diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 06f1efe7658..2632d91615d 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -277,7 +277,6 @@ where EthcoreError::Snapshot(SnapshotError::SnapshotAborted) => info!("Snapshot aborted"), _ => warn!("Failed to take snapshot at block #{}: {}", num, e), } - } }); diff --git a/ethcore/snapshot/src/lib.rs b/ethcore/snapshot/src/lib.rs index 464586d4690..8c9652c9a2f 100644 --- a/ethcore/snapshot/src/lib.rs +++ b/ethcore/snapshot/src/lib.rs @@ -130,7 +130,6 @@ pub fn take_snapshot( let block_number = start_header.number(); info!("Taking snapshot starting at block #{}/{:?}", block_number, block_hash); - let version = chunker.current_version(); let writer = Mutex::new(writer); let (state_hashes, block_hashes) = thread::scope(|scope| -> Result<(Vec, Vec), Error> { @@ -149,13 +148,11 @@ pub fn take_snapshot( for thread_idx in 0..num_threads { let state_guard = scope.spawn(move |_| -> Result, Error> { let mut chunk_hashes = Vec::new(); - for part in (thread_idx..SNAPSHOT_SUBPARTS).step_by(num_threads) { - debug!(target: "snapshot", "Chunking part {} in thread {}", part, thread_idx); + debug!(target: "snapshot", "Chunking part {} of the state at {} in thread {}", part, block_number, thread_idx); let mut hashes = chunk_state(state_db, &state_root, writer, p, Some(part), thread_idx)?; chunk_hashes.append(&mut hashes); } - Ok(chunk_hashes) }); state_guards.push(state_guard); @@ -170,6 +167,7 @@ pub fn take_snapshot( } debug!(target: "snapshot", "Took a snapshot of {} accounts", p.accounts.load(Ordering::SeqCst)); + Ok((state_hashes, block_hashes)) }).expect("Sub-thread never panics; qed")?; @@ -327,7 +325,7 @@ pub fn chunk_state<'a>( if let Some(part) = part { assert!(part < 16, "Wrong chunk state part number (must be <16) in snapshot creation."); - let part_offset = MAX_SNAPSHOT_SUBPARTS / SNAPSHOT_SUBPARTS; + let part_offset = MAX_SNAPSHOT_SUBPARTS / SNAPSHOT_SUBPARTS; // 16 let mut seek_from = vec![0; 32]; seek_from[0] = (part * part_offset) as u8; account_iter.seek(&seek_from)?; diff --git a/ethcore/snapshot/src/service.rs b/ethcore/snapshot/src/service.rs index 283f01c8432..a8a6f6fc35f 100644 --- a/ethcore/snapshot/src/service.rs +++ b/ethcore/snapshot/src/service.rs @@ -212,7 +212,7 @@ impl Restoration { } self.guard.disarm(); - trace!(target: "snapshot", "restoration finalised correctly"); + trace!(target: "snapshot", "Restoration finalised correctly"); Ok(()) } @@ -413,7 +413,10 @@ impl Service where C: SnapshotClient + ChainInfo { Some(x) => x, None => return Ok(0), }; - + info!(target: "snapshot", "Migrating blocks from old db to new. Start: #{}/{:?}, Target: #{}/{:?}", + self.client.block_number(BlockId::Hash(start_hash)).unwrap_or_default(), start_hash, + self.client.block_number(BlockId::Hash(target_hash)).unwrap_or_default(), target_hash, + ); let mut batch = DBTransaction::new(); let mut parent_hash = start_hash; while parent_hash != target_hash { @@ -455,10 +458,10 @@ impl Service where C: SnapshotClient + ChainInfo { next_chain.commit(); next_db.key_value().flush().expect("DB flush failed."); batch = DBTransaction::new(); - } - if block_number % 10_000 == 0 { - info!(target: "snapshot", "Block restoration at #{}", block_number); + if block_number % 10_000 == 0 { + info!(target: "snapshot", "Block restoration at #{}", block_number); + } } } @@ -497,6 +500,7 @@ impl Service where C: SnapshotClient + ChainInfo { } info!("Taking snapshot at #{}", num); + let start_time = std::time::Instant::now(); self.progress.reset(); let temp_dir = self.temp_snapshot_dir(); @@ -506,21 +510,21 @@ impl Service where C: SnapshotClient + ChainInfo { let writer = LooseWriter::new(temp_dir.clone())?; - let guard = Guard::new(temp_dir.clone()); let res = client.take_snapshot(writer, BlockId::Number(num), &self.progress); self.taking_snapshot.store(false, Ordering::SeqCst); if let Err(e) = res { + // TODO[dvdplm]: when freezing pruning this condition is always met, causing this message to be logged at shutdown. if client.chain_info().best_block_number >= num + client.pruning_history() { - // The state we were snapshotting was pruned before we could finish. - info!("Periodic snapshot failed: block state pruned. Run with a longer `--pruning-history` or with `--no-periodic-snapshot`"); + info!("Periodic snapshot failed: the state at #{} was pruned before we could finish. Run with a longer `--pruning-history` (currently {}) or with `--no-periodic-snapshot`?", num, client.pruning_history()); + trace!(target: "snapshot", "snapshot error: {:?}", e); return Err(e); } else { return Err(e); } } - - info!("Finished taking snapshot at #{}", num); + let end_time = std::time::Instant::now(); + info!("Finished taking snapshot at #{}, in {:#?}", num, end_time - start_time); let mut reader = self.reader.write(); @@ -528,11 +532,12 @@ impl Service where C: SnapshotClient + ChainInfo { *reader = None; if snapshot_dir.exists() { + trace!(target: "snapshot", "Removing previous snapshot at {:?}", &snapshot_dir); fs::remove_dir_all(&snapshot_dir)?; } fs::rename(temp_dir, &snapshot_dir)?; - + trace!(target: "snapshot", "Moved new snapshot into place at {:?}", &snapshot_dir); *reader = Some(LooseReader::new(snapshot_dir)?); guard.disarm(); @@ -655,13 +660,18 @@ impl Service where C: SnapshotClient + ChainInfo { Ok(()) } - /// Import a previous chunk at the given path. Returns whether the block was imported or not - fn import_prev_chunk(&self, restoration: &mut Option, manifest: &ManifestData, file: io::Result) -> Result { + /// Import a previous chunk at the given path. Returns whether the chunk was imported or not + fn import_prev_chunk( + &self, + restoration: &mut Option, + manifest: &ManifestData, + file: io::Result + ) -> Result { let file = file?; let path = file.path(); let mut file = File::open(path.clone())?; - let mut buffer = Vec::new(); + let mut buffer = Vec::new(); // todo[dvdplm] estimate size and allocate up-front. file.read_to_end(&mut buffer)?; let hash = keccak(&buffer); @@ -671,6 +681,7 @@ impl Service where C: SnapshotClient + ChainInfo { } else if manifest.state_hashes.contains(&hash) { true } else { + warn!(target: "snapshot", "Hash of the content of {:?} not present in the manifest block/state hashes.", path); return Ok(false); }; @@ -681,11 +692,10 @@ impl Service where C: SnapshotClient + ChainInfo { Ok(true) } - // finalize the restoration. this accepts an already-locked - // restoration as an argument -- so acquiring it again _will_ - // lead to deadlock. + // Finalize the restoration. This accepts an already-locked restoration as an argument -- so + // acquiring it again _will_ lead to deadlock. fn finalize_restoration(&self, rest: &mut Option) -> Result<(), Error> { - trace!(target: "snapshot", "finalizing restoration"); + trace!(target: "snapshot", "Finalizing restoration"); *self.status.lock() = RestorationStatus::Finalizing; let recover = rest.as_ref().map_or(false, |rest| rest.writer.is_some()); @@ -696,7 +706,7 @@ impl Service where C: SnapshotClient + ChainInfo { .unwrap_or(Ok(()))?; let migrated_blocks = self.migrate_blocks()?; - info!(target: "snapshot", "Migrated {} ancient blocks", migrated_blocks); + info!(target: "snapshot", "Migrated {} ancient blocks from the old DB", migrated_blocks); // replace the Client's database with the new one (restart the Client). self.client.restore_db(&*self.restoration_db().to_string_lossy())?; @@ -708,11 +718,11 @@ impl Service where C: SnapshotClient + ChainInfo { let snapshot_dir = self.snapshot_dir(); if snapshot_dir.exists() { - trace!(target: "snapshot", "removing old snapshot dir at {}", snapshot_dir.to_string_lossy()); + trace!(target: "snapshot", "Removing old snapshot dir at {}", snapshot_dir.to_string_lossy()); fs::remove_dir_all(&snapshot_dir)?; } - trace!(target: "snapshot", "copying restored snapshot files over"); + trace!(target: "snapshot", "Copying restored snapshot files over"); fs::rename(self.temp_recovery_dir(), &snapshot_dir)?; *reader = Some(LooseReader::new(snapshot_dir)?); diff --git a/ethcore/snapshot/src/watcher.rs b/ethcore/snapshot/src/watcher.rs index d5a834ca94c..e4d5c989784 100644 --- a/ethcore/snapshot/src/watcher.rs +++ b/ethcore/snapshot/src/watcher.rs @@ -70,9 +70,10 @@ impl Broadcast for Mutex>> { pub struct Watcher { oracle: Box, broadcast: Box, - // how often to take periodic snapshots. + // How often we attempt to take a snapshot: only snapshot on blocknumbers that are multiples of + // `period`. Always set to `SNAPSHOT_PERIOD`, i.e. 5000. period: u64, - // how many blocks to wait before starting a periodic snapshot. + // Start snapshots `history` blocks from the tip. Always set to `SNAPSHOT_HISTORY`, i.e. 100. history: u64, } @@ -115,9 +116,7 @@ impl ChainNotify for Watcher { return } - trace!(target: "snapshot_watcher", "{} blocks imported", new_blocks.imported.len()); - - // Decide if the imported blocks is the new "best block". + // Decide if it's time for a snapshot: the highest of the imported blocks is . let highest = new_blocks.imported.into_iter() // Convert block hashes to block numbers for all newly imported blocks .filter_map(|h| self.oracle.to_number(h)) @@ -127,18 +126,19 @@ impl ChainNotify for Watcher { .filter(|&num| num >= self.period + self.history) // Subtract `history` (i.e. `SNAPSHOT_HISTORY`, i.e. 100) from the block numbers. // todo: why? Here we back off 100 blocks such that the final block - // number from which we start the snapshot is "(new) best block" - 100) + // number from which we start the snapshot is "(new) highest block" - 100) + // Maybe we do this to avoid IO contention on the tip? Or for reorgs? If the + // latter, it should be maybe be higher? .map(|num| num - self.history) - // …filter out blocks that do not fall on the a multiple of `period` - // todo: why? it means we only ever start a snapshot on blocks that are multiples of - // 5000 but I fail to see the point of that. - .filter(|num| num % self.period == 0) - // Pick biggest block number of the candidates: this is where we want to snapshot from. + // …filter out blocks that do not fall on the a multiple of `period`. This regulates the + // frequency of snapshots and ensures more snapshots are produced from similar points in + // the chain. + .filter(|num| num % self.period == 0 ) + // Pick newest of the candidates: this is where we want to snapshot from. .fold(0, ::std::cmp::max); - match highest { - 0 => self.broadcast.take_at(None), - _ => self.broadcast.take_at(Some(highest)), + if highest > 0 { + self.broadcast.take_at(Some(highest)); } } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 6aaf562f1a5..e9be898aa4d 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -20,7 +20,7 @@ use std::convert::TryFrom; use std::io::{BufRead, BufReader}; use std::str::from_utf8; use std::sync::{Arc, Weak}; -use std::sync::atomic::{AtomicBool, AtomicI64, Ordering as AtomicOrdering}; +use std::sync::atomic::{AtomicBool, AtomicI64, Ordering as AtomicOrdering, Ordering, AtomicU64}; use std::time::{Duration, Instant}; use ansi_term::Colour; @@ -204,6 +204,9 @@ pub struct Client { /// Database pruning strategy to use for StateDB pruning: journaldb::Algorithm, + /// Don't prune the state we're currently snapshotting + snapshotting_at: RwLock, + /// Client uses this to store blocks, traces, etc. db: RwLock>, @@ -780,6 +783,7 @@ impl Client { tracedb, engine, pruning: config.pruning.clone(), + snapshotting_at: RwLock::new(AtomicU64::new(0)), db: RwLock::new(db.clone()), state_db: RwLock::new(state_db), report: RwLock::new(Default::default()), @@ -964,13 +968,13 @@ impl Client { return Ok(()) } - let number = match state_db.journal_db().latest_era() { + let latest_era = match state_db.journal_db().latest_era() { Some(n) => n, None => return Ok(()), }; // prune all ancient eras until we're below the memory target, - // but have at least the minimum number of states. + // but have at least the minimum number of states, i.e. `history` . loop { let needs_pruning = state_db.journal_db().journal_size() >= self.config.history_mem; @@ -979,17 +983,26 @@ impl Client { } match state_db.journal_db().earliest_era() { - Some(era) if era + self.history <= number => { - trace!(target: "client", "Pruning state for ancient era {}", era); - match chain.block_hash(era) { + Some(earliest_era) if earliest_era + self.history <= latest_era => { + let freeze_at = self.snapshotting_at.read().load(Ordering::SeqCst); // todo[dvdplm]: can be `Acquire` I think? + if freeze_at > 0 && freeze_at == earliest_era { + trace!(target: "pruning", "Pruning is freezed at era {}; earliest era={}, latest era={}, journal_size={}, mem_used={}. Not pruning.", + freeze_at, earliest_era, latest_era, state_db.journal_db().journal_size(), state_db.journal_db().mem_used()); + break; + } + trace!(target: "pruning", "Pruning state for ancient era #{}; latest era={}, journal_size={}, mem_used={}.", + earliest_era, latest_era, state_db.journal_db().journal_size(), state_db.journal_db().mem_used()); +// todo[dvdplm] reinstate this before merge, logging mem is expensive: +// trace!(target: "pruning", "Pruning state for ancient era #{}", earliest_era); + match chain.block_hash(earliest_era) { Some(ancient_hash) => { let mut batch = DBTransaction::new(); - state_db.mark_canonical(&mut batch, era, &ancient_hash)?; + state_db.mark_canonical(&mut batch, earliest_era, &ancient_hash)?; self.db.read().key_value().write_buffered(batch); state_db.journal_db().flush(); } None => - debug!(target: "client", "Missing expected hash for block {}", era), + debug!(target: "pruning", "Missing expected hash for block {}", earliest_era), } } _ => break, // means that every era is kept, no pruning necessary. @@ -2535,24 +2548,25 @@ impl SnapshotClient for Client { let db = self.state_db.read().journal_db().boxed_clone(); let block_number = self.block_number(at).ok_or_else(|| SnapshotError::InvalidStartingBlock(at))?; - - if db.is_prunable() && self.pruning_info().earliest_state > block_number { + let earliest_era = db.earliest_era().unwrap_or(0); + if db.is_prunable() && earliest_era > block_number { return Err(SnapshotError::OldBlockPrunedDB.into()); } - let history = cmp::min(self.history, 1000); // `history`: number of eras kept in the journal before they are pruned let (actual_block_nr, block_hash) = match at { BlockId::Latest => { + // Start `self.history` blocks from the best block, but no further back than 1000 blocks. + let history = cmp::min(self.history, 1000); // `history`: number of eras kept in the journal before they are pruned let best_block_number = self.chain_info().best_block_number; - let start_num = match db.earliest_era() { - Some(era) => cmp::max(era, best_block_number.saturating_sub(history)), - None => best_block_number.saturating_sub(history), - }; + let start_num = cmp::max(earliest_era, best_block_number.saturating_sub(history)); match self.block_hash(BlockId::Number(start_num)) { Some(hash) => (start_num, hash), - None => return Err(SnapshotError::InvalidStartingBlock(at).into()), + None => { + error!(target: "snapshot", "Can't take snapshot at {:?}: missing hash for the starting block #{}", at, start_num); + return Err(SnapshotError::InvalidStartingBlock(at).into()) + }, } } _ => match self.block_hash(at) { @@ -2563,19 +2577,26 @@ impl SnapshotClient for Client { let processing_threads = self.config.snapshot.processing_threads; trace!(target: "snapshot", "Snapshot requested at block {:?}. Using block #{}/{:?}. Earliest block: #{}, earliest state era #{}. Using {} threads.", - at, actual_block_nr, block_hash, self.pruning_info().earliest_chain, self.pruning_info().earliest_state, processing_threads, + at, actual_block_nr, block_hash, self.pruning_info().earliest_chain, earliest_era, processing_threads, ); - let chunker = snapshot::chunker(self.engine.snapshot_mode()).ok_or_else(|| SnapshotError::SnapshotsUnsupported)?; - snapshot::take_snapshot( - chunker, - &self.chain.read(), - block_hash, - db.as_hash_db(), - writer, - p, - processing_threads, - )?; - Ok(()) + self.snapshotting_at.write().store(actual_block_nr, Ordering::SeqCst); + { + scopeguard::defer! {{ + trace!(target: "snapshot", "(defer) Unfreezing pruning, setting snapshotting_at back to 0"); + self.snapshotting_at.write().store(0, Ordering::SeqCst) + }}; + let chunker = snapshot::chunker(self.engine.snapshot_mode()).ok_or_else(|| SnapshotError::SnapshotsUnsupported)?; + snapshot::take_snapshot( + chunker, + &self.chain.read(), + block_hash, + db.as_hash_db(), + writer, + p, + processing_threads, + )?; + Ok(()) + } } diff --git a/parity/run.rs b/parity/run.rs index c0076c3aa2b..5492996646d 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -68,11 +68,12 @@ use signer; use db; use registrar::RegistrarClient; -// how often to take periodic snapshots. +// How often we attempt to take a snapshot: only snapshot on blocknumbers that are multiples of this. +// const SNAPSHOT_PERIOD: u64 = 5000; const SNAPSHOT_PERIOD: u64 = 50; -// how many blocks to wait before starting a periodic snapshot. -const SNAPSHOT_HISTORY: u64 = 10; +// Start snapshots `history` blocks from the tip. + const SNAPSHOT_HISTORY: u64 = 100; // Number of minutes before a given gas price corpus should expire. // Light client only. diff --git a/parity/snapshot_cmd.rs b/parity/snapshot_cmd.rs index bd41400a3cd..e1c92bf29d6 100644 --- a/parity/snapshot_cmd.rs +++ b/parity/snapshot_cmd.rs @@ -268,7 +268,7 @@ impl SnapshotCommand { if cur_size != last_size { last_size = cur_size; let bytes = ::informant::format_bytes(cur_size as usize); - info!("Snapshot: {} accounts {} blocks {}", p.accounts(), p.blocks(), bytes); + info!("Snapshot: {} accounts (state), {} blocks, {} bytes", p.accounts(), p.blocks(), bytes); } ::std::thread::sleep(Duration::from_secs(5)); diff --git a/util/journaldb/src/overlayrecentdb.rs b/util/journaldb/src/overlayrecentdb.rs index 0c0f92d5eb0..6ea285cd173 100644 --- a/util/journaldb/src/overlayrecentdb.rs +++ b/util/journaldb/src/overlayrecentdb.rs @@ -228,10 +228,10 @@ impl OverlayRecentDB { JournalOverlay { backing_overlay: overlay, pending_overlay: HashMap::default(), - journal: journal, - latest_era: latest_era, - earliest_era: earliest_era, - cumulative_size: cumulative_size, + journal, + latest_era, + earliest_era, + cumulative_size, } } @@ -264,7 +264,6 @@ impl JournalDB for OverlayRecentDB { fn journal_size(&self) -> usize { self.journal_overlay.read().cumulative_size - } fn is_empty(&self) -> bool { @@ -351,7 +350,7 @@ impl JournalDB for OverlayRecentDB { let mut ops = 0; // apply old commits' details - if let Some(ref mut records) = journal_overlay.journal.get_mut(&end_era) { + if let Some(records) = journal_overlay.journal.get_mut(&end_era) { let mut canon_insertions: Vec<(H256, DBValue)> = Vec::new(); let mut canon_deletions: Vec = Vec::new(); let mut overlay_deletions: Vec = Vec::new(); From a436fece815a14ddd3b0bf224fc9afaeeb1354ee Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Oct 2019 22:58:01 +0200 Subject: [PATCH 04/18] Allocate memory for the full chunk --- ethcore/snapshot/src/service.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethcore/snapshot/src/service.rs b/ethcore/snapshot/src/service.rs index a8a6f6fc35f..f34a0e01760 100644 --- a/ethcore/snapshot/src/service.rs +++ b/ethcore/snapshot/src/service.rs @@ -671,7 +671,8 @@ impl Service where C: SnapshotClient + ChainInfo { let path = file.path(); let mut file = File::open(path.clone())?; - let mut buffer = Vec::new(); // todo[dvdplm] estimate size and allocate up-front. + let filesize = file.metadata()?.len(); + let mut buffer = Vec::with_capacity(filesize as usize + 1); // +1 for EOF file.read_to_end(&mut buffer)?; let hash = keccak(&buffer); From 4307695aa8090b673ad13ef72abff30d52e197fd Mon Sep 17 00:00:00 2001 From: David Palm Date: Thu, 17 Oct 2019 23:03:13 +0200 Subject: [PATCH 05/18] Name snapshotting threads --- ethcore/snapshot/src/lib.rs | 10 ++++++---- ethcore/src/client/client.rs | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ethcore/snapshot/src/lib.rs b/ethcore/snapshot/src/lib.rs index 8c9652c9a2f..eff3101a48c 100644 --- a/ethcore/snapshot/src/lib.rs +++ b/ethcore/snapshot/src/lib.rs @@ -134,9 +134,10 @@ pub fn take_snapshot( let writer = Mutex::new(writer); let (state_hashes, block_hashes) = thread::scope(|scope| -> Result<(Vec, Vec), Error> { let writer = &writer; - let block_guard = scope.spawn(move |_| { + let tb = scope.builder().name("snapshots: Blocks".to_string()); + let block_guard = tb.spawn(move |_| { chunk_secondary(chunker, chain, block_hash, writer, p) - }); + })?; // The number of threads must be between 1 and SNAPSHOT_SUBPARTS assert!(processing_threads >= 1, "Cannot use less than 1 threads for creating snapshots"); @@ -146,7 +147,8 @@ pub fn take_snapshot( let mut state_guards = Vec::with_capacity(num_threads); for thread_idx in 0..num_threads { - let state_guard = scope.spawn(move |_| -> Result, Error> { + let tb = scope.builder().name(format!("snapshots: State-{}", thread_idx).to_string()); + let state_guard = tb.spawn(move |_| -> Result, Error> { let mut chunk_hashes = Vec::new(); for part in (thread_idx..SNAPSHOT_SUBPARTS).step_by(num_threads) { debug!(target: "snapshot", "Chunking part {} of the state at {} in thread {}", part, block_number, thread_idx); @@ -154,7 +156,7 @@ pub fn take_snapshot( chunk_hashes.append(&mut hashes); } Ok(chunk_hashes) - }); + })?; state_guards.push(state_guard); } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index e9be898aa4d..36e31efce9e 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2557,7 +2557,7 @@ impl SnapshotClient for Client { let (actual_block_nr, block_hash) = match at { BlockId::Latest => { // Start `self.history` blocks from the best block, but no further back than 1000 blocks. - let history = cmp::min(self.history, 1000); // `history`: number of eras kept in the journal before they are pruned + let history = cmp::min(self.history, 1000); let best_block_number = self.chain_info().best_block_number; let start_num = cmp::max(earliest_era, best_block_number.saturating_sub(history)); From 382b0cc6e039ad91aacd53fb3dd3ec430d8a1ff5 Mon Sep 17 00:00:00 2001 From: David Palm Date: Fri, 18 Oct 2019 10:13:21 +0200 Subject: [PATCH 06/18] Ensure `taking_snapshot` is set to false whenever and however `take_snapshot`returns Rename `take_at` to `request_snapshot_at` Cleanup --- Cargo.lock | 31 +++++---- ethcore/service/src/service.rs | 1 - ethcore/snapshot/Cargo.toml | 1 + .../snapshot/snapshot-tests/src/watcher.rs | 2 +- ethcore/snapshot/src/lib.rs | 4 +- ethcore/snapshot/src/service.rs | 69 +++++++++---------- ethcore/snapshot/src/traits.rs | 2 +- ethcore/snapshot/src/watcher.rs | 11 +-- ethcore/src/client/client.rs | 7 +- 9 files changed, 60 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc939ca9b24..00c68d84079 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -667,7 +667,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -676,7 +676,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -686,7 +686,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -697,7 +697,7 @@ name = "crossbeam-queue" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -707,7 +707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam-utils" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2569,7 +2569,7 @@ dependencies = [ "account-state 0.1.0", "client-traits 0.1.0", "common-types 0.1.0", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-contract 9.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi-derive 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3758,7 +3758,7 @@ name = "rand_chacha" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3797,7 +3797,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3839,7 +3839,7 @@ name = "rand_xorshift" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3867,7 +3867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4221,7 +4221,7 @@ dependencies = [ "account-state 0.1.0", "client-traits 0.1.0", "common-types 0.1.0", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "engine 0.1.0", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4253,6 +4253,7 @@ dependencies = [ "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp_derive 0.1.0", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "snapshot-tests 0.1.0", "spec 0.1.0", "state-db 0.1.0", @@ -4638,7 +4639,7 @@ name = "tokio-executor" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4739,7 +4740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4762,7 +4763,7 @@ name = "tokio-timer" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5404,7 +5405,7 @@ dependencies = [ "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" diff --git a/ethcore/service/src/service.rs b/ethcore/service/src/service.rs index 2632d91615d..597ee6d3d4e 100644 --- a/ethcore/service/src/service.rs +++ b/ethcore/service/src/service.rs @@ -270,7 +270,6 @@ where ClientIoMessage::TakeSnapshot(num) => { let client = self.client.clone(); let snapshot = self.snapshot.clone(); - let res = thread::Builder::new().name("Periodic Snapshot".into()).spawn(move || { if let Err(e) = snapshot.take_snapshot(&*client, num) { match e { diff --git a/ethcore/snapshot/Cargo.toml b/ethcore/snapshot/Cargo.toml index dd3749274db..697e3f60c32 100644 --- a/ethcore/snapshot/Cargo.toml +++ b/ethcore/snapshot/Cargo.toml @@ -33,6 +33,7 @@ rand = "0.6" rand_xorshift = "0.1.1" rlp = "0.4.2" rlp_derive = { path = "../../util/rlp-derive" } +scopeguard = "1.0.0" snappy = { package = "parity-snappy", version ="0.1.0" } state-db = { path = "../state-db" } trie-db = "0.15.0" diff --git a/ethcore/snapshot/snapshot-tests/src/watcher.rs b/ethcore/snapshot/snapshot-tests/src/watcher.rs index d7cf35ced3e..a5c8032d53d 100644 --- a/ethcore/snapshot/snapshot-tests/src/watcher.rs +++ b/ethcore/snapshot/snapshot-tests/src/watcher.rs @@ -41,7 +41,7 @@ impl Oracle for TestOracle { struct TestBroadcast(Option); impl Broadcast for TestBroadcast { - fn take_at(&self, num: Option) { + fn request_snapshot_at(&self, num: u64) { if num != self.0 { panic!("Watcher broadcast wrong number. Expected {:?}, found {:?}", self.0, num); } diff --git a/ethcore/snapshot/src/lib.rs b/ethcore/snapshot/src/lib.rs index eff3101a48c..53716a909b8 100644 --- a/ethcore/snapshot/src/lib.rs +++ b/ethcore/snapshot/src/lib.rs @@ -134,7 +134,7 @@ pub fn take_snapshot( let writer = Mutex::new(writer); let (state_hashes, block_hashes) = thread::scope(|scope| -> Result<(Vec, Vec), Error> { let writer = &writer; - let tb = scope.builder().name("snapshots: Blocks".to_string()); + let tb = scope.builder().name("Snapshot Worker - Blocks".to_string()); let block_guard = tb.spawn(move |_| { chunk_secondary(chunker, chain, block_hash, writer, p) })?; @@ -147,7 +147,7 @@ pub fn take_snapshot( let mut state_guards = Vec::with_capacity(num_threads); for thread_idx in 0..num_threads { - let tb = scope.builder().name(format!("snapshots: State-{}", thread_idx).to_string()); + let tb = scope.builder().name(format!("Snapshot Worker #{} - State", thread_idx).to_string()); let state_guard = tb.spawn(move |_| -> Result, Error> { let mut chunk_hashes = Vec::new(); for part in (thread_idx..SNAPSHOT_SUBPARTS).step_by(num_threads) { diff --git a/ethcore/snapshot/src/service.rs b/ethcore/snapshot/src/service.rs index f34a0e01760..f096d1129d6 100644 --- a/ethcore/snapshot/src/service.rs +++ b/ethcore/snapshot/src/service.rs @@ -500,48 +500,45 @@ impl Service where C: SnapshotClient + ChainInfo { } info!("Taking snapshot at #{}", num); - let start_time = std::time::Instant::now(); - self.progress.reset(); - - let temp_dir = self.temp_snapshot_dir(); - let snapshot_dir = self.snapshot_dir(); - - let _ = fs::remove_dir_all(&temp_dir); - - let writer = LooseWriter::new(temp_dir.clone())?; - - let guard = Guard::new(temp_dir.clone()); - let res = client.take_snapshot(writer, BlockId::Number(num), &self.progress); - self.taking_snapshot.store(false, Ordering::SeqCst); - if let Err(e) = res { - // TODO[dvdplm]: when freezing pruning this condition is always met, causing this message to be logged at shutdown. - if client.chain_info().best_block_number >= num + client.pruning_history() { - info!("Periodic snapshot failed: the state at #{} was pruned before we could finish. Run with a longer `--pruning-history` (currently {}) or with `--no-periodic-snapshot`?", num, client.pruning_history()); - trace!(target: "snapshot", "snapshot error: {:?}", e); - return Err(e); - } else { - return Err(e); + { + scopeguard::defer! {{ + self.taking_snapshot.store(false, Ordering::SeqCst); + }} + let start_time = std::time::Instant::now(); + self.progress.reset(); + + let temp_dir = self.temp_snapshot_dir(); + let snapshot_dir = self.snapshot_dir(); + + let _ = fs::remove_dir_all(&temp_dir)?; + + let writer = LooseWriter::new(temp_dir.clone())?; + + let guard = Guard::new(temp_dir.clone()); + let res = client.take_snapshot(writer, BlockId::Number(num), &self.progress); + + if res.is_err() { + return res } - } - let end_time = std::time::Instant::now(); - info!("Finished taking snapshot at #{}, in {:#?}", num, end_time - start_time); + info!("Finished taking snapshot at #{}, in {:#?}", num, start_time.elapsed()); - let mut reader = self.reader.write(); + let mut reader = self.reader.write(); - // destroy the old snapshot reader. - *reader = None; + // destroy the old snapshot reader. + *reader = None; - if snapshot_dir.exists() { - trace!(target: "snapshot", "Removing previous snapshot at {:?}", &snapshot_dir); - fs::remove_dir_all(&snapshot_dir)?; - } + if snapshot_dir.exists() { + trace!(target: "snapshot", "Removing previous snapshot at {:?}", &snapshot_dir); + fs::remove_dir_all(&snapshot_dir)?; + } - fs::rename(temp_dir, &snapshot_dir)?; - trace!(target: "snapshot", "Moved new snapshot into place at {:?}", &snapshot_dir); - *reader = Some(LooseReader::new(snapshot_dir)?); + fs::rename(temp_dir, &snapshot_dir)?; + trace!(target: "snapshot", "Moved new snapshot into place at {:?}", &snapshot_dir); + *reader = Some(LooseReader::new(snapshot_dir)?); - guard.disarm(); - Ok(()) + guard.disarm(); + Ok(()) + } } /// Initialize the restoration synchronously. diff --git a/ethcore/snapshot/src/traits.rs b/ethcore/snapshot/src/traits.rs index c8b227e5745..8f5e12a119c 100644 --- a/ethcore/snapshot/src/traits.rs +++ b/ethcore/snapshot/src/traits.rs @@ -148,7 +148,7 @@ pub trait SnapshotClient: BlockChainClient + BlockInfo + DatabaseRestore + Block /// Helper trait for broadcasting a block to take a snapshot at. pub trait Broadcast: Send + Sync { /// Start a snapshot from the given block number. - fn take_at(&self, num: Option); + fn request_snapshot_at(&self, num: u64); } diff --git a/ethcore/snapshot/src/watcher.rs b/ethcore/snapshot/src/watcher.rs index e4d5c989784..4b33cd328cf 100644 --- a/ethcore/snapshot/src/watcher.rs +++ b/ethcore/snapshot/src/watcher.rs @@ -49,14 +49,7 @@ impl Oracle for StandardOracle } impl Broadcast for Mutex>> { - fn take_at(&self, num: Option) { - let num = match num { - Some(n) => n, - None => return, - }; - - trace!(target: "snapshot_watcher", "Requesting snapshot at block #{}", num); - + fn request_snapshot_at(&self, num: u64) { if let Err(e) = self.lock().send(ClientIoMessage::TakeSnapshot(num)) { warn!(target: "snapshot_watcher", "Snapshot watcher disconnected from IoService: {}", e); } else { @@ -138,7 +131,7 @@ impl ChainNotify for Watcher { .fold(0, ::std::cmp::max); if highest > 0 { - self.broadcast.take_at(Some(highest)); + self.broadcast.request_snapshot_at(highest); } } } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 36e31efce9e..126625f2153 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2556,7 +2556,8 @@ impl SnapshotClient for Client { let (actual_block_nr, block_hash) = match at { BlockId::Latest => { - // Start `self.history` blocks from the best block, but no further back than 1000 blocks. + // Start `self.history` blocks from the best block, but no further back than 1000 + // blocks (or earliest era, whichever is greatest). let history = cmp::min(self.history, 1000); let best_block_number = self.chain_info().best_block_number; let start_num = cmp::max(earliest_era, best_block_number.saturating_sub(history)); @@ -2579,6 +2580,7 @@ impl SnapshotClient for Client { trace!(target: "snapshot", "Snapshot requested at block {:?}. Using block #{}/{:?}. Earliest block: #{}, earliest state era #{}. Using {} threads.", at, actual_block_nr, block_hash, self.pruning_info().earliest_chain, earliest_era, processing_threads, ); + // Stop pruning from happening while the snapshot is under way. self.snapshotting_at.write().store(actual_block_nr, Ordering::SeqCst); { scopeguard::defer! {{ @@ -2586,6 +2588,7 @@ impl SnapshotClient for Client { self.snapshotting_at.write().store(0, Ordering::SeqCst) }}; let chunker = snapshot::chunker(self.engine.snapshot_mode()).ok_or_else(|| SnapshotError::SnapshotsUnsupported)?; + // Spawn threads and take snapshot snapshot::take_snapshot( chunker, &self.chain.read(), @@ -2598,8 +2601,6 @@ impl SnapshotClient for Client { Ok(()) } } - - } impl ImportExportBlocks for Client { From 4adc3e693403acc22a255a63be95aae3c2cc9627 Mon Sep 17 00:00:00 2001 From: David Palm Date: Fri, 18 Oct 2019 10:52:02 +0200 Subject: [PATCH 07/18] Let "in_progress" deletion fail Fix tests --- ethcore/snapshot/snapshot-tests/src/watcher.rs | 2 +- ethcore/snapshot/src/service.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/snapshot/snapshot-tests/src/watcher.rs b/ethcore/snapshot/snapshot-tests/src/watcher.rs index a5c8032d53d..95e932a2a35 100644 --- a/ethcore/snapshot/snapshot-tests/src/watcher.rs +++ b/ethcore/snapshot/snapshot-tests/src/watcher.rs @@ -42,7 +42,7 @@ impl Oracle for TestOracle { struct TestBroadcast(Option); impl Broadcast for TestBroadcast { fn request_snapshot_at(&self, num: u64) { - if num != self.0 { + if Some(num) != self.0 { panic!("Watcher broadcast wrong number. Expected {:?}, found {:?}", self.0, num); } } diff --git a/ethcore/snapshot/src/service.rs b/ethcore/snapshot/src/service.rs index f096d1129d6..bde95b8679d 100644 --- a/ethcore/snapshot/src/service.rs +++ b/ethcore/snapshot/src/service.rs @@ -510,7 +510,7 @@ impl Service where C: SnapshotClient + ChainInfo { let temp_dir = self.temp_snapshot_dir(); let snapshot_dir = self.snapshot_dir(); - let _ = fs::remove_dir_all(&temp_dir)?; + let _ = fs::remove_dir_all(&temp_dir); // expected to fail let writer = LooseWriter::new(temp_dir.clone())?; From c58b30bbd5bf0c77468ac1ccd52a452836bd20bc Mon Sep 17 00:00:00 2001 From: David Palm Date: Fri, 18 Oct 2019 11:31:50 +0200 Subject: [PATCH 08/18] Just use an atomic --- ethcore/src/client/client.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 126625f2153..3e85cbab390 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -205,7 +205,7 @@ pub struct Client { pruning: journaldb::Algorithm, /// Don't prune the state we're currently snapshotting - snapshotting_at: RwLock, + snapshotting_at: AtomicU64, /// Client uses this to store blocks, traces, etc. db: RwLock>, @@ -783,7 +783,7 @@ impl Client { tracedb, engine, pruning: config.pruning.clone(), - snapshotting_at: RwLock::new(AtomicU64::new(0)), + snapshotting_at: AtomicU64::new(0), db: RwLock::new(db.clone()), state_db: RwLock::new(state_db), report: RwLock::new(Default::default()), @@ -984,7 +984,7 @@ impl Client { match state_db.journal_db().earliest_era() { Some(earliest_era) if earliest_era + self.history <= latest_era => { - let freeze_at = self.snapshotting_at.read().load(Ordering::SeqCst); // todo[dvdplm]: can be `Acquire` I think? + let freeze_at = self.snapshotting_at.load(Ordering::SeqCst); // todo[dvdplm]: can be `Acquire` I think? if freeze_at > 0 && freeze_at == earliest_era { trace!(target: "pruning", "Pruning is freezed at era {}; earliest era={}, latest era={}, journal_size={}, mem_used={}. Not pruning.", freeze_at, earliest_era, latest_era, state_db.journal_db().journal_size(), state_db.journal_db().mem_used()); @@ -2581,11 +2581,11 @@ impl SnapshotClient for Client { at, actual_block_nr, block_hash, self.pruning_info().earliest_chain, earliest_era, processing_threads, ); // Stop pruning from happening while the snapshot is under way. - self.snapshotting_at.write().store(actual_block_nr, Ordering::SeqCst); + self.snapshotting_at.store(actual_block_nr, Ordering::SeqCst); { scopeguard::defer! {{ trace!(target: "snapshot", "(defer) Unfreezing pruning, setting snapshotting_at back to 0"); - self.snapshotting_at.write().store(0, Ordering::SeqCst) + self.snapshotting_at.store(0, Ordering::SeqCst) }}; let chunker = snapshot::chunker(self.engine.snapshot_mode()).ok_or_else(|| SnapshotError::SnapshotsUnsupported)?; // Spawn threads and take snapshot From 827cfb317d60b238da22226c4502cb04435e94e3 Mon Sep 17 00:00:00 2001 From: David Palm Date: Fri, 18 Oct 2019 12:02:59 +0200 Subject: [PATCH 09/18] Review grumbles --- ethcore/snapshot/src/service.rs | 9 ++------- parity/run.rs | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ethcore/snapshot/src/service.rs b/ethcore/snapshot/src/service.rs index bde95b8679d..d49efa8850b 100644 --- a/ethcore/snapshot/src/service.rs +++ b/ethcore/snapshot/src/service.rs @@ -515,16 +515,11 @@ impl Service where C: SnapshotClient + ChainInfo { let writer = LooseWriter::new(temp_dir.clone())?; let guard = Guard::new(temp_dir.clone()); - let res = client.take_snapshot(writer, BlockId::Number(num), &self.progress); - - if res.is_err() { - return res - } + let _ = client.take_snapshot(writer, BlockId::Number(num), &self.progress)?; info!("Finished taking snapshot at #{}, in {:#?}", num, start_time.elapsed()); - let mut reader = self.reader.write(); - // destroy the old snapshot reader. + let mut reader = self.reader.write(); *reader = None; if snapshot_dir.exists() { diff --git a/parity/run.rs b/parity/run.rs index 5492996646d..12fbd372936 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -73,7 +73,7 @@ use registrar::RegistrarClient; const SNAPSHOT_PERIOD: u64 = 50; // Start snapshots `history` blocks from the tip. - const SNAPSHOT_HISTORY: u64 = 100; +const SNAPSHOT_HISTORY: u64 = 100; // Number of minutes before a given gas price corpus should expire. // Light client only. From 1b04f40e22470d70802ff9ca339df25323f0f853 Mon Sep 17 00:00:00 2001 From: David Palm Date: Fri, 18 Oct 2019 13:07:22 +0200 Subject: [PATCH 10/18] Finish the sentence --- ethcore/snapshot/src/watcher.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/snapshot/src/watcher.rs b/ethcore/snapshot/src/watcher.rs index 4b33cd328cf..29f3af0c3b9 100644 --- a/ethcore/snapshot/src/watcher.rs +++ b/ethcore/snapshot/src/watcher.rs @@ -109,7 +109,7 @@ impl ChainNotify for Watcher { return } - // Decide if it's time for a snapshot: the highest of the imported blocks is . + // Decide if it's time for a snapshot: the highest of the imported blocks is a multiple of 5000? let highest = new_blocks.imported.into_iter() // Convert block hashes to block numbers for all newly imported blocks .filter_map(|h| self.oracle.to_number(h)) From bc7ba86707838f009f6d7c8b750c4f3d11f5cac3 Mon Sep 17 00:00:00 2001 From: David Palm Date: Sat, 19 Oct 2019 09:59:51 +0200 Subject: [PATCH 11/18] Resolve a few todos and clarify comments. --- ethcore/snapshot/src/watcher.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ethcore/snapshot/src/watcher.rs b/ethcore/snapshot/src/watcher.rs index 29f3af0c3b9..277e2548477 100644 --- a/ethcore/snapshot/src/watcher.rs +++ b/ethcore/snapshot/src/watcher.rs @@ -113,16 +113,9 @@ impl ChainNotify for Watcher { let highest = new_blocks.imported.into_iter() // Convert block hashes to block numbers for all newly imported blocks .filter_map(|h| self.oracle.to_number(h)) - // …only keep the new blocks that have numbers bigger than period + history - // todo: this seems nonsensical: period is always 5000 and history is always 100, so - // this filters out blocknumbers that are lower than 5100; what's the point of that? - .filter(|&num| num >= self.period + self.history) - // Subtract `history` (i.e. `SNAPSHOT_HISTORY`, i.e. 100) from the block numbers. - // todo: why? Here we back off 100 blocks such that the final block - // number from which we start the snapshot is "(new) highest block" - 100) - // Maybe we do this to avoid IO contention on the tip? Or for reorgs? If the - // latter, it should be maybe be higher? - .map(|num| num - self.history) + // Subtract `history` (i.e. `SNAPSHOT_HISTORY`, i.e. 100) from the block numbers to stay + // clear of reorgs. + .map(|num| num.saturating_sub(self.history) ) // …filter out blocks that do not fall on the a multiple of `period`. This regulates the // frequency of snapshots and ensures more snapshots are produced from similar points in // the chain. From d801a730ef71d6cc5217f378b670b1d8a05ef651 Mon Sep 17 00:00:00 2001 From: David Palm Date: Sat, 19 Oct 2019 10:06:34 +0200 Subject: [PATCH 12/18] Calculate progress rate since last update --- ethcore/snapshot/src/lib.rs | 7 ++-- ethcore/snapshot/src/service.rs | 10 +++-- ethcore/src/client/client.rs | 12 +++--- ethcore/src/client/config.rs | 2 +- ethcore/types/Cargo.toml | 3 +- ethcore/types/src/lib.rs | 1 + ethcore/types/src/snapshot.rs | 65 +++++++++++++++++++++++++++++---- parity/run.rs | 7 +++- parity/snapshot_cmd.rs | 4 +- 9 files changed, 85 insertions(+), 26 deletions(-) diff --git a/ethcore/snapshot/src/lib.rs b/ethcore/snapshot/src/lib.rs index 53716a909b8..406aeeddb93 100644 --- a/ethcore/snapshot/src/lib.rs +++ b/ethcore/snapshot/src/lib.rs @@ -168,7 +168,7 @@ pub fn take_snapshot( state_hashes.extend(part_state_hashes); } - debug!(target: "snapshot", "Took a snapshot of {} accounts", p.accounts.load(Ordering::SeqCst)); + info!("Took a snapshot at #{} of {} accounts", block_number, p.accounts()); Ok((state_hashes, block_hashes)) }).expect("Sub-thread never panics; qed")?; @@ -218,7 +218,7 @@ pub fn chunk_secondary<'a>( trace!(target: "snapshot", "wrote secondary chunk. hash: {:x}, size: {}, uncompressed size: {}", hash, size, raw_data.len()); - progress.size.fetch_add(size as u64, Ordering::SeqCst); + progress.update(0, size); chunk_hashes.push(hash); Ok(()) }; @@ -275,8 +275,7 @@ impl<'a> StateChunker<'a> { self.writer.lock().write_state_chunk(hash, compressed)?; trace!(target: "snapshot", "Thread {} wrote state chunk. size: {}, uncompressed size: {}", self.thread_idx, compressed_size, raw_data.len()); - self.progress.accounts.fetch_add(num_entries, Ordering::SeqCst); - self.progress.size.fetch_add(compressed_size as u64, Ordering::SeqCst); + self.progress.update(num_entries, compressed_size); self.hashes.push(hash); self.cur_size = 0; diff --git a/ethcore/snapshot/src/service.rs b/ethcore/snapshot/src/service.rs index d49efa8850b..da84482db71 100644 --- a/ethcore/snapshot/src/service.rs +++ b/ethcore/snapshot/src/service.rs @@ -39,7 +39,7 @@ use ethcore_io::IoChannel; use journaldb::Algorithm; use keccak_hash::keccak; use kvdb::DBTransaction; -use log::{error, info, trace, warn}; +use log::{debug, error, info, trace, warn}; use parking_lot::{Mutex, RwLock, RwLockReadGuard}; use snappy; use trie_db::TrieError; @@ -280,7 +280,7 @@ impl Service where C: SnapshotClient + ChainInfo { state_chunks: AtomicUsize::new(0), block_chunks: AtomicUsize::new(0), client: params.client, - progress: Default::default(), + progress: Progress::new(), taking_snapshot: AtomicBool::new(false), restoring_snapshot: AtomicBool::new(false), }; @@ -486,7 +486,9 @@ impl Service where C: SnapshotClient + ChainInfo { if self.progress.done() || !self.taking_snapshot.load(Ordering::SeqCst) { return } let p = &self.progress; - info!("Snapshot: {} accounts, {} blocks, {} bytes", p.accounts(), p.blocks(), p.size()); + info!("Snapshot: {} accounts, {} blocks, {} bytes", p.accounts(), p.blocks(), p.bytes()); + let rate = p.rate(); + debug!(target: "snapshot", "Current progress rate: {:.0} acc/s, {:.0} bytes/s (compressed)", rate.0, rate.1); } /// Take a snapshot at the block with the given number. @@ -516,7 +518,7 @@ impl Service where C: SnapshotClient + ChainInfo { let guard = Guard::new(temp_dir.clone()); let _ = client.take_snapshot(writer, BlockId::Number(num), &self.progress)?; - info!("Finished taking snapshot at #{}, in {:#?}", num, start_time.elapsed()); + info!("Finished taking snapshot at #{}, in {:.0?}", num, start_time.elapsed()); // destroy the old snapshot reader. let mut reader = self.reader.write(); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 3e85cbab390..2b140a1f214 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -973,8 +973,10 @@ impl Client { None => return Ok(()), }; - // prune all ancient eras until we're below the memory target, - // but have at least the minimum number of states, i.e. `history` . + // Prune all ancient eras until we're below the memory target (default: 32Mb), + // but have at least the minimum number of states, i.e. `history`. + // If a snapshot is under way, no pruning happens and memory consumption is allowed to + // increase above the memory target until the snapshot has finished. loop { let needs_pruning = state_db.journal_db().journal_size() >= self.config.history_mem; @@ -984,7 +986,7 @@ impl Client { match state_db.journal_db().earliest_era() { Some(earliest_era) if earliest_era + self.history <= latest_era => { - let freeze_at = self.snapshotting_at.load(Ordering::SeqCst); // todo[dvdplm]: can be `Acquire` I think? + let freeze_at = self.snapshotting_at.load(Ordering::SeqCst); if freeze_at > 0 && freeze_at == earliest_era { trace!(target: "pruning", "Pruning is freezed at era {}; earliest era={}, latest era={}, journal_size={}, mem_used={}. Not pruning.", freeze_at, earliest_era, latest_era, state_db.journal_db().journal_size(), state_db.journal_db().mem_used()); @@ -992,8 +994,8 @@ impl Client { } trace!(target: "pruning", "Pruning state for ancient era #{}; latest era={}, journal_size={}, mem_used={}.", earliest_era, latest_era, state_db.journal_db().journal_size(), state_db.journal_db().mem_used()); -// todo[dvdplm] reinstate this before merge, logging mem is expensive: -// trace!(target: "pruning", "Pruning state for ancient era #{}", earliest_era); + // todo[dvdplm] reinstate this before merge, logging mem is expensive: + // trace!(target: "pruning", "Pruning state for ancient era #{}", earliest_era); match chain.block_hash(earliest_era) { Some(ancient_hash) => { let mut batch = DBTransaction::new(); diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index 5a1c2b87e75..23104c48b56 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -90,7 +90,7 @@ pub struct ClientConfig { pub history: u64, /// Ideal memory usage for state pruning history. pub history_mem: usize, - /// Check seal valididity on block import + /// Check seal validity on block import pub check_seal: bool, /// Maximal number of transactions queued for verification in a separate thread. pub transaction_verification_queue_size: usize, diff --git a/ethcore/types/Cargo.toml b/ethcore/types/Cargo.toml index 4aa5d8b5dba..7a51f7e40d5 100644 --- a/ethcore/types/Cargo.toml +++ b/ethcore/types/Cargo.toml @@ -13,8 +13,9 @@ ethjson = { path = "../../json" } ethkey = { path = "../../accounts/ethkey" } keccak-hash = "0.4.0" parity-bytes = "0.1" -parity-util-mem = "0.2.0" parity-snappy = "0.1" +parity-util-mem = "0.2.0" +parking_lot = "0.9.0" patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" } rlp = "0.4.0" rlp_derive = { path = "../../util/rlp-derive" } diff --git a/ethcore/types/src/lib.rs b/ethcore/types/src/lib.rs index d78995d0c15..1e695005b69 100644 --- a/ethcore/types/src/lib.rs +++ b/ethcore/types/src/lib.rs @@ -40,6 +40,7 @@ extern crate ethkey; #[macro_use] extern crate derive_more; extern crate keccak_hash as hash; +extern crate parking_lot; extern crate parity_bytes as bytes; extern crate patricia_trie_ethereum as ethtrie; extern crate rlp; diff --git a/ethcore/types/src/snapshot.rs b/ethcore/types/src/snapshot.rs index ed305d68919..a3be631bebf 100644 --- a/ethcore/types/src/snapshot.rs +++ b/ethcore/types/src/snapshot.rs @@ -16,11 +16,13 @@ //! Snapshot type definitions -use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU64, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::time::Instant; +use bytes::Bytes; use ethereum_types::H256; +use parking_lot::RwLock; use rlp::{Rlp, RlpStream, DecoderError}; -use bytes::Bytes; /// Modes of snapshotting pub enum Snapshotting { @@ -39,31 +41,53 @@ pub enum Snapshotting { } /// A progress indicator for snapshots. -#[derive(Debug, Default)] +#[derive(Debug)] pub struct Progress { /// Number of accounts processed so far - pub accounts: AtomicUsize, + accounts: AtomicUsize, + // Number of accounts processed at last tick. + prev_accounts: AtomicUsize, /// Number of blocks processed so far pub blocks: AtomicUsize, /// Size in bytes of a all compressed chunks processed so far - pub size: AtomicU64, + bytes: AtomicUsize, + // Number of bytes processed at last tick. + prev_bytes: AtomicUsize, /// Signals that the snapshotting process is completed pub done: AtomicBool, /// Signal snapshotting process to abort pub abort: AtomicBool, + + last_tick: RwLock, } impl Progress { + /// Create a new progress tracker. + pub fn new() -> Progress { + Progress { + accounts: AtomicUsize::new(0), + prev_accounts: AtomicUsize::new(0), + blocks: AtomicUsize::new(0), + bytes: AtomicUsize::new(0), + prev_bytes: AtomicUsize::new(0), + abort: AtomicBool::new(false), + done: AtomicBool::new(false), + last_tick: RwLock::new(Instant::now()), + } + } + /// Reset the progress. pub fn reset(&self) { self.accounts.store(0, Ordering::Release); self.blocks.store(0, Ordering::Release); - self.size.store(0, Ordering::Release); + self.bytes.store(0, Ordering::Release); self.abort.store(false, Ordering::Release); // atomic fence here to ensure the others are written first? // logs might very rarely get polluted if not. self.done.store(false, Ordering::Release); + + *self.last_tick.write() = Instant::now(); } /// Get the number of accounts snapshotted thus far. @@ -73,10 +97,37 @@ impl Progress { pub fn blocks(&self) -> usize { self.blocks.load(Ordering::Acquire) } /// Get the written size of the snapshot in bytes. - pub fn size(&self) -> u64 { self.size.load(Ordering::Acquire) } + pub fn bytes(&self) -> usize { self.bytes.load(Ordering::Acquire) } /// Whether the snapshot is complete. pub fn done(&self) -> bool { self.done.load(Ordering::Acquire) } + + /// Return the progress rate over the last tick (i.e. since last update). + pub fn rate(&self) -> (f64, f64) { + let last_tick = *self.last_tick.read(); + let dt = last_tick.elapsed().as_secs_f64(); + if dt < 1.0 { + return (0f64, 0f64); + } + let delta_acc = self.accounts.load(Ordering::Relaxed) + .saturating_sub(self.prev_accounts.load(Ordering::Relaxed)); + let delta_bytes = self.bytes.load(Ordering::Relaxed) + .saturating_sub(self.prev_bytes.load(Ordering::Relaxed)); + (delta_acc as f64 / dt, delta_bytes as f64 / dt) + } + + /// Update state progress counters and set the last tick. + pub fn update(&self, accounts_delta: usize, bytes_delta: usize) { + *self.last_tick.write() = Instant::now(); + self.prev_accounts.store( + self.accounts.fetch_add(accounts_delta, Ordering::SeqCst), + Ordering::SeqCst + ); + self.prev_bytes.store( + self.bytes.fetch_add(bytes_delta, Ordering::SeqCst), + Ordering::SeqCst + ); + } } /// Manifest data. diff --git a/parity/run.rs b/parity/run.rs index 12fbd372936..9f3857aa65c 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -69,11 +69,14 @@ use db; use registrar::RegistrarClient; // How often we attempt to take a snapshot: only snapshot on blocknumbers that are multiples of this. +// todo[dvdplm] reinstate before merging // const SNAPSHOT_PERIOD: u64 = 5000; const SNAPSHOT_PERIOD: u64 = 50; -// Start snapshots `history` blocks from the tip. -const SNAPSHOT_HISTORY: u64 = 100; +// Start snapshots `history` blocks from the tip. Should be smaller than `SNAPSHOT_HISTORY`. +// todo[dvdplm] reinstate before merging +//const SNAPSHOT_HISTORY: u64 = 100; +const SNAPSHOT_HISTORY: u64 = 10; // Number of minutes before a given gas price corpus should expire. // Light client only. diff --git a/parity/snapshot_cmd.rs b/parity/snapshot_cmd.rs index e1c92bf29d6..8a9157ad62c 100644 --- a/parity/snapshot_cmd.rs +++ b/parity/snapshot_cmd.rs @@ -257,14 +257,14 @@ impl SnapshotCommand { let writer = PackedWriter::new(&file_path) .map_err(|e| format!("Failed to open snapshot writer: {}", e))?; - let progress = Arc::new(Progress::default()); + let progress = Arc::new(Progress::new()); let p = progress.clone(); let informant_handle = ::std::thread::spawn(move || { ::std::thread::sleep(Duration::from_secs(5)); let mut last_size = 0; while !p.done() { - let cur_size = p.size(); + let cur_size = p.bytes(); if cur_size != last_size { last_size = cur_size; let bytes = ::informant::format_bytes(cur_size as usize); From 20abe4a0d60f5eda7ee759fd761f4a2fa9ca43b3 Mon Sep 17 00:00:00 2001 From: David Palm Date: Sat, 19 Oct 2019 11:39:40 +0200 Subject: [PATCH 13/18] Lockfile --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 00c68d84079..4f49df53859 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -602,6 +602,7 @@ dependencies = [ "parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-snappy 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-util-mem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "patricia-trie-ethereum 0.1.0", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp_derive 0.1.0", From cf0c89f9f57aedc80104fbc3b14f61cd3c5c6724 Mon Sep 17 00:00:00 2001 From: David Palm Date: Sat, 19 Oct 2019 18:16:31 +0200 Subject: [PATCH 14/18] Fix tests --- ethcore/snapshot/snapshot-tests/src/account.rs | 12 ++++++------ ethcore/snapshot/snapshot-tests/src/helpers.rs | 5 +++-- ethcore/snapshot/snapshot-tests/src/proof_of_work.rs | 2 +- ethcore/snapshot/snapshot-tests/src/service.rs | 4 ++-- ethcore/snapshot/snapshot-tests/src/state.rs | 6 +++--- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ethcore/snapshot/snapshot-tests/src/account.rs b/ethcore/snapshot/snapshot-tests/src/account.rs index 09707c31156..fd1e5941bfa 100644 --- a/ethcore/snapshot/snapshot-tests/src/account.rs +++ b/ethcore/snapshot/snapshot-tests/src/account.rs @@ -48,7 +48,7 @@ fn encoding_basic() { let thin_rlp = ::rlp::encode(&account); assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); - let p = Progress::default(); + let p = Progress::new(); let fat_rlps = to_fat_rlps(&keccak(&addr), &account, &AccountDB::from_hash(db.as_hash_db(), keccak(addr)), &mut Default::default(), usize::max_value(), usize::max_value(), &p).unwrap(); let fat_rlp = Rlp::new(&fat_rlps[0]).at(1).unwrap(); assert_eq!(from_fat_rlp(&mut AccountDBMut::from_hash(db.as_hash_db_mut(), keccak(addr)), fat_rlp, H256::zero()).unwrap().0, account); @@ -69,7 +69,7 @@ fn encoding_version() { let thin_rlp = ::rlp::encode(&account); assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); - let p = Progress::default(); + let p = Progress::new(); let fat_rlps = to_fat_rlps(&keccak(&addr), &account, &AccountDB::from_hash(db.as_hash_db(), keccak(addr)), &mut Default::default(), usize::max_value(), usize::max_value(), &p).unwrap(); let fat_rlp = Rlp::new(&fat_rlps[0]).at(1).unwrap(); assert_eq!(from_fat_rlp(&mut AccountDBMut::from_hash(db.as_hash_db_mut(), keccak(addr)), fat_rlp, H256::zero()).unwrap().0, account); @@ -96,7 +96,7 @@ fn encoding_storage() { let thin_rlp = ::rlp::encode(&account); assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); - let p = Progress::default(); + let p = Progress::new(); let fat_rlp = to_fat_rlps(&keccak(&addr), &account, &AccountDB::from_hash(db.as_hash_db(), keccak(addr)), &mut Default::default(), usize::max_value(), usize::max_value(), &p).unwrap(); let fat_rlp = Rlp::new(&fat_rlp[0]).at(1).unwrap(); @@ -124,7 +124,7 @@ fn encoding_storage_split() { let thin_rlp = ::rlp::encode(&account); assert_eq!(::rlp::decode::(&thin_rlp).unwrap(), account); - let p = Progress::default(); + let p = Progress::new(); let fat_rlps = to_fat_rlps(&keccak(addr), &account, &AccountDB::from_hash(db.as_hash_db(), keccak(addr)), &mut Default::default(), 500, 1000, &p).unwrap(); let mut root = KECCAK_NULL_RLP; let mut restored_account = None; @@ -170,8 +170,8 @@ fn encoding_code() { }; let mut used_code = HashSet::new(); - let p1 = Progress::default(); - let p2 = Progress::default(); + let p1 = Progress::new(); + let p2 = Progress::new(); let fat_rlp1 = to_fat_rlps(&keccak(&addr1), &account1, &AccountDB::from_hash(db.as_hash_db(), keccak(addr1)), &mut used_code, usize::max_value(), usize::max_value(), &p1).unwrap(); let fat_rlp2 = to_fat_rlps(&keccak(&addr2), &account2, &AccountDB::from_hash(db.as_hash_db(), keccak(addr2)), &mut used_code, usize::max_value(), usize::max_value(), &p2).unwrap(); assert_eq!(used_code.len(), 1); diff --git a/ethcore/snapshot/snapshot-tests/src/helpers.rs b/ethcore/snapshot/snapshot-tests/src/helpers.rs index afc4979068d..0c419dd71bb 100644 --- a/ethcore/snapshot/snapshot-tests/src/helpers.rs +++ b/ethcore/snapshot/snapshot-tests/src/helpers.rs @@ -27,7 +27,8 @@ use client_traits::ChainInfo; use common_types::{ ids::BlockId, basic_account::BasicAccount, - errors::EthcoreError + errors::EthcoreError, + snapshot::Progress, }; use engine::Engine; use ethcore::client::Client; @@ -145,7 +146,7 @@ pub fn snap(client: &Client) -> (Box, TempDir) { let tempdir = TempDir::new("").unwrap(); let path = tempdir.path().join("file"); let writer = PackedWriter::new(&path).unwrap(); - let progress = Default::default(); + let progress = Progress::new(); let hash = client.chain_info().best_block_hash; client.take_snapshot(writer, BlockId::Hash(hash), &progress).unwrap(); diff --git a/ethcore/snapshot/snapshot-tests/src/proof_of_work.rs b/ethcore/snapshot/snapshot-tests/src/proof_of_work.rs index 81dcfe2cd5b..9d01432fff3 100644 --- a/ethcore/snapshot/snapshot-tests/src/proof_of_work.rs +++ b/ethcore/snapshot/snapshot-tests/src/proof_of_work.rs @@ -74,7 +74,7 @@ fn chunk_and_restore(amount: u64) { &bc, best_hash, &writer, - &Progress::default() + &Progress::new() ).unwrap(); let manifest = ManifestData { diff --git a/ethcore/snapshot/snapshot-tests/src/service.rs b/ethcore/snapshot/snapshot-tests/src/service.rs index b2e7a98256f..ebedd5472c9 100644 --- a/ethcore/snapshot/snapshot-tests/src/service.rs +++ b/ethcore/snapshot/snapshot-tests/src/service.rs @@ -278,7 +278,7 @@ fn keep_ancient_blocks() { &bc, best_hash, &writer, - &Progress::default() + &Progress::new() ).unwrap(); let state_db = client.state_db().journal_db().boxed_clone(); let start_header = bc.block_header_data(&best_hash).unwrap(); @@ -287,7 +287,7 @@ fn keep_ancient_blocks() { state_db.as_hash_db(), &state_root, &writer, - &Progress::default(), + &Progress::new(), None, 0 ).unwrap(); diff --git a/ethcore/snapshot/snapshot-tests/src/state.rs b/ethcore/snapshot/snapshot-tests/src/state.rs index 4cccd0d82e9..ef905796404 100644 --- a/ethcore/snapshot/snapshot-tests/src/state.rs +++ b/ethcore/snapshot/snapshot-tests/src/state.rs @@ -62,7 +62,7 @@ fn snap_and_restore() { let mut state_hashes = Vec::new(); for part in 0..SNAPSHOT_SUBPARTS { - let mut hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default(), Some(part), 0).unwrap(); + let mut hashes = chunk_state(&old_db, &state_root, &writer, &Progress::new(), Some(part), 0).unwrap(); state_hashes.append(&mut hashes); } @@ -133,7 +133,7 @@ fn get_code_from_prev_chunk() { let mut make_chunk = |acc, hash| { let mut db = journaldb::new_memory_db(); AccountDBMut::from_hash(&mut db, hash).insert(EMPTY_PREFIX, &code[..]); - let p = Progress::default(); + let p = Progress::new(); let fat_rlp = to_fat_rlps(&hash, &acc, &AccountDB::from_hash(&db, hash), &mut used_code, usize::max_value(), usize::max_value(), &p).unwrap(); let mut stream = RlpStream::new_list(1); stream.append_raw(&fat_rlp[0], 1); @@ -178,7 +178,7 @@ fn checks_flag() { let state_root = producer.state_root(); let writer = Mutex::new(PackedWriter::new(&snap_file).unwrap()); - let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::default(), None, 0).unwrap(); + let state_hashes = chunk_state(&old_db, &state_root, &writer, &Progress::new(), None, 0).unwrap(); writer.into_inner().finish(ManifestData { version: 2, From 3fcb56c5c6ae59ef3c4e62bce49008c2d368d71f Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 21 Oct 2019 13:16:25 +0200 Subject: [PATCH 15/18] typo --- ethcore/src/client/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 2b140a1f214..d3ee6bf85d5 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -988,7 +988,7 @@ impl Client { Some(earliest_era) if earliest_era + self.history <= latest_era => { let freeze_at = self.snapshotting_at.load(Ordering::SeqCst); if freeze_at > 0 && freeze_at == earliest_era { - trace!(target: "pruning", "Pruning is freezed at era {}; earliest era={}, latest era={}, journal_size={}, mem_used={}. Not pruning.", + trace!(target: "pruning", "Pruning is frozen at era {}; earliest era={}, latest era={}, journal_size={}, mem_used={}. Not pruning.", freeze_at, earliest_era, latest_era, state_db.journal_db().journal_size(), state_db.journal_db().mem_used()); break; } From f8e1c42d24ee494458eb65374f337d1496434547 Mon Sep 17 00:00:00 2001 From: David Palm Date: Tue, 22 Oct 2019 23:08:34 +0200 Subject: [PATCH 16/18] Reinstate default snapshotting frequency Cut down on the logging noise --- ethcore/snapshot/src/watcher.rs | 7 +------ ethcore/src/client/client.rs | 2 +- parity/run.rs | 8 ++------ 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/ethcore/snapshot/src/watcher.rs b/ethcore/snapshot/src/watcher.rs index 277e2548477..34ed5189bbd 100644 --- a/ethcore/snapshot/src/watcher.rs +++ b/ethcore/snapshot/src/watcher.rs @@ -102,12 +102,7 @@ impl Watcher { impl ChainNotify for Watcher { fn new_blocks(&self, new_blocks: NewBlocks) { - if self.oracle.is_major_importing() { - trace!(target: "snapshot_watcher", "Is major importing; not taking snapshot"); - } else if new_blocks.has_more_blocks_to_import { - trace!(target: "snapshot_watcher", "Has more blocks to import; not taking snapshot"); - return - } + if self.oracle.is_major_importing() || new_blocks.has_more_blocks_to_import { return } // Decide if it's time for a snapshot: the highest of the imported blocks is a multiple of 5000? let highest = new_blocks.imported.into_iter() diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index d3ee6bf85d5..643fe289f32 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2536,7 +2536,7 @@ impl ProvingBlockChainClient for Client { self.chain.read().get_pending_transition(hash).map(|pending| pending.proof) } } -// todo[dvdplm]: move snapshotting code to own module? + impl SnapshotClient for Client { fn take_snapshot( &self, diff --git a/parity/run.rs b/parity/run.rs index 9f3857aa65c..98781943134 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -69,14 +69,10 @@ use db; use registrar::RegistrarClient; // How often we attempt to take a snapshot: only snapshot on blocknumbers that are multiples of this. -// todo[dvdplm] reinstate before merging -// const SNAPSHOT_PERIOD: u64 = 5000; -const SNAPSHOT_PERIOD: u64 = 50; +const SNAPSHOT_PERIOD: u64 = 5000; // Start snapshots `history` blocks from the tip. Should be smaller than `SNAPSHOT_HISTORY`. -// todo[dvdplm] reinstate before merging -//const SNAPSHOT_HISTORY: u64 = 100; -const SNAPSHOT_HISTORY: u64 = 10; +const SNAPSHOT_HISTORY: u64 = 100; // Number of minutes before a given gas price corpus should expire. // Light client only. From 82ae2765e515ab21dbb07b58b867ac1fd2cd4438 Mon Sep 17 00:00:00 2001 From: David Palm Date: Wed, 23 Oct 2019 21:19:23 +0200 Subject: [PATCH 17/18] address grumble --- ethcore/src/client/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 643fe289f32..050072653ce 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -2586,7 +2586,7 @@ impl SnapshotClient for Client { self.snapshotting_at.store(actual_block_nr, Ordering::SeqCst); { scopeguard::defer! {{ - trace!(target: "snapshot", "(defer) Unfreezing pruning, setting snapshotting_at back to 0"); + trace!(target: "snapshot", "Re-enabling pruning."); self.snapshotting_at.store(0, Ordering::SeqCst) }}; let chunker = snapshot::chunker(self.engine.snapshot_mode()).ok_or_else(|| SnapshotError::SnapshotsUnsupported)?; From 4c8d5dc8112232f3acdcd452d643372eb93143a5 Mon Sep 17 00:00:00 2001 From: David Palm Date: Wed, 23 Oct 2019 21:26:40 +0200 Subject: [PATCH 18/18] Log memory use with `journal_size()` and explain why. --- ethcore/src/client/client.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 050072653ce..10df6078312 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -988,14 +988,15 @@ impl Client { Some(earliest_era) if earliest_era + self.history <= latest_era => { let freeze_at = self.snapshotting_at.load(Ordering::SeqCst); if freeze_at > 0 && freeze_at == earliest_era { - trace!(target: "pruning", "Pruning is frozen at era {}; earliest era={}, latest era={}, journal_size={}, mem_used={}. Not pruning.", - freeze_at, earliest_era, latest_era, state_db.journal_db().journal_size(), state_db.journal_db().mem_used()); + // Note: journal_db().mem_used() can be used for a more accurate memory + // consumption measurement but it can be expensive so sticking with the + // faster `journal_size()` instead. + trace!(target: "pruning", "Pruning is paused at era {} (snapshot under way); earliest era={}, latest era={}, journal_size={} – Not pruning.", + freeze_at, earliest_era, latest_era, state_db.journal_db().journal_size()); break; } - trace!(target: "pruning", "Pruning state for ancient era #{}; latest era={}, journal_size={}, mem_used={}.", - earliest_era, latest_era, state_db.journal_db().journal_size(), state_db.journal_db().mem_used()); - // todo[dvdplm] reinstate this before merge, logging mem is expensive: - // trace!(target: "pruning", "Pruning state for ancient era #{}", earliest_era); + trace!(target: "pruning", "Pruning state for ancient era #{}; latest era={}, journal_size={}", + earliest_era, latest_era, state_db.journal_db().journal_size()); match chain.block_hash(earliest_era) { Some(ancient_hash) => { let mut batch = DBTransaction::new();