This repository was archived by the owner on Nov 6, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Accounts bloom #2357
Merged
Merged
Accounts bloom #2357
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
5207927
proper bloom
NikVolf 5efc137
incremental bloom updates
NikVolf d2217f7
crate update
NikVolf dc95ee2
return of the column
NikVolf 82c08bd
fix n^2 byteorder write
NikVolf 1f7036e
add notes to funs
NikVolf 12abc31
working bloom commits
NikVolf c33e442
Optimizations
arkpar c45e992
bloom diag
NikVolf 260e75f
migration basic
NikVolf c2022fa
migration ongoing
NikVolf f3b094a
migration finalizing
NikVolf a55e108
mingration api workarounds
NikVolf ee36df0
fix test_client setups
NikVolf ee34d0e
snapshot bloom update
NikVolf 2db6e7e
review fixes
NikVolf 039c345
just forward keys in the migration
NikVolf 1bf7f46
migration extra tracing
NikVolf f4b5de8
fix migration path
NikVolf e25441d
remove close pray
NikVolf def6343
review issues
NikVolf File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| // Copyright 2015, 2016 Ethcore (UK) Ltd. | ||
| // This file is part of Parity. | ||
|
|
||
| // Parity is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // Parity is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with Parity. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| //! Bloom upgrade | ||
|
|
||
| use client::{DB_COL_EXTRA, DB_COL_HEADERS, DB_NO_OF_COLUMNS, DB_COL_STATE, DB_COL_ACCOUNT_BLOOM}; | ||
| use state_db::{ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET, StateDB, ACCOUNT_BLOOM_HASHCOUNT_KEY}; | ||
| use util::trie::TrieDB; | ||
| use views::HeaderView; | ||
| use bloomfilter::Bloom; | ||
| use util::migration::Error; | ||
| use util::journaldb; | ||
| use util::{H256, FixedHash, BytesConvertable}; | ||
| use util::{Database, DatabaseConfig, DBTransaction, CompactionProfile}; | ||
| use std::path::Path; | ||
|
|
||
| fn check_bloom_exists(db: &Database) -> bool { | ||
| let hash_count_entry = db.get(DB_COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY) | ||
| .expect("Low-level database error"); | ||
|
|
||
| hash_count_entry.is_some() | ||
| } | ||
|
|
||
| /// Account bloom upgrade routine. If bloom already present, does nothing. | ||
| /// If database empty (no best block), does nothing. | ||
| /// Can be called on upgraded database with no issues (will do nothing). | ||
| pub fn upgrade_account_bloom(db_path: &Path) -> Result<(), Error> { | ||
| let path = try!(db_path.to_str().ok_or(Error::MigrationImpossible)); | ||
| trace!(target: "migration", "Account bloom upgrade at {:?}", db_path); | ||
|
|
||
| let source = try!(Database::open(&DatabaseConfig { | ||
| max_open_files: 64, | ||
| cache_size: None, | ||
| compaction: CompactionProfile::default(), | ||
| columns: DB_NO_OF_COLUMNS, | ||
| wal: true, | ||
| }, path)); | ||
|
|
||
| let best_block_hash = match try!(source.get(DB_COL_EXTRA, b"best")) { | ||
| // no migration needed | ||
| None => { | ||
| trace!(target: "migration", "No best block hash, skipping"); | ||
| return Ok(()); | ||
| }, | ||
| Some(hash) => hash, | ||
| }; | ||
| let best_block_header = match try!(source.get(DB_COL_HEADERS, &best_block_hash)) { | ||
| // no best block, nothing to do | ||
| None => { | ||
| trace!(target: "migration", "No best block header, skipping"); | ||
| return Ok(()) | ||
| }, | ||
| Some(x) => x, | ||
| }; | ||
| let state_root = HeaderView::new(&best_block_header).state_root(); | ||
|
|
||
| if check_bloom_exists(&source) { | ||
| // bloom already exists, nothing to do | ||
| trace!(target: "migration", "Bloom already present, skipping"); | ||
| return Ok(()) | ||
| } | ||
|
|
||
| println!("Adding accounts bloom (one-time upgrade)"); | ||
| let db = ::std::sync::Arc::new(source); | ||
| let bloom_journal = { | ||
| let mut bloom = Bloom::new(ACCOUNT_BLOOM_SPACE, DEFAULT_ACCOUNT_PRESET); | ||
| // no difference what algorithm is passed, since there will be no writes | ||
| let state_db = journaldb::new( | ||
| db.clone(), | ||
| journaldb::Algorithm::OverlayRecent, | ||
| DB_COL_STATE); | ||
| let account_trie = try!(TrieDB::new(state_db.as_hashdb(), &state_root).map_err(|e| Error::Custom(format!("Cannot open trie: {:?}", e)))); | ||
| for (ref account_key, _) in account_trie.iter() { | ||
| let account_key_hash = H256::from_slice(&account_key); | ||
| bloom.set(account_key_hash.as_slice()); | ||
| } | ||
|
|
||
| bloom.drain_journal() | ||
| }; | ||
|
|
||
| trace!(target: "migration", "Generated {} bloom updates", bloom_journal.entries.len()); | ||
|
|
||
| let batch = DBTransaction::new(&db); | ||
| try!(StateDB::commit_bloom(&batch, bloom_journal).map_err(|_| Error::Custom("Failed to commit bloom".to_owned()))); | ||
| try!(db.write(batch)); | ||
|
|
||
| trace!(target: "migration", "Finished bloom update"); | ||
|
|
||
|
|
||
| Ok(()) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| // Copyright 2015, 2016 Ethcore (UK) Ltd. | ||
| // This file is part of Parity. | ||
|
|
||
| // Parity is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
|
|
||
| // Parity is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
|
|
||
| // You should have received a copy of the GNU General Public License | ||
| // along with Parity. If not, see <http://www.gnu.org/licenses/>. | ||
|
|
||
| //! This migration compresses the state db. | ||
|
|
||
| use util::migration::SimpleMigration; | ||
|
|
||
| /// Compressing migration. | ||
| #[derive(Default)] | ||
| pub struct ToV10; | ||
|
|
||
| impl SimpleMigration for ToV10 { | ||
| fn version(&self) -> u32 { | ||
| 10 | ||
| } | ||
|
|
||
| fn columns(&self) -> Option<u32> { Some(6) } | ||
|
|
||
| fn simple_migrate(&mut self, key: Vec<u8>, value: Vec<u8>) -> Option<(Vec<u8>, Vec<u8>)> { | ||
| Some((key, value)) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -259,9 +259,12 @@ impl State { | |
| /// Mutate storage of account `address` so that it is `value` for `key`. | ||
| pub fn storage_at(&self, address: &Address, key: &H256) -> H256 { | ||
| // Storage key search and update works like this: | ||
| // 1. If there's an entry for the account in the local cache check for the key and return it if found. | ||
| // 2. If there's an entry for the account in the global cache check for the key or load it into that account. | ||
| // 3. If account is missing in the global cache load it into the local cache and cache the key there. | ||
| // 1. Check bloom to see if account never used surely | ||
| // 2. If there's an entry for the account in the local cache check for the key and return it if found. | ||
| // 3. If there's an entry for the account in the global cache check for the key or load it into that account. | ||
| // 4. If account is missing in the global cache load it into the local cache and cache the key there. | ||
|
|
||
| // check bloom | ||
|
|
||
| // check local cache first without updating | ||
| { | ||
|
|
@@ -293,6 +296,7 @@ impl State { | |
| } | ||
| } | ||
| // account is not found in the global cache, get from the DB and insert into local | ||
| if !self.db.check_account_bloom(address) { return H256::zero() } | ||
| let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); | ||
| let maybe_acc = match db.get(address) { | ||
| Ok(acc) => acc.map(Account::from_rlp), | ||
|
|
@@ -387,6 +391,7 @@ impl State { | |
| for (address, ref mut a) in accounts.iter_mut() { | ||
| match a { | ||
| &mut&mut AccountEntry::Cached(ref mut account) if account.is_dirty() => { | ||
| db.note_account_bloom(&address); | ||
| let mut account_db = AccountDBMut::from_hash(db.as_hashdb_mut(), account.address_hash(address)); | ||
| account.commit_storage(trie_factory, &mut account_db); | ||
| account.commit_code(&mut account_db); | ||
|
|
@@ -449,6 +454,7 @@ impl State { | |
| pub fn populate_from(&mut self, accounts: PodState) { | ||
| assert!(self.snapshots.borrow().is_empty()); | ||
| for (add, acc) in accounts.drain().into_iter() { | ||
| self.db.note_account_bloom(&add); | ||
| self.cache.borrow_mut().insert(add, AccountEntry::Cached(Account::from_pod(acc))); | ||
| } | ||
| } | ||
|
|
@@ -525,6 +531,7 @@ impl State { | |
| Some(r) => r, | ||
| None => { | ||
| // not found in the global cache, get from the DB and insert into local | ||
| if !self.db.check_account_bloom(a) { return f(None); } | ||
| let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); | ||
| let mut maybe_acc = match db.get(a) { | ||
| Ok(acc) => acc.map(Account::from_rlp), | ||
|
|
@@ -559,11 +566,17 @@ impl State { | |
| Some(Some(acc)) => self.insert_cache(a, AccountEntry::Cached(acc)), | ||
| Some(None) => self.insert_cache(a, AccountEntry::Missing), | ||
| None => { | ||
| let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); | ||
| let maybe_acc = match db.get(a) { | ||
| Ok(Some(acc)) => AccountEntry::Cached(Account::from_rlp(acc)), | ||
| Ok(None) => AccountEntry::Missing, | ||
| Err(e) => panic!("Potential DB corruption encountered: {}", e), | ||
| let maybe_acc = if self.db.check_account_bloom(a) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this check can be saved just by caching the value of the previous query
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can't see how |
||
| let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); | ||
| let maybe_acc = match db.get(a) { | ||
| Ok(Some(acc)) => AccountEntry::Cached(Account::from_rlp(acc)), | ||
| Ok(None) => AccountEntry::Missing, | ||
| Err(e) => panic!("Potential DB corruption encountered: {}", e), | ||
| }; | ||
| maybe_acc | ||
| } | ||
| else { | ||
| AccountEntry::Missing | ||
| }; | ||
| self.insert_cache(a, maybe_acc); | ||
| } | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unsure if this can or can not happend concurrently
would be nice if @rphmeier review this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Becomes a non-issue if you switch the strategy to the one described in my other comment.
DBTransactionexists entirely outside of the rocksdb layer so it's safe itself, and thendb.writemay race against any other writes. Afaik the migrations are single-threaded so it probably shouldn't.