expose only chunk_blocks and chunk_state APIs

This commit is contained in:
Robert Habermeier 2016-06-13 16:29:26 +02:00
parent 446d59426a
commit 98c7677ce1
2 changed files with 53 additions and 59 deletions

View File

@ -756,7 +756,7 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
} }
fn take_snapshot(&self, root_dir: &Path) { fn take_snapshot(&self, root_dir: &Path) {
use pv64::{BlockChunker, ManifestData, StateChunker}; use pv64::{ManifestData, chunk_blocks, chunk_state};
let best_header_bytes = self.best_block_header(); let best_header_bytes = self.best_block_header();
let best_header = HeaderView::new(&best_header_bytes); let best_header = HeaderView::new(&best_header_bytes);
@ -771,13 +771,13 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
// lock the state db while we create the state chunks. // lock the state db while we create the state chunks.
let state_hashes = { let state_hashes = {
let state_db = self.state_db.lock().unwrap(); let state_db = self.state_db.lock().unwrap();
StateChunker::chunk_all(state_db.as_hashdb(), &state_root, &path).unwrap() chunk_state(state_db.as_hashdb(), &state_root, &path).unwrap()
}; };
let best_hash = best_header.hash(); let best_hash = best_header.hash();
let genesis_hash = self.chain.genesis_hash(); let genesis_hash = self.chain.genesis_hash();
let block_chunk_hashes = BlockChunker::new(self, best_hash, genesis_hash).chunk_all(&path).unwrap(); let block_chunk_hashes = chunk_blocks(self, best_hash, genesis_hash, &path).unwrap();
let manifest_data = ManifestData { let manifest_data = ManifestData {
state_hashes: state_hashes, state_hashes: state_hashes,

View File

@ -36,7 +36,7 @@ use util::numbers::U256;
use util::rlp::{DecoderError, Stream, Rlp, RlpStream, UntrustedRlp, View}; use util::rlp::{DecoderError, Stream, Rlp, RlpStream, UntrustedRlp, View};
/// Used to build block chunks. /// Used to build block chunks.
pub struct BlockChunker<'a> { struct BlockChunker<'a> {
client: &'a BlockChainClient, client: &'a BlockChainClient,
// block, receipt rlp pairs. // block, receipt rlp pairs.
rlps: VecDeque<Bytes>, rlps: VecDeque<Bytes>,
@ -46,18 +46,6 @@ pub struct BlockChunker<'a> {
} }
impl<'a> BlockChunker<'a> { impl<'a> BlockChunker<'a> {
/// Create a new BlockChunker given a client and the genesis hash.
pub fn new(client: &'a BlockChainClient, best_block_hash: H256, genesis_hash: H256) -> Self {
// Todo [rob]: find a way to reuse rlp allocations
BlockChunker {
client: client,
rlps: VecDeque::new(),
genesis_hash: genesis_hash,
current_hash: best_block_hash,
hashes: Vec::new(),
}
}
// Try to fill the buffers, moving backwards from current block hash. // Try to fill the buffers, moving backwards from current block hash.
// This will return true if it created a block chunk, false otherwise. // This will return true if it created a block chunk, false otherwise.
fn fill_buffers(&mut self) -> bool { fn fill_buffers(&mut self) -> bool {
@ -118,27 +106,33 @@ impl<'a> BlockChunker<'a> {
self.hashes.push(hash); self.hashes.push(hash);
Ok(()) Ok(())
} }
}
/// Create and write out all block chunks to disk, returning a vector of all /// Create and write out all block chunks to disk, returning a vector of all
/// the hashes of block chunks created. /// the hashes of block chunks created.
/// ///
/// The path parameter is the directory to store the block chunks in. /// The path parameter is the directory to store the block chunks in.
/// This function assumes the directory exists already. /// This function assumes the directory exists already.
pub fn chunk_all(mut self, path: &Path) -> Result<Vec<H256>, Error> { pub fn chunk_blocks(client: &BlockChainClient, best_block_hash: H256, genesis_hash: H256, path: &Path) -> Result<Vec<H256>, Error> {
while self.fill_buffers() { let mut chunker = BlockChunker {
try!(self.write_chunk(path)); client: client,
} rlps: VecDeque::new(),
genesis_hash: genesis_hash,
current_hash: best_block_hash,
hashes: Vec::new(),
};
if self.rlps.len() != 0 { while chunker.fill_buffers() {
try!(self.write_chunk(path)); try!(chunker.write_chunk(path));
}
Ok(self.hashes)
} }
if chunker.rlps.len() != 0 {
try!(chunker.write_chunk(path));
}
Ok(chunker.hashes)
} }
/// State trie chunker. /// State trie chunker.
pub struct StateChunker<'a> { struct StateChunker<'a> {
hashes: Vec<H256>, hashes: Vec<H256>,
rlps: Vec<Bytes>, rlps: Vec<Bytes>,
cur_size: usize, cur_size: usize,
@ -193,41 +187,41 @@ impl<'a> StateChunker<'a> {
Ok(()) Ok(())
} }
}
/// Walk the given state database starting from the given root, /// Walk the given state database starting from the given root,
/// creating chunks and writing them out. /// creating chunks and writing them out.
/// ///
/// Returns a list of hashes of chunks created, or any error it may /// Returns a list of hashes of chunks created, or any error it may
/// have encountered. /// have encountered.
pub fn chunk_all(db: &'a HashDB, root: &'a H256, path: &'a Path) -> Result<Vec<H256>, Error> { pub fn chunk_state(db: &HashDB, root: &H256, path: &Path) -> Result<Vec<H256>, Error> {
let account_view = try!(TrieDB::new(db, &root)); let account_view = try!(TrieDB::new(db, &root));
let mut chunker = StateChunker { let mut chunker = StateChunker {
hashes: Vec::new(), hashes: Vec::new(),
rlps: Vec::new(), rlps: Vec::new(),
cur_size: 0, cur_size: 0,
snapshot_path: path, snapshot_path: path,
}; };
trace!(target: "pv64_snapshot", "beginning state chunking"); trace!(target: "pv64_snapshot", "beginning state chunking");
// account_key here is the address' hash. // account_key here is the address' hash.
for (account_key, account_data) in account_view.iter() { for (account_key, account_data) in account_view.iter() {
let account = AccountReader::from_thin_rlp(account_data); let account = AccountReader::from_thin_rlp(account_data);
let account_key_hash = H256::from_slice(&account_key); let account_key_hash = H256::from_slice(&account_key);
let account_db = AccountDB::from_hash(db, account_key_hash); let account_db = AccountDB::from_hash(db, account_key_hash);
let fat_rlp = try!(account.to_fat_rlp(&account_db)); let fat_rlp = try!(account.to_fat_rlp(&account_db));
try!(chunker.push(account_key, fat_rlp)); try!(chunker.push(account_key, fat_rlp));
}
if chunker.cur_size != 0 {
try!(chunker.write_chunk());
}
Ok(chunker.hashes)
} }
if chunker.cur_size != 0 {
try!(chunker.write_chunk());
}
Ok(chunker.hashes)
} }
// An alternate account structure, only used for reading the storage values // An alternate account structure, only used for reading the storage values