From 6e97496b27f771620d69b159053863f92f4e9b82 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 11 Apr 2016 15:51:14 -0700 Subject: [PATCH] Support for --pruning=auto. --- parity/main.rs | 32 +++++++++++++++++++++++---- util/src/journaldb/archivedb.rs | 2 ++ util/src/journaldb/earlymergedb.rs | 2 ++ util/src/journaldb/overlayrecentdb.rs | 2 ++ util/src/journaldb/refcounteddb.rs | 21 ++++++++++++++++++ util/src/journaldb/traits.rs | 3 +++ 6 files changed, 58 insertions(+), 4 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index e2e4c9c37..af454a518 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -126,11 +126,11 @@ Networking Options: API and Console Options: -j --jsonrpc Enable the JSON-RPC API server. + --jsonrpc-port PORT Specify the port portion of the JSONRPC API server + [default: 8545]. --jsonrpc-interface IP Specify the hostname portion of the JSONRPC API server, IP should be an interface's IP address, or all (all interfaces) or local [default: local]. - --jsonrpc-port PORT Specify the port portion of the JSONRPC API server - [default: 8545]. --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. --jsonrpc-apis APIS Specify the APIs available through the JSONRPC @@ -169,8 +169,14 @@ Sealing/Mining Options: Footprint Options: --pruning METHOD Configure pruning of the state/storage trie. METHOD - may be one of: archive, basic (experimental), fast - (experimental) [default: archive]. + may be one of auto, archive, basic, fast, light: + archive - keep all state trie data. No pruning. + basic - reference count in disk DB. Slow but light. + fast - maintain journal overlay. Fast but 50MB used. + light - early merges with partial tracking. Fast + and light. Experimental! + auto - use the method most recently synced or + default to archive if none synced [default: auto]. --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. --cache-max-size BYTES Specify the maximum size of the blockchain cache in @@ -536,6 +542,23 @@ impl Configuration { ret } + fn find_best_db(path: &str) -> Option { + let mut ret = None; + let mut latest_era = None; + for i in [journaldb::Algorithm::Archive, journaldb::Algorithm::EarlyMerge, journaldb::Algorithm::OverlayRecent, journaldb::Algorithm::RefCounted].into_iter() { + let db = journaldb::new(path, i); + match (latest_era, db.latest_era()) { + (Some(best), Some(this)) if best >= this => {} + (_, None) => {} + (_, Some(this)) => { + latest_era = Some(this); + ret = Some(i); + } + } + } + ret + } + fn client_config(&self) -> ClientConfig { let mut client_config = ClientConfig::default(); match self.args.flag_cache { @@ -553,6 +576,7 @@ impl Configuration { "light" => journaldb::Algorithm::EarlyMerge, "fast" => journaldb::Algorithm::OverlayRecent, "basic" => journaldb::Algorithm::RefCounted, + "auto" => Self::find_best_db().unwrap_or(journaldb::Algorithm::OverlayRecent), _ => { die!("Invalid pruning method given."); } }; client_config.name = self.args.flag_identity.clone(); diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 380e8e423..8f112b18b 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -168,6 +168,8 @@ impl JournalDB for ArchiveDB { Ok((inserts + deletes) as u32) } + fn latest_era() -> Option { self.latest_era } + fn state(&self, id: &H256) -> Option { self.backing.get_by_prefix(&id.bytes()[0..12]).and_then(|b| Some(b.to_vec())) } diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index eada4bbaa..41bf78efa 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -333,6 +333,8 @@ impl JournalDB for EarlyMergeDB { self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() } + fn latest_era() -> Option { self.latest_era } + fn mem_used(&self) -> usize { self.overlay.mem_used() + match self.refs { Some(ref c) => c.read().unwrap().heap_size_of_children(), diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index 0b9ad4fda..e3adb3983 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -213,6 +213,8 @@ impl JournalDB for OverlayRecentDB { self.backing.get(&LATEST_ERA_KEY).expect("Low level database error").is_none() } + fn latest_era() -> Option { self.latest_era } + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // record new commit's details. trace!("commit: #{} ({}), end era: {:?}", now, id, end); diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index e69eccab7..ef74ce1cf 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -112,6 +112,8 @@ impl JournalDB for RefCountedDB { self.latest_era.is_none() } + fn latest_era() -> Option { self.latest_era } + fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result { // journal format: // [era, 0] => [ id, [insert_0, ...], [remove_0, ...] ] @@ -220,6 +222,25 @@ mod tests { assert!(!jdb.exists(&h)); } + #[test] + fn latest_era_should_work() { + // history is 3 + let mut jdb = RefCountedDB::new_temp(); + assert_eq!(jdb.latest_era(), None); + let h = jdb.insert(b"foo"); + jdb.commit(0, &b"0".sha3(), None).unwrap(); + assert_eq!(jdb.latest_era(), Some(0)); + jdb.remove(&h); + jdb.commit(1, &b"1".sha3(), None).unwrap(); + assert_eq!(jdb.latest_era(), Some(1)); + jdb.commit(2, &b"2".sha3(), None).unwrap(); + assert_eq!(jdb.latest_era(), Some(2)); + jdb.commit(3, &b"3".sha3(), Some((0, b"0".sha3()))).unwrap(); + assert_eq!(jdb.latest_era(), Some(3)); + jdb.commit(4, &b"4".sha3(), Some((1, b"1".sha3()))).unwrap(); + assert_eq!(jdb.latest_era(), Some(4)); + } + #[test] fn complex() { // history is 1 diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs index b1ba27957..87efcdaf8 100644 --- a/util/src/journaldb/traits.rs +++ b/util/src/journaldb/traits.rs @@ -31,6 +31,9 @@ pub trait JournalDB : HashDB + Send + Sync { /// Check if this database has any commits fn is_empty(&self) -> bool; + /// Get the latest era in the DB. None if there isn't yet any data in there. + fn latest_era() -> Option { self.latest_era } + /// Commit all recent insert operations and canonical historical commits' removals from the /// old era to the backing database, reverting any non-canonical historical commit's inserts. fn commit(&mut self, now: u64, id: &H256, end: Option<(u64, H256)>) -> Result;