diff --git a/Cargo.toml b/Cargo.toml index 8450bf1b8..3a74bf589 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ ethcore-util = "0.1.0" rustc-serialize = "0.3" flate2 = "0.2" rocksdb = "0.2.1" +heapsize = "0.2.0" evmjit = { path = "rust-evmjit", optional = true } diff --git a/src/blockchain.rs b/src/blockchain.rs index facb57cdb..6a48e12af 100644 --- a/src/blockchain.rs +++ b/src/blockchain.rs @@ -1,8 +1,9 @@ use std::collections::HashMap; -use std::sync::RwLock; +use std::cell::{Cell, RefCell}; use std::path::Path; use std::hash::Hash; use rocksdb::{DB, WriteBatch, Writable}; +use heapsize::HeapSizeOf; use util::hash::*; use util::uint::*; use util::rlp::*; @@ -10,6 +11,7 @@ use util::hashdb::*; use util::overlaydb::*; use util::sha3::*; use util::bytes::*; +use util::squeeze::*; use blockheader::*; use block::*; use verifiedblock::*; @@ -19,6 +21,15 @@ use genesis::*; use extras::*; use transaction::*; +#[derive(Debug)] +pub struct CacheSize { + pub blocks: usize, + pub block_details: usize, + pub transaction_addresses: usize, + pub block_logs: usize, + pub blocks_blooms: usize +} + pub struct BlockChain { // rlp list of 3 genesis_block: Bytes, @@ -27,17 +38,17 @@ pub struct BlockChain { genesis_hash: H256, _genesis_state: HashMap, - _last_block_number: U256, + last_block_number: Cell, // block cache - blocks: RwLock>, + blocks: RefCell>, // extra caches block_details: Extras, block_hashes: Extras, transaction_addresses: Extras, block_logs: Extras, - _blocks_blooms: Extras, + blocks_blooms: Extras, extras_db: DB, blocks_db: DB @@ -65,7 +76,7 @@ impl BlockChain { /// let genesis_hash = "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"; /// assert_eq!(bc.genesis_hash(), &H256::from_str(genesis_hash).unwrap()); /// assert!(bc.is_known(bc.genesis_hash())); - /// assert_eq!(bc.genesis_hash(), &bc.number_hash(&U256::from(0u8)).unwrap()); + /// assert_eq!(bc.genesis_hash(), &bc.block_hash(&U256::from(0u8)).unwrap()); /// } /// ``` pub fn new(genesis: Genesis, path: &Path) -> BlockChain { @@ -103,38 +114,18 @@ impl BlockChain { _genesis_header: genesis_header, genesis_hash: genesis_hash, _genesis_state: genesis_state, - _last_block_number: U256::from(0u8), - blocks: RwLock::new(HashMap::new()), + last_block_number: Cell::new(U256::from(0u8)), + blocks: RefCell::new(HashMap::new()), block_details: Extras::new(ExtrasIndex::BlockDetails), block_hashes: Extras::new(ExtrasIndex::BlockHash), transaction_addresses: Extras::new(ExtrasIndex::TransactionAddress), block_logs: Extras::new(ExtrasIndex::BlockLogBlooms), - _blocks_blooms: Extras::new(ExtrasIndex::BlocksBlooms), + blocks_blooms: Extras::new(ExtrasIndex::BlocksBlooms), extras_db: extras_db, blocks_db: blocks_db } } - pub fn genesis_block(&self, db: &OverlayDB) -> Block { - let root = HeaderView::new(&self.genesis_block).state_root(); - - if db.exists(&root) { - return Block::new_existing(db.clone(), root) - } - - let _block = Block::new(db.clone()); - // TODO: commit - //block.mutable_state().insert_accounts(&self.genesis_state); - // block.mutable_state().db().commit(); - // TODO: set previous block - // TODO: reset current - unimplemented!() - } - - pub fn verify_block<'a>(&self, _block: &'a [u8]) -> VerifiedBlock<'a> { - unimplemented!() - } - pub fn import_block(&self, _block: &[u8], _db: &OverlayDB) -> ImportRoute { unimplemented!(); } @@ -191,10 +182,20 @@ impl BlockChain { } /// Get the hash of given block's number - pub fn number_hash(&self, hash: &U256) -> Option { + pub fn block_hash(&self, hash: &U256) -> Option { self.query_extras(hash, &self.block_hashes) } + /// Get last block number + pub fn last_block_number(&self) -> U256 { + self.last_block_number.get() + } + + /// Get the number of given block's hash + pub fn block_number(&self, hash: &H256) -> Option { + self.block(hash).map(|bytes| BlockView::new(&bytes).header_view().number()) + } + /// Get the transactions' log blooms of a block pub fn log_blooms(&self, hash: &H256) -> Option { self.query_extras(hash, &self.block_logs) @@ -202,7 +203,7 @@ impl BlockChain { fn block(&self, hash: &H256) -> Option { { - let read = self.blocks.read().unwrap(); + let read = self.blocks.borrow(); match read.get(hash) { Some(v) => return Some(v.clone()), None => () @@ -215,7 +216,7 @@ impl BlockChain { match opt { Some(b) => { let bytes: Bytes = b.to_vec(); - let mut write = self.blocks.write().unwrap(); + let mut write = self.blocks.borrow_mut(); write.insert(hash.clone(), bytes.clone()); Some(bytes) }, @@ -227,7 +228,7 @@ impl BlockChain { T: Clone + Decodable, K: ExtrasSliceConvertable + Eq + Hash + Clone { { - let read = cache.read().unwrap(); + let read = cache.borrow(); match read.get(hash) { Some(v) => return Some(v.clone()), None => () @@ -240,7 +241,7 @@ impl BlockChain { match opt { Some(b) => { let t: T = decode(&b); - let mut write = cache.write().unwrap(); + let mut write = cache.borrow_mut(); write.insert(hash.clone(), t.clone()); Some(t) }, @@ -251,7 +252,7 @@ impl BlockChain { fn query_extras_exist(&self, hash: &K, cache: &Extras) -> bool where K: ExtrasSliceConvertable + Eq + Hash + Clone { { - let read = cache.read().unwrap(); + let read = cache.borrow(); match read.get(hash) { Some(_) => return true, None => () @@ -263,5 +264,25 @@ impl BlockChain { opt.is_some() } + + /// Get current cache size + pub fn cache_size(&self) -> CacheSize { + CacheSize { + blocks: self.blocks.heap_size_of_children(), + block_details: self.block_details.heap_size_of_children(), + transaction_addresses: self.transaction_addresses.heap_size_of_children(), + block_logs: self.block_logs.heap_size_of_children(), + blocks_blooms: self.blocks_blooms.heap_size_of_children() + } + } + + /// Squeeze the cache if its too big + pub fn squeeze_to_fit(&self, size: CacheSize) { + self.blocks.borrow_mut().squeeze(size.blocks); + self.block_details.borrow_mut().squeeze(size.block_details); + self.transaction_addresses.borrow_mut().squeeze(size.transaction_addresses); + self.block_logs.borrow_mut().squeeze(size.block_logs); + self.blocks_blooms.borrow_mut().squeeze(size.blocks_blooms); + } } diff --git a/src/extras.rs b/src/extras.rs index 5606f2e10..d0cfffd89 100644 --- a/src/extras.rs +++ b/src/extras.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; -use std::sync::RwLock; +use std::cell::RefCell; use std::ops::Deref; use std::hash::Hash; +use heapsize::HeapSizeOf; use util::uint::*; use util::hash::*; use util::rlp::*; @@ -18,18 +19,18 @@ pub enum ExtrasIndex { /// rw locked extra data with slice suffix // consifer if arc needed here, since blockchain itself will be wrapped -pub struct Extras(RwLock>, ExtrasIndex) where K: Eq + Hash; +pub struct Extras(RefCell>, ExtrasIndex) where K: Eq + Hash; impl Extras where K: Eq + Hash { pub fn new(i: ExtrasIndex) -> Extras { - Extras(RwLock::new(HashMap::new()), i) + Extras(RefCell::new(HashMap::new()), i) } pub fn index(&self) -> ExtrasIndex { self.1 } } impl Deref for Extras where K : Eq + Hash { - type Target = RwLock>; + type Target = RefCell>; fn deref(&self) -> &Self::Target { &self.0 @@ -63,6 +64,12 @@ pub struct BlockDetails { pub children: Vec } +impl HeapSizeOf for BlockDetails { + fn heap_size_of_children(&self) -> usize { + self.children.heap_size_of_children() + } +} + impl Decodable for BlockDetails { fn decode(decoder: &D) -> Result where D: Decoder { let d = try!(decoder.as_list()); @@ -92,6 +99,12 @@ pub struct BlockLogBlooms { pub blooms: Vec } +impl HeapSizeOf for BlockLogBlooms { + fn heap_size_of_children(&self) -> usize { + self.blooms.heap_size_of_children() + } +} + impl Decodable for BlockLogBlooms { fn decode(decoder: &D) -> Result where D: Decoder { let block_blooms = BlockLogBlooms { @@ -112,6 +125,10 @@ pub struct BlocksBlooms { pub blooms: [H2048; 16] } +impl HeapSizeOf for BlocksBlooms { + fn heap_size_of_children(&self) -> usize { 0 } +} + impl Clone for BlocksBlooms { fn clone(&self) -> Self { let mut blooms: [H2048; 16] = unsafe { ::std::mem::uninitialized() }; @@ -149,6 +166,10 @@ pub struct TransactionAddress { pub index: u64 } +impl HeapSizeOf for TransactionAddress { + fn heap_size_of_children(&self) -> usize { 0 } +} + impl Decodable for TransactionAddress { fn decode(decoder: &D) -> Result where D: Decoder { let d = try!(decoder.as_list()); diff --git a/src/lib.rs b/src/lib.rs index cc1240233..feb0e6991 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,7 @@ extern crate log; extern crate rustc_serialize; extern crate flate2; extern crate rocksdb; +extern crate heapsize; extern crate env_logger; #[cfg(feature = "jit" )] @@ -96,7 +97,6 @@ pub mod genesis; pub mod verifiedblock; pub mod importroute; - pub mod networkparams; pub mod denominations;