use anyhow::Error;
use exonum::merkledb::{migration::rollback_migration, Database, RocksDB};
use exonum::runtime::remove_local_migration_result;
use exonum_node::helpers::clear_consensus_messages_cache;
use serde_derive::{Deserialize, Serialize};
use structopt::StructOpt;
use std::path::{Path, PathBuf};
use crate::{
command::{ExonumCommand, StandardResult},
config::NodeConfig,
io::load_config_file,
};
#[derive(StructOpt, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Maintenance {
#[structopt(long, short = "c")]
pub node_config: PathBuf,
#[structopt(long, short = "d")]
pub db_path: PathBuf,
#[structopt(subcommand)]
pub action: MaintenanceAction,
}
#[derive(StructOpt, Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum MaintenanceAction {
#[structopt(name = "clear-cache")]
ClearCache,
#[structopt(name = "restart-migration")]
RestartMigration {
service_name: String,
},
}
impl MaintenanceAction {
fn clear_cache(node_config: &Path, db_path: &Path) -> Result<(), Error> {
let node_config: NodeConfig = load_config_file(node_config)?;
let db: Box<dyn Database> = Box::new(RocksDB::open(
db_path,
&node_config.private_config.database,
)?);
let fork = db.fork();
clear_consensus_messages_cache(&fork);
db.merge_sync(fork.into_patch())?;
Ok(())
}
fn restart_migration(
node_config: &Path,
db_path: &Path,
service_name: &str,
) -> Result<(), Error> {
let node_config: NodeConfig = load_config_file(node_config)?;
let db: Box<dyn Database> = Box::new(RocksDB::open(
db_path,
&node_config.private_config.database,
)?);
let mut fork = db.fork();
rollback_migration(&mut fork, service_name);
remove_local_migration_result(&fork, service_name);
db.merge_sync(fork.into_patch())?;
Ok(())
}
}
impl ExonumCommand for Maintenance {
fn execute(self) -> Result<StandardResult, Error> {
match self.action {
MaintenanceAction::ClearCache => {
MaintenanceAction::clear_cache(&self.node_config, &self.db_path)?
}
MaintenanceAction::RestartMigration { ref service_name } => {
MaintenanceAction::restart_migration(
&self.node_config,
&self.db_path,
service_name,
)?
}
}
Ok(StandardResult::Maintenance {
node_config_path: self.node_config,
db_path: self.db_path,
performed_action: self.action,
})
}
}