Added purge subcommand to purge beacon chain db (#971)
This commit is contained in:
parent
869b0621d6
commit
065ea15c9f
@ -221,7 +221,7 @@ where
|
|||||||
.get::<PersistedBeaconChain>(&Hash256::from_slice(&BEACON_CHAIN_DB_KEY))
|
.get::<PersistedBeaconChain>(&Hash256::from_slice(&BEACON_CHAIN_DB_KEY))
|
||||||
.map_err(|e| format!("DB error when reading persisted beacon chain: {:?}", e))?
|
.map_err(|e| format!("DB error when reading persisted beacon chain: {:?}", e))?
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
"No persisted beacon chain found in store. Try deleting the .lighthouse/beacon dir."
|
"No persisted beacon chain found in store. Try purging the beacon chain database."
|
||||||
.to_string()
|
.to_string()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use beacon_chain::builder::PUBKEY_CACHE_FILENAME;
|
||||||
use network::NetworkConfig;
|
use network::NetworkConfig;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -11,6 +12,9 @@ const TESTNET_SPEC_CONSTANTS: &str = "minimal";
|
|||||||
/// Default directory name for the freezer database under the top-level data dir.
|
/// Default directory name for the freezer database under the top-level data dir.
|
||||||
const DEFAULT_FREEZER_DB_DIR: &str = "freezer_db";
|
const DEFAULT_FREEZER_DB_DIR: &str = "freezer_db";
|
||||||
|
|
||||||
|
/// Trap file indicating if chain_db was purged
|
||||||
|
const CHAIN_DB_PURGED_TRAP_FILE: &str = ".db_purged";
|
||||||
|
|
||||||
/// Defines how the client should initialize the `BeaconChain` and other components.
|
/// Defines how the client should initialize the `BeaconChain` and other components.
|
||||||
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum ClientGenesis {
|
pub enum ClientGenesis {
|
||||||
@ -97,6 +101,68 @@ impl Config {
|
|||||||
.map(|data_dir| data_dir.join(&self.db_name))
|
.map(|data_dir| data_dir.join(&self.db_name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the path of the chain db purged trap file
|
||||||
|
pub fn get_db_purged_trap_file_path(&self) -> Option<PathBuf> {
|
||||||
|
self.get_data_dir()
|
||||||
|
.map(|data_dir| data_dir.join(CHAIN_DB_PURGED_TRAP_FILE))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns whether chain_db was recently purged
|
||||||
|
pub fn chain_db_was_purged(&self) -> bool {
|
||||||
|
self.get_db_purged_trap_file_path()
|
||||||
|
.map_or(false, |trap_file| trap_file.exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// purges the chain_db and creates trap file
|
||||||
|
pub fn purge_chain_db(&self) -> Result<(), String> {
|
||||||
|
// create the trap file
|
||||||
|
let trap_file = self
|
||||||
|
.get_db_purged_trap_file_path()
|
||||||
|
.ok_or("Failed to get trap file path".to_string())?;
|
||||||
|
fs::File::create(trap_file)
|
||||||
|
.map_err(|err| format!("Failed to create trap file: {}", err))?;
|
||||||
|
|
||||||
|
// remove the chain_db
|
||||||
|
fs::remove_dir_all(
|
||||||
|
self.get_db_path()
|
||||||
|
.ok_or("Failed to get db_path".to_string())?,
|
||||||
|
)
|
||||||
|
.map_err(|err| format!("Failed to remove chain_db: {}", err))?;
|
||||||
|
|
||||||
|
// remove the freezer db
|
||||||
|
fs::remove_dir_all(
|
||||||
|
self.get_freezer_db_path()
|
||||||
|
.ok_or("Failed to get freezer db path".to_string())?,
|
||||||
|
)
|
||||||
|
.map_err(|err| format!("Failed to remove chain_db: {}", err))?;
|
||||||
|
|
||||||
|
// also need to remove pubkey cache file if it exists
|
||||||
|
let pubkey_cache_file = self
|
||||||
|
.get_data_dir()
|
||||||
|
.map(|data_dir| data_dir.join(PUBKEY_CACHE_FILENAME))
|
||||||
|
.ok_or("Failed to get pubkey cache file path".to_string())?;
|
||||||
|
if !pubkey_cache_file.exists() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
fs::remove_file(pubkey_cache_file)
|
||||||
|
.map_err(|err| format!("Failed to remove pubkey cache: {}", err))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// cleans up purge_db trap file
|
||||||
|
pub fn cleanup_after_purge_db(&self) -> Result<(), String> {
|
||||||
|
let trap_file = self
|
||||||
|
.get_db_purged_trap_file_path()
|
||||||
|
.ok_or("Failed to get trap file path".to_string())?;
|
||||||
|
if !trap_file.exists() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
fs::remove_file(trap_file).map_err(|err| format!("Failed to remove trap file: {}", err))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the database path, creating it if necessary.
|
/// Get the database path, creating it if necessary.
|
||||||
pub fn create_db_path(&self) -> Result<PathBuf, String> {
|
pub fn create_db_path(&self) -> Result<PathBuf, String> {
|
||||||
let db_path = self
|
let db_path = self
|
||||||
|
@ -309,4 +309,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
.help("A file from which to read the state"))
|
.help("A file from which to read the state"))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
/*
|
||||||
|
* The "purge" sub-command.
|
||||||
|
*
|
||||||
|
* Allows user to purge beacon database
|
||||||
|
*/
|
||||||
|
.subcommand(SubCommand::with_name("purge")
|
||||||
|
.about("Purge the beacon chain database.")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -189,15 +189,27 @@ pub fn get_config<E: EthSpec>(
|
|||||||
("testnet", Some(sub_cmd_args)) => {
|
("testnet", Some(sub_cmd_args)) => {
|
||||||
process_testnet_subcommand(&mut client_config, ð2_config, sub_cmd_args)?
|
process_testnet_subcommand(&mut client_config, ð2_config, sub_cmd_args)?
|
||||||
}
|
}
|
||||||
|
("purge", _) => {
|
||||||
|
client_config.purge_chain_db()?;
|
||||||
|
println!("Successfully purged chain db");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
// No sub-command assumes a resume operation.
|
// No sub-command assumes a resume operation.
|
||||||
_ => {
|
_ => {
|
||||||
// If no primary subcommand was given, start the beacon chain from an existing
|
// If no primary subcommand was given, start the beacon chain from an existing
|
||||||
// database.
|
// database.
|
||||||
client_config.genesis = ClientGenesis::Resume;
|
client_config.genesis = ClientGenesis::Resume;
|
||||||
|
|
||||||
|
let db_path_exists: bool = match client_config.get_db_path() {
|
||||||
|
Some(path) => path.exists(),
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
|
||||||
// Whilst there is no large testnet or mainnet force the user to specify how they want
|
// Whilst there is no large testnet or mainnet force the user to specify how they want
|
||||||
// to start a new chain (e.g., from a genesis YAML file, another node, etc).
|
// to start a new chain (e.g., from a genesis YAML file, another node, etc).
|
||||||
if !client_config.data_dir.exists() {
|
if !client_config.data_dir.exists()
|
||||||
|
|| (!db_path_exists && client_config.chain_db_was_purged())
|
||||||
|
{
|
||||||
info!(
|
info!(
|
||||||
log,
|
log,
|
||||||
"Starting from an empty database";
|
"Starting from an empty database";
|
||||||
@ -392,7 +404,8 @@ fn init_new_client<E: EthSpec>(
|
|||||||
///
|
///
|
||||||
/// Returns an error if `self.data_dir` already exists.
|
/// Returns an error if `self.data_dir` already exists.
|
||||||
pub fn create_new_datadir(client_config: &ClientConfig, eth2_config: &Eth2Config) -> Result<()> {
|
pub fn create_new_datadir(client_config: &ClientConfig, eth2_config: &Eth2Config) -> Result<()> {
|
||||||
if client_config.data_dir.exists() {
|
let rebuild_db = client_config.chain_db_was_purged();
|
||||||
|
if client_config.data_dir.exists() && !rebuild_db {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Data dir already exists at {:?}",
|
"Data dir already exists at {:?}",
|
||||||
client_config.data_dir
|
client_config.data_dir
|
||||||
@ -407,7 +420,9 @@ pub fn create_new_datadir(client_config: &ClientConfig, eth2_config: &Eth2Config
|
|||||||
($file: ident, $variable: ident) => {
|
($file: ident, $variable: ident) => {
|
||||||
let file = client_config.data_dir.join($file);
|
let file = client_config.data_dir.join($file);
|
||||||
if file.exists() {
|
if file.exists() {
|
||||||
return Err(format!("Datadir is not clean, {} exists.", $file));
|
if !rebuild_db {
|
||||||
|
return Err(format!("Datadir is not clean, {} exists.", $file));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Write the onfig to a TOML file in the datadir.
|
// Write the onfig to a TOML file in the datadir.
|
||||||
write_to_file(client_config.data_dir.join($file), $variable)
|
write_to_file(client_config.data_dir.join($file), $variable)
|
||||||
@ -418,6 +433,7 @@ pub fn create_new_datadir(client_config: &ClientConfig, eth2_config: &Eth2Config
|
|||||||
|
|
||||||
write_to_file!(CLIENT_CONFIG_FILENAME, client_config);
|
write_to_file!(CLIENT_CONFIG_FILENAME, client_config);
|
||||||
write_to_file!(ETH2_CONFIG_FILENAME, eth2_config);
|
write_to_file!(ETH2_CONFIG_FILENAME, eth2_config);
|
||||||
|
client_config.cleanup_after_purge_db()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user