Commit 458afcd2 authored by Marek Kotewicz's avatar Marek Kotewicz Committed by Afri Schoedon
Browse files

new blooms database (#8712)

* new blooms database

* fixed conflict in Cargo.lock

* removed bloomchain

* cleanup in progress

* all tests passing in trace db with new blooms-db

* added trace_blooms to BlockChainDB interface, fixed db flushing

* BlockChainDB no longer exposes RwLock in the interface

* automatically flush blooms-db after every insert

* blooms-db uses io::BufReader to read files, wrap blooms-db into Mutex, cause fs::File is just a shared file handle

* fix json_tests

* blooms-db can filter multiple possibilities at the same time

* removed enum trace/db.rs CacheId

* lint fixes

* fixed tests

* kvdb-rocksdb uses fs-swap crate

* update Cargo.lock

* use fs::rename

* fixed failing test on linux

* fix tests

* use fs_swap

* fixed failing test on linux

* cleanup after swap

* fix tests

* fixed osx permissions

* simplify parity database opening functions

* added migration to blooms-db

* address @niklasad1 grumbles

* fix license and authors field of blooms-db Cargo.toml

* restore blooms-db after snapshot
parent cf5ae81c
......@@ -151,12 +151,14 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bloomchain"
version = "0.2.0"
name = "blooms-db"
version = "0.1.0"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 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)",
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -512,7 +514,7 @@ name = "ethcore"
version = "1.12.0"
dependencies = [
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bloomchain 0.2.0",
"blooms-db 0.1.0",
"bn 0.4.4 (git+https://github.com/paritytech/bn)",
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"common-types 0.1.0",
......@@ -1112,6 +1114,15 @@ name = "fnv"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fs-swap"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
......@@ -1500,6 +1511,7 @@ version = "0.1.0"
dependencies = [
"elastic-array 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"fs-swap 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"interleaved-ordered 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"kvdb 0.1.0",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -1980,6 +1992,7 @@ version = "1.12.0"
dependencies = [
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"blooms-db 0.1.0",
"clap 2.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)",
"daemonize 0.2.3 (git+https://github.com/paritytech/daemonize)",
......@@ -3855,6 +3868,7 @@ dependencies = [
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909"
"checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
"checksum fs-swap 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "18c72c2e124a7f8cf6966d72143940885a0936f30cabe807001552126a50737d"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
......
......@@ -7,6 +7,7 @@ license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
blooms-db = { path = "util/blooms-db" }
log = "0.3"
env_logger = "0.4"
rustc-hex = "1.0"
......
......@@ -8,7 +8,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
ansi_term = "0.10"
bloomchain = { path = "../util/bloomchain" }
blooms-db = { path = "../util/blooms-db" }
bn = { git = "https://github.com/paritytech/bn", default-features = false }
byteorder = "1.0"
common-types = { path = "types" }
......@@ -67,11 +67,11 @@ keccak-hash = { path = "../util/hash" }
triehash = { path = "../util/triehash" }
unexpected = { path = "../util/unexpected" }
journaldb = { path = "../util/journaldb" }
tempdir = "0.3"
kvdb-rocksdb = { path = "../util/kvdb-rocksdb" }
[dev-dependencies]
tempdir = "0.3"
trie-standardmap = { path = "../util/trie-standardmap" }
kvdb-rocksdb = { path = "../util/kvdb-rocksdb" }
[features]
# Display EVM debug traces.
......
......@@ -21,11 +21,10 @@ use std::fmt;
use std::sync::Arc;
use ethcore::client::ClientIoMessage;
use ethcore::db;
use ethcore::{db, BlockChainDB};
use ethcore::error::Error as CoreError;
use ethcore::spec::Spec;
use io::{IoContext, IoError, IoHandler, IoService};
use kvdb::KeyValueDB;
use cache::Cache;
use parking_lot::Mutex;
......@@ -65,11 +64,10 @@ pub struct Service<T> {
impl<T: ChainDataFetcher> Service<T> {
/// Start the service: initialize I/O workers and client itself.
pub fn start(config: ClientConfig, spec: &Spec, fetcher: T, db: Arc<KeyValueDB>, cache: Arc<Mutex<Cache>>) -> Result<Self, Error> {
pub fn start(config: ClientConfig, spec: &Spec, fetcher: T, db: Arc<BlockChainDB>, cache: Arc<Mutex<Cache>>) -> Result<Self, Error> {
let io_service = IoService::<ClientIoMessage>::start().map_err(Error::Io)?;
let client = Arc::new(Client::new(config,
db,
db.key_value().clone(),
db::COL_LIGHT_CHAIN,
spec,
fetcher,
......@@ -122,12 +120,11 @@ mod tests {
use client::fetch;
use std::time::Duration;
use parking_lot::Mutex;
use kvdb_memorydb;
use ethcore::db::NUM_COLUMNS;
use ethcore::test_helpers;
#[test]
fn it_works() {
let db = Arc::new(kvdb_memorydb::create(NUM_COLUMNS.unwrap_or(0)));
let db = test_helpers::new_db();
let spec = Spec::new_test();
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600))));
......
......@@ -115,6 +115,7 @@ mod test {
use ethcore::spec::Spec;
use ethcore::client::{BlockChainClient, Client, ClientConfig};
use ethcore::miner::Miner;
use ethcore::test_helpers;
use network::{ConnectionDirection, ConnectionFilter, NodeId};
use io::IoChannel;
use super::NodeFilter;
......@@ -127,7 +128,7 @@ mod test {
let data = include_bytes!("../res/node_filter.json");
let tempdir = TempDir::new("").unwrap();
let spec = Spec::load(&tempdir.path(), &data[..]).unwrap();
let client_db = Arc::new(::kvdb_memorydb::create(::ethcore::db::NUM_COLUMNS.unwrap_or(0)));
let client_db = test_helpers::new_db();
let client = Client::new(
ClientConfig::default(),
......
......@@ -22,10 +22,10 @@ use std::time::Duration;
use ansi_term::Colour;
use io::{IoContext, TimerToken, IoHandler, IoService, IoError};
use kvdb::{KeyValueDB, KeyValueDBHandler};
use stop_guard::StopGuard;
use sync::PrivateTxHandler;
use ethcore::{BlockChainDB, BlockChainDBHandler};
use ethcore::client::{Client, ClientConfig, ChainNotify, ClientIoMessage};
use ethcore::miner::Miner;
use ethcore::snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams};
......@@ -69,7 +69,7 @@ pub struct ClientService {
client: Arc<Client>,
snapshot: Arc<SnapshotService>,
private_tx: Arc<PrivateTxService>,
database: Arc<KeyValueDB>,
database: Arc<BlockChainDB>,
_stop_guard: StopGuard,
}
......@@ -78,9 +78,9 @@ impl ClientService {
pub fn start(
config: ClientConfig,
spec: &Spec,
client_db: Arc<KeyValueDB>,
blockchain_db: Arc<BlockChainDB>,
snapshot_path: &Path,
restoration_db_handler: Box<KeyValueDBHandler>,
restoration_db_handler: Box<BlockChainDBHandler>,
_ipc_path: &Path,
miner: Arc<Miner>,
account_provider: Arc<AccountProvider>,
......@@ -93,7 +93,7 @@ impl ClientService {
info!("Configured for {} using {} engine", Colour::White.bold().paint(spec.name.clone()), Colour::Yellow.bold().paint(spec.engine.name()));
let pruning = config.pruning;
let client = Client::new(config, &spec, client_db.clone(), miner.clone(), io_service.channel())?;
let client = Client::new(config, &spec, blockchain_db.clone(), miner.clone(), io_service.channel())?;
let snapshot_params = SnapServiceParams {
engine: spec.engine.clone(),
......@@ -131,7 +131,7 @@ impl ClientService {
client: client,
snapshot: snapshot,
private_tx,
database: client_db,
database: blockchain_db,
_stop_guard: stop_guard,
})
}
......@@ -167,7 +167,7 @@ impl ClientService {
}
/// Get a handle to the database.
pub fn db(&self) -> Arc<KeyValueDB> { self.database.clone() }
pub fn db(&self) -> Arc<BlockChainDB> { self.database.clone() }
/// Shutdown the Client Service
pub fn shutdown(&self) {
......@@ -259,8 +259,8 @@ mod tests {
use ethcore::miner::Miner;
use ethcore::spec::Spec;
use ethcore::db::NUM_COLUMNS;
use kvdb::Error;
use kvdb_rocksdb::{Database, DatabaseConfig, CompactionProfile};
use ethcore::test_helpers;
use kvdb_rocksdb::{DatabaseConfig, CompactionProfile};
use super::*;
use ethcore_private_tx;
......@@ -278,24 +278,9 @@ mod tests {
client_db_config.compaction = CompactionProfile::auto(&client_path);
client_db_config.wal = client_config.db_wal;
let client_db = Arc::new(Database::open(
&client_db_config,
&client_path.to_str().expect("DB path could not be converted to string.")
).unwrap());
struct RestorationDBHandler {
config: DatabaseConfig,
}
impl KeyValueDBHandler for RestorationDBHandler {
fn open(&self, db_path: &Path) -> Result<Arc<KeyValueDB>, Error> {
Ok(Arc::new(Database::open(&self.config, &db_path.to_string_lossy())?))
}
}
let restoration_db_handler = Box::new(RestorationDBHandler {
config: client_db_config,
});
let client_db_handler = test_helpers::restoration_db_handler(client_db_config.clone());
let client_db = client_db_handler.open(&client_path).unwrap();
let restoration_db_handler = test_helpers::restoration_db_handler(client_db_config);
let spec = Spec::new_test();
let service = ClientService::start(
......
......@@ -16,13 +16,13 @@
//! Blockchain database.
use std::collections::{HashMap, HashSet, hash_map};
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::mem;
use itertools::Itertools;
use bloomchain as bc;
use blooms_db;
use heapsize::HeapSizeOf;
use ethereum_types::{H256, Bloom, U256};
use ethereum_types::{H256, Bloom, BloomRef, U256};
use parking_lot::{Mutex, RwLock};
use bytes::Bytes;
use rlp::RlpStream;
......@@ -32,7 +32,6 @@ use transaction::*;
use views::{BlockView, HeaderView};
use log_entry::{LogEntry, LocalizedLogEntry};
use receipt::Receipt;
use blooms::{BloomGroup, GroupPosition};
use blockchain::best_block::{BestBlock, BestAncientBlock};
use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData};
use blockchain::extras::{BlockReceipts, BlockDetails, TransactionAddress, EPOCH_KEY_PREFIX, EpochTransitions};
......@@ -48,9 +47,27 @@ use engines::epoch::{Transition as EpochTransition, PendingTransition as Pending
use rayon::prelude::*;
use ansi_term::Colour;
use kvdb::{DBTransaction, KeyValueDB};
use error::Error;
use std::path::Path;
const LOG_BLOOMS_LEVELS: usize = 3;
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
/// Database backing `BlockChain`.
pub trait BlockChainDB: Send + Sync {
/// Generic key value store.
fn key_value(&self) -> &Arc<KeyValueDB>;
/// Header blooms database.
fn blooms(&self) -> &blooms_db::Database;
/// Trace blooms database.
fn trace_blooms(&self) -> &blooms_db::Database;
}
/// Generic database handler. This trait contains one function `open`. When called, it opens database with a
/// predefined config.
pub trait BlockChainDBHandler: Send + Sync {
/// Open the predefined key-value database.
fn open(&self, path: &Path) -> Result<Arc<BlockChainDB>, Error>;
}
/// Interface for querying blocks by hash and by number.
pub trait BlockProvider {
......@@ -152,7 +169,12 @@ pub trait BlockProvider {
}
/// Returns numbers of blocks containing given bloom.
fn blocks_with_bloom(&self, bloom: &Bloom, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber>;
fn blocks_with_bloom<'a, B, I, II>(&self, blooms: II, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber>
where
BloomRef<'a>: From<B>,
II: IntoIterator<Item = B, IntoIter = I> + Copy,
I: Iterator<Item = B>,
Self: Sized;
/// Returns logs matching given filter.
fn logs<F>(&self, blocks: Vec<H256>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
......@@ -166,26 +188,14 @@ enum CacheId {
BlockDetails(H256),
BlockHashes(BlockNumber),
TransactionAddresses(H256),
BlocksBlooms(GroupPosition),
BlockReceipts(H256),
}
impl bc::group::BloomGroupDatabase for BlockChain {
fn blooms_at(&self, position: &bc::group::GroupPosition) -> Option<bc::group::BloomGroup> {
let position = GroupPosition::from(position.clone());
let result = self.db.read_with_cache(db::COL_EXTRA, &self.blocks_blooms, &position).map(Into::into);
self.cache_man.lock().note_used(CacheId::BlocksBlooms(position));
result
}
}
/// Structure providing fast access to blockchain data.
///
/// **Does not do input data verification.**
pub struct BlockChain {
// All locks must be captured in the order declared here.
blooms_config: bc::Config,
best_block: RwLock<BestBlock>,
// Stores best block of the first uninterrupted sequence of blocks. `None` if there are no gaps.
// Only updated with `insert_unordered_block`.
......@@ -202,10 +212,9 @@ pub struct BlockChain {
block_details: RwLock<HashMap<H256, BlockDetails>>,
block_hashes: RwLock<HashMap<BlockNumber, H256>>,
transaction_addresses: RwLock<HashMap<H256, TransactionAddress>>,
blocks_blooms: RwLock<HashMap<GroupPosition, BloomGroup>>,
block_receipts: RwLock<HashMap<H256, BlockReceipts>>,
db: Arc<KeyValueDB>,
db: Arc<BlockChainDB>,
cache_man: Mutex<CacheManager<CacheId>>,
......@@ -219,7 +228,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.db.exists_with_cache(db::COL_EXTRA, &self.block_details, hash)
self.db.key_value().exists_with_cache(db::COL_EXTRA, &self.block_details, hash)
}
fn first_block(&self) -> Option<H256> {
......@@ -260,7 +269,7 @@ impl BlockProvider for BlockChain {
}
// Read from DB and populate cache
let b = self.db.get(db::COL_HEADERS, hash)
let b = self.db.key_value().get(db::COL_HEADERS, hash)
.expect("Low level database error. Some issue with disk?")?;
let header = encoded::Header::new(decompress(&b, blocks_swapper()).into_vec());
......@@ -290,7 +299,7 @@ impl BlockProvider for BlockChain {
}
// Read from DB and populate cache
let b = self.db.get(db::COL_BODIES, hash)
let b = self.db.key_value().get(db::COL_BODIES, hash)
.expect("Low level database error. Some issue with disk?")?;
let body = encoded::Body::new(decompress(&b, blocks_swapper()).into_vec());
......@@ -303,40 +312,41 @@ impl BlockProvider for BlockChain {
/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_details, hash)?;
let result = self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_details, hash)?;
self.cache_man.lock().note_used(CacheId::BlockDetails(*hash));
Some(result)
}
/// Get the hash of given block's number.
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_hashes, &index)?;
let result = self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_hashes, &index)?;
self.cache_man.lock().note_used(CacheId::BlockHashes(index));
Some(result)
}
/// Get the address of transaction with given hash.
fn transaction_address(&self, hash: &H256) -> Option<TransactionAddress> {
let result = self.db.read_with_cache(db::COL_EXTRA, &self.transaction_addresses, hash)?;
let result = self.db.key_value().read_with_cache(db::COL_EXTRA, &self.transaction_addresses, hash)?;
self.cache_man.lock().note_used(CacheId::TransactionAddresses(*hash));
Some(result)
}
/// Get receipts of block with given hash.
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
let result = self.db.read_with_cache(db::COL_EXTRA, &self.block_receipts, hash)?;
let result = self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_receipts, hash)?;
self.cache_man.lock().note_used(CacheId::BlockReceipts(*hash));
Some(result)
}
/// Returns numbers of blocks containing given bloom.
fn blocks_with_bloom(&self, bloom: &Bloom, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber> {
let range = from_block as bc::Number..to_block as bc::Number;
let chain = bc::group::BloomGroupChain::new(self.blooms_config, self);
chain.with_bloom(&range, bloom)
.into_iter()
.map(|b| b as BlockNumber)
.collect()
fn blocks_with_bloom<'a, B, I, II>(&self, blooms: II, from_block: BlockNumber, to_block: BlockNumber) -> Vec<BlockNumber>
where
BloomRef<'a>: From<B>,
II: IntoIterator<Item = B, IntoIter = I> + Copy,
I: Iterator<Item = B> {
self.db.blooms()
.filter(from_block, to_block, blooms)
.expect("Low level database error. Some issue with disk?")
}
/// Returns logs matching given filter. The order of logs returned will be the same as the order of the blocks
......@@ -498,15 +508,11 @@ impl<'a> Iterator for EpochTransitionIter<'a> {
impl BlockChain {
/// Create new instance of blockchain from given Genesis.
pub fn new(config: Config, genesis: &[u8], db: Arc<KeyValueDB>) -> BlockChain {
pub fn new(config: Config, genesis: &[u8], db: Arc<BlockChainDB>) -> BlockChain {
// 400 is the average size of the key
let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400);
let mut bc = BlockChain {
blooms_config: bc::Config {
levels: LOG_BLOOMS_LEVELS,
elements_per_index: LOG_BLOOMS_ELEMENTS_PER_INDEX,
},
first_block: None,
best_block: RwLock::new(BestBlock {
// BestBlock will be overwritten anyway.
......@@ -520,7 +526,6 @@ impl BlockChain {
block_details: RwLock::new(HashMap::new()),
block_hashes: RwLock::new(HashMap::new()),
transaction_addresses: RwLock::new(HashMap::new()),
blocks_blooms: RwLock::new(HashMap::new()),
block_receipts: RwLock::new(HashMap::new()),
db: db.clone(),
cache_man: Mutex::new(cache_man),
......@@ -531,7 +536,7 @@ impl BlockChain {
};
// load best block
let best_block_hash = match bc.db.get(db::COL_EXTRA, b"best").unwrap() {
let best_block_hash = match bc.db.key_value().get(db::COL_EXTRA, b"best").unwrap() {
Some(best) => {
H256::from_slice(&best)
}
......@@ -559,7 +564,7 @@ impl BlockChain {
batch.write(db::COL_EXTRA, &header.number(), &hash);
batch.put(db::COL_EXTRA, b"best", &hash);
bc.db.write(batch).expect("Low level database error. Some issue with disk?");
bc.db.key_value().write(batch).expect("Low level database error. Some issue with disk?");
hash
}
};
......@@ -581,8 +586,8 @@ impl BlockChain {
{
let best_block_number = bc.best_block.read().header.number();
// Fetch first and best ancient block details
let raw_first = bc.db.get(db::COL_EXTRA, b"first").unwrap().map(|v| v.into_vec());
let mut best_ancient = bc.db.get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
let raw_first = bc.db.key_value().get(db::COL_EXTRA, b"first").unwrap().map(|v| v.into_vec());
let mut best_ancient = bc.db.key_value().get(db::COL_EXTRA, b"ancient").unwrap().map(|h| H256::from_slice(&h));
let best_ancient_number;
if best_ancient.is_none() && best_block_number > 1 && bc.block_hash(1).is_none() {
best_ancient = Some(bc.genesis_hash());
......@@ -611,9 +616,9 @@ impl BlockChain {
if hash != bc.genesis_hash() {
trace!("First block calculated: {:?}", hash);
let mut batch = db.transaction();
let mut batch = db.key_value().transaction();
batch.put(db::COL_EXTRA, b"first", &hash);
db.write(batch).expect("Low level database error.");
db.key_value().write(batch).expect("Low level database error.");
bc.first_block = Some(hash);
}
},
......@@ -638,7 +643,7 @@ impl BlockChain {
/// Returns true if the given parent block has given child
/// (though not necessarily a part of the canon chain).
fn is_known_child(&self, parent: &H256, hash: &H256) -> bool {
self.db.read_with_cache(db::COL_EXTRA, &self.block_details, parent).map_or(false, |d| d.children.contains(hash))
self.db.key_value().read_with_cache(db::COL_EXTRA, &self.block_details, parent).map_or(false, |d| d.children.contains(hash))
}
/// Returns a tree route between `from` and `to`, which is a tuple of:
......@@ -843,7 +848,7 @@ impl BlockChain {
///
/// The block the transition occurred at should have already been inserted into the chain.
pub fn insert_epoch_transition(&self, batch: &mut DBTransaction, epoch_num: u64, transition: EpochTransition) {
let mut transitions = match self.db.read(db::COL_EXTRA, &epoch_num) {
let mut transitions = match self.db.key_value().read(db::COL_EXTRA, &epoch_num) {
Some(existing) => existing,
None => EpochTransitions {
number: epoch_num,
......@@ -861,7 +866,7 @@ impl BlockChain {
/// Iterate over all epoch transitions.
/// This will only return transitions within the canonical chain.
pub fn epoch_transitions(&self) -> EpochTransitionIter {
let iter = self.db.iter_from_prefix(db::COL_EXTRA, &EPOCH_KEY_PREFIX[..]);
let iter = self.db.key_value().iter_from_prefix(db::COL_EXTRA, &EPOCH_KEY_PREFIX[..]);
EpochTransitionIter {
chain: self,
prefix_iter: iter,
......@@ -873,7 +878,7 @@ impl BlockChain {
trace!(target: "blockchain", "Loading epoch transition at block {}, {}",
block_num, block_hash);
self.db.read(db::COL_EXTRA, &block_num).and_then(|transitions: EpochTransitions| {
self.db.key_value().read(db::COL_EXTRA, &block_num).and_then(|transitions: EpochTransitions| {
transitions.candidates.into_iter().find(|c| c.block_hash == block_hash)
})
}
......@@ -919,7 +924,7 @@ impl BlockChain {
// TODO: implement removal safely: this can only be done upon finality of a block
// that _uses_ the pending transition.
pub fn get_pending_transition(&self, hash: H256) -> Option<PendingEpochTransition> {
self.db.read(db::COL_EXTRA, &hash)
self.db.key_value().read(db::COL_EXTRA, &hash)
}
/// Add a child to a given block. Assumes that the block hash is in
......@@ -1064,35 +1069,10 @@ impl BlockChain {
batch.extend_with_cache(db::COL_EXTRA, &mut *write_receipts, update.block_receipts, CacheUpdatePolicy::Remove);
}
{
let mut write_blocks_blooms = self.blocks_blooms.write();
// update best block
match update.info.location {
BlockLocation::Branch => (),
BlockLocation::BranchBecomingCanonChain(_) => {
// clear all existing blooms, cause they may be created for block
// number higher than current best block
*write_blocks_blooms = update.blocks_blooms;
for (key, value) in write_blocks_blooms.iter() {
batch.write(db::COL_EXTRA, key, value);
}
},
BlockLocation::CanonChain => {
// update all existing blooms groups
for (key, value) in update.blocks_blooms {
match write_blocks_blooms.entry(key) {
hash_map::Entry::Occupied(mut entry) => {
entry.get_mut().accrue_bloom_group(&value);
batch.write(db::COL_EXTRA, entry.key(), entry.get());
},
hash_map::Entry::Vacant(entry) => {
batch.write(db::COL_EXTRA, entry.key(), &value);
entry.insert(value);
},
}
}
},
}
if let Some((block, blooms)) = update.blocks_blooms {
self.db.blooms()
.insert_blooms(block, blooms.iter())
.expect("Low level database error. Some issue with disk?");
}
// These cached values must be updated last with all four locks taken to avoid
......@@ -1355,25 +1335,23 @@ impl BlockChain {
/// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex)
/// to bloom location in database (BlocksBloomLocation).
///
fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<GroupPosition, BloomGroup> {
fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> Option<(u64, Vec<Bloom>)> {
let block = view!(BlockView, block_bytes);
let header = block.header_view();
let log_blooms = match info.location {
BlockLocation::Branch => HashMap::new(),
match info.location {
BlockLocation::Branch => None,
BlockLocation::CanonChain => {
let log_bloom = header.log_bloom();