run chain compaction on startup (#2127)

* run chain compaction on startup
* make sure we can compact an empty chain
This commit is contained in:
Antioch Peverell 2018-12-11 16:52:55 +00:00 committed by Ignotus Peverell
parent 16641fe149
commit c5e771cbf0

View file

@ -167,34 +167,44 @@ impl Chain {
archive_mode: bool, archive_mode: bool,
stop_state: Arc<Mutex<StopState>>, stop_state: Arc<Mutex<StopState>>,
) -> Result<Chain, Error> { ) -> Result<Chain, Error> {
// Note: We take a lock on the stop_state here and do not release it until let chain = {
// we have finished chain initialization. // Note: We take a lock on the stop_state here and do not release it until
let stop_state_local = stop_state.clone(); // we have finished chain initialization.
let stop_lock = stop_state_local.lock(); let stop_state_local = stop_state.clone();
if stop_lock.is_stopped() { let stop_lock = stop_state_local.lock();
return Err(ErrorKind::Stopped.into()); if stop_lock.is_stopped() {
} return Err(ErrorKind::Stopped.into());
}
let store = Arc::new(store::ChainStore::new(db_env)?); let store = Arc::new(store::ChainStore::new(db_env)?);
// open the txhashset, creating a new one if necessary // open the txhashset, creating a new one if necessary
let mut txhashset = txhashset::TxHashSet::open(db_root.clone(), store.clone(), None)?; let mut txhashset = txhashset::TxHashSet::open(db_root.clone(), store.clone(), None)?;
setup_head(&genesis, &store, &mut txhashset)?; setup_head(&genesis, &store, &mut txhashset)?;
Chain::log_heads(&store)?; Chain::log_heads(&store)?;
Ok(Chain { Chain {
db_root, db_root,
store, store,
adapter, adapter,
orphans: Arc::new(OrphanBlockPool::new()), orphans: Arc::new(OrphanBlockPool::new()),
txhashset: Arc::new(RwLock::new(txhashset)), txhashset: Arc::new(RwLock::new(txhashset)),
pow_verifier, pow_verifier,
verifier_cache, verifier_cache,
archive_mode, archive_mode,
stop_state, stop_state,
genesis: genesis.header.clone(), genesis: genesis.header.clone(),
}) }
};
// Run chain compaction. Laptops and other intermittent nodes
// may not run long enough to trigger daily compaction.
// So run it explicitly here on startup (its fast enough to do so).
// Note: we release the stop_lock from above as compact also requires a lock.
chain.compact()?;
Ok(chain)
} }
fn log_heads(store: &store::ChainStore) -> Result<(), Error> { fn log_heads(store: &store::ChainStore) -> Result<(), Error> {
@ -895,10 +905,10 @@ impl Chain {
} }
fn compact_txhashset(&self) -> Result<(), Error> { fn compact_txhashset(&self) -> Result<(), Error> {
debug!("Starting blockchain compaction."); debug!("Starting txhashset compaction...");
{ {
// Note: We take a lock on the stop_state here and do not release it until // Note: We take a lock on the stop_state here and do not release it until
// we have finished processing this compaction operation. // we have finished processing this chain compaction operation.
let stop_lock = self.stop_state.lock(); let stop_lock = self.stop_state.lock();
if stop_lock.is_stopped() { if stop_lock.is_stopped() {
return Err(ErrorKind::Stopped.into()); return Err(ErrorKind::Stopped.into());
@ -906,16 +916,8 @@ impl Chain {
let mut txhashset = self.txhashset.write(); let mut txhashset = self.txhashset.write();
txhashset.compact()?; txhashset.compact()?;
txhashset::extending_readonly(&mut txhashset, |extension| {
extension.dump_output_pmmr();
Ok(())
})?;
} }
debug!("... finished txhashset compaction.");
// Now check we can still successfully validate the chain state after
// compacting, shouldn't be necessary once all of this is well-oiled
debug!("Validating state after compaction.");
self.validate(true)?;
Ok(()) Ok(())
} }
@ -929,7 +931,11 @@ impl Chain {
let horizon = global::cut_through_horizon() as u64; let horizon = global::cut_through_horizon() as u64;
let head = self.head()?; let head = self.head()?;
let tail = self.tail()?;
let tail = match self.tail() {
Ok(tail) => tail,
Err(_) => Tip::from_header(&self.genesis),
};
let cutoff = head.height.saturating_sub(horizon); let cutoff = head.height.saturating_sub(horizon);