diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 60585d19f..4d1bec884 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -30,7 +30,7 @@ use blockchain::bloom_indexer::BloomIndexer; use blockchain::tree_route::TreeRoute; use blockchain::update::ExtrasUpdate; use blockchain::{CacheSize, ImportRoute}; -use db::{Writable, Readable, Key}; +use db::{Writable, Readable, Key, DatabaseReader, BatchWriter, CacheUpdatePolicy}; const BLOOM_INDEX_SIZE: usize = 16; const BLOOM_LEVELS: u8 = 3; @@ -183,7 +183,7 @@ impl BlockProvider for BlockChain { /// Returns true if the given block is known /// (though not necessarily a part of the canon chain). fn is_known(&self, hash: &H256) -> bool { - self.query_extras_exist(hash, &self.block_details) + DatabaseReader::new(&self.extras_db, &self.block_details).exists(hash) } // We do not store tracing information. @@ -466,28 +466,25 @@ impl BlockChain { batch.put(b"best", &update.info.hash).unwrap(); { - let mut write_details = self.block_details.write().unwrap(); - for (hash, details) in update.block_details.into_iter() { - batch.write(&hash, &details); - self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone())); - write_details.insert(hash, details); + for hash in update.block_details.keys().cloned() { + self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash)); } + + let mut write_details = self.block_details.write().unwrap(); + BatchWriter::new(&batch, &mut write_details) + .extend(update.block_details, CacheUpdatePolicy::Overwrite); } { let mut write_receipts = self.block_receipts.write().unwrap(); - for (hash, receipt) in &update.block_receipts { - batch.write(hash, receipt); - write_receipts.remove(hash); - } + BatchWriter::new(&batch, &mut write_receipts) + .extend(update.block_receipts, CacheUpdatePolicy::Remove); } { let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); - for (bloom_hash, blocks_bloom) in &update.blocks_blooms { - batch.write(bloom_hash, blocks_bloom); - write_blocks_blooms.remove(bloom_hash); - } + BatchWriter::new(&batch, &mut write_blocks_blooms) + .extend(update.blocks_blooms, CacheUpdatePolicy::Remove); } // These cached values must be updated last and togeterh @@ -508,15 +505,11 @@ impl BlockChain { } } - for (number, hash) in &update.block_hashes { - batch.write(number, hash); - write_hashes.remove(number); - } + BatchWriter::new(&batch, &mut write_hashes) + .extend(update.block_hashes, CacheUpdatePolicy::Remove); - for (hash, tx_address) in &update.transactions_addresses { - batch.write(hash, tx_address); - write_txs.remove(hash); - } + BatchWriter::new(&batch, &mut write_txs) + .extend(update.transactions_addresses, CacheUpdatePolicy::Remove); // update extras database self.extras_db.write(batch).unwrap(); @@ -751,32 +744,8 @@ impl BlockChain { T: ExtrasIndexable + Clone + Decodable, K: Key + Eq + Hash + Clone, H256: From { - { - let read = cache.read().unwrap(); - if let Some(v) = read.get(hash) { - return Some(v.clone()); - } - } - self.note_used(CacheID::Extras(T::index(), H256::from(hash.clone()))); - - self.extras_db.read(hash).map(|t: T| { - let mut write = cache.write().unwrap(); - write.insert(hash.clone(), t.clone()); - t - }) - } - - fn query_extras_exist(&self, hash: &K, cache: &RwLock>) -> bool where - K: Key + Eq + Hash + Clone { - { - let read = cache.read().unwrap(); - if let Some(_) = read.get(hash) { - return true; - } - } - - self.extras_db.exists::(hash) + DatabaseReader::new(&self.extras_db, cache).read(hash) } /// Get current cache size. diff --git a/ethcore/src/db.rs b/ethcore/src/db/db.rs similarity index 100% rename from ethcore/src/db.rs rename to ethcore/src/db/db.rs diff --git a/ethcore/src/db/mod.rs b/ethcore/src/db/mod.rs new file mode 100644 index 000000000..199614b79 --- /dev/null +++ b/ethcore/src/db/mod.rs @@ -0,0 +1,23 @@ +// 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 . + +pub mod db; +mod reader; +mod writer; + +pub use self::db::{Key, Writable, Readable}; +pub use self::reader::DatabaseReader; +pub use self::writer::{BatchWriter, CacheUpdatePolicy}; diff --git a/ethcore/src/db/reader.rs b/ethcore/src/db/reader.rs new file mode 100644 index 000000000..4e4755b11 --- /dev/null +++ b/ethcore/src/db/reader.rs @@ -0,0 +1,65 @@ +// 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 . + +use std::hash::Hash; +use std::sync::RwLock; +use std::collections::HashMap; +use util::Database; +use util::rlp::Decodable; +use super::{Readable, Key}; + +pub struct DatabaseReader<'a, K, V> where K: 'a, V: 'a { + db: &'a Database, + cache: &'a RwLock>, +} + +impl<'a, K, V> DatabaseReader<'a, K, V> { + pub fn new(db: &'a Database, cache: &'a RwLock>) -> Self { + DatabaseReader { + db: db, + cache: cache, + } + } + + pub fn read(&self, key: &K) -> Option where + K: Eq + Hash + Clone + Key, + V: Clone + Decodable { + { + let read = self.cache.read().unwrap(); + if let Some(v) = read.get(key) { + return Some(v.clone()); + } + } + + self.db.read(key).map(|value: V|{ + let mut write = self.cache.write().unwrap(); + write.insert(key.clone(), value.clone()); + value + }) + } + + pub fn exists(&self, key: &K) -> bool where + K: Eq + Hash + Key { + { + let read = self.cache.read().unwrap(); + if read.get(key).is_some() { + return true; + } + } + + self.db.exists::(key) + } +} diff --git a/ethcore/src/db/writer.rs b/ethcore/src/db/writer.rs new file mode 100644 index 000000000..35658eadc --- /dev/null +++ b/ethcore/src/db/writer.rs @@ -0,0 +1,60 @@ +// 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 . + +use std::collections::HashMap; +use std::hash::Hash; +use util::DBTransaction; +use util::rlp::Encodable; +use super::{Key, Writable}; + +#[derive(Clone, Copy)] +pub enum CacheUpdatePolicy { + Overwrite, + Remove, +} + +pub struct BatchWriter<'a, K, V> where K: 'a, V: 'a { + batch: &'a DBTransaction, + cache: &'a mut HashMap, +} + +impl<'a, K, V> BatchWriter<'a, K, V> { + pub fn new(batch: &'a DBTransaction, cache: &'a mut HashMap) -> Self { + BatchWriter { + batch: batch, + cache: cache, + } + } + + pub fn extend(&mut self, map: HashMap, policy: CacheUpdatePolicy) where + K: Key + Hash + Eq, + V: Encodable { + match policy { + CacheUpdatePolicy::Overwrite => { + for (key, value) in map.into_iter() { + self.batch.write(&key, &value); + self.cache.insert(key, value); + } + }, + CacheUpdatePolicy::Remove => { + for (key, value) in &map { + self.batch.write(key, value); + self.cache.remove(key); + } + }, + } + } +}