refactor(cli): db subcommands (#19754)

This commit is contained in:
Alexey Shekhirin
2025-11-14 22:37:01 +00:00
committed by GitHub
parent f88fae0ea1
commit 860a453930
6 changed files with 57 additions and 55 deletions

View File

@@ -6,8 +6,9 @@ use reth_db_api::{
transaction::{DbTx, DbTxMut},
TableViewer, Tables,
};
use reth_db_common::DbTool;
use reth_node_builder::NodeTypesWithDB;
use reth_provider::{ProviderFactory, StaticFileProviderFactory};
use reth_provider::StaticFileProviderFactory;
use reth_static_file_types::StaticFileSegment;
/// The arguments for the `reth db clear` command
@@ -19,16 +20,13 @@ pub struct Command {
impl Command {
/// Execute `db clear` command
pub fn execute<N: NodeTypesWithDB>(
self,
provider_factory: ProviderFactory<N>,
) -> eyre::Result<()> {
pub fn execute<N: NodeTypesWithDB>(self, tool: &DbTool<N>) -> eyre::Result<()> {
match self.subcommand {
Subcommands::Mdbx { table } => {
table.view(&ClearViewer { db: provider_factory.db_ref() })?
table.view(&ClearViewer { db: tool.provider_factory.db_ref() })?
}
Subcommands::StaticFile { segment } => {
let static_file_provider = provider_factory.static_file_provider();
let static_file_provider = tool.provider_factory.static_file_provider();
let static_files = iter_static_files(static_file_provider.directory())?;
if let Some(segment_static_files) = static_files.get(&segment) {

View File

@@ -60,10 +60,11 @@ pub enum Subcommands {
Path,
}
/// `db_ro_exec` opens a database in read-only mode, and then execute with the provided command
macro_rules! db_ro_exec {
($env:expr, $tool:ident, $N:ident, $command:block) => {
let Environment { provider_factory, .. } = $env.init::<$N>(AccessRights::RO)?;
/// Initializes a provider factory with specified access rights, and then execute with the provided
/// command
macro_rules! db_exec {
($env:expr, $tool:ident, $N:ident, $access_rights:expr, $command:block) => {
let Environment { provider_factory, .. } = $env.init::<$N>($access_rights)?;
let $tool = DbTool::new(provider_factory)?;
$command;
@@ -91,27 +92,32 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
match self.command {
// TODO: We'll need to add this on the DB trait.
Subcommands::Stats(command) => {
db_ro_exec!(self.env, tool, N, {
let access_rights = if command.skip_consistency_checks {
AccessRights::RoInconsistent
} else {
AccessRights::RO
};
db_exec!(self.env, tool, N, access_rights, {
command.execute(data_dir, &tool)?;
});
}
Subcommands::List(command) => {
db_ro_exec!(self.env, tool, N, {
db_exec!(self.env, tool, N, AccessRights::RO, {
command.execute(&tool)?;
});
}
Subcommands::Checksum(command) => {
db_ro_exec!(self.env, tool, N, {
db_exec!(self.env, tool, N, AccessRights::RO, {
command.execute(&tool)?;
});
}
Subcommands::Diff(command) => {
db_ro_exec!(self.env, tool, N, {
db_exec!(self.env, tool, N, AccessRights::RO, {
command.execute(&tool)?;
});
}
Subcommands::Get(command) => {
db_ro_exec!(self.env, tool, N, {
db_exec!(self.env, tool, N, AccessRights::RO, {
command.execute(&tool)?;
});
}
@@ -133,21 +139,27 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
}
}
let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?;
let tool = DbTool::new(provider_factory)?;
tool.drop(db_path, static_files_path, exex_wal_path)?;
db_exec!(self.env, tool, N, AccessRights::RW, {
tool.drop(db_path, static_files_path, exex_wal_path)?;
});
}
Subcommands::Clear(command) => {
let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?;
command.execute(provider_factory)?;
db_exec!(self.env, tool, N, AccessRights::RW, {
command.execute(&tool)?;
});
}
Subcommands::RepairTrie(command) => {
let access_rights =
if command.dry_run { AccessRights::RO } else { AccessRights::RW };
let Environment { provider_factory, .. } = self.env.init::<N>(access_rights)?;
command.execute(provider_factory)?;
db_exec!(self.env, tool, N, access_rights, {
command.execute(&tool)?;
});
}
Subcommands::StaticFileHeader(command) => {
db_exec!(self.env, tool, N, AccessRights::RoInconsistent, {
command.execute(&tool)?;
});
}
Subcommands::StaticFileHeader(command) => command.execute::<N, _>(self.env)?,
Subcommands::Version => {
let local_db_version = match get_db_version(&db_path) {
Ok(version) => Some(version),

View File

@@ -5,8 +5,9 @@ use reth_db_api::{
tables,
transaction::{DbTx, DbTxMut},
};
use reth_db_common::DbTool;
use reth_node_builder::NodeTypesWithDB;
use reth_provider::{providers::ProviderNodeTypes, ProviderFactory, StageCheckpointReader};
use reth_provider::{providers::ProviderNodeTypes, StageCheckpointReader};
use reth_stages::StageId;
use reth_trie::{
verify::{Output, Verifier},
@@ -29,23 +30,20 @@ pub struct Command {
impl Command {
/// Execute `db repair-trie` command
pub fn execute<N: ProviderNodeTypes>(
self,
provider_factory: ProviderFactory<N>,
) -> eyre::Result<()> {
pub fn execute<N: ProviderNodeTypes>(self, tool: &DbTool<N>) -> eyre::Result<()> {
if self.dry_run {
verify_only(provider_factory)?
verify_only(tool)?
} else {
verify_and_repair(provider_factory)?
verify_and_repair(tool)?
}
Ok(())
}
}
fn verify_only<N: NodeTypesWithDB>(provider_factory: ProviderFactory<N>) -> eyre::Result<()> {
fn verify_only<N: NodeTypesWithDB>(tool: &DbTool<N>) -> eyre::Result<()> {
// Get a database transaction directly from the database
let db = provider_factory.db_ref();
let db = tool.provider_factory.db_ref();
let mut tx = db.tx()?;
tx.disable_long_read_transaction_safety();
@@ -114,11 +112,9 @@ fn verify_checkpoints(provider: impl StageCheckpointReader) -> eyre::Result<()>
Ok(())
}
fn verify_and_repair<N: ProviderNodeTypes>(
provider_factory: ProviderFactory<N>,
) -> eyre::Result<()> {
fn verify_and_repair<N: ProviderNodeTypes>(tool: &DbTool<N>) -> eyre::Result<()> {
// Get a read-write database provider
let mut provider_rw = provider_factory.provider_rw()?;
let mut provider_rw = tool.provider_factory.provider_rw()?;
// Check that a pipeline sync isn't in progress.
verify_checkpoints(provider_rw.as_ref())?;

View File

@@ -1,12 +1,10 @@
use clap::{Parser, Subcommand};
use reth_cli::chainspec::ChainSpecParser;
use reth_provider::StaticFileProviderFactory;
use reth_db_common::DbTool;
use reth_provider::{providers::ProviderNodeTypes, StaticFileProviderFactory};
use reth_static_file_types::StaticFileSegment;
use std::path::PathBuf;
use tracing::warn;
use crate::common::{AccessRights, CliNodeTypes, EnvironmentArgs};
/// The arguments for the `reth db static-file-header` command
#[derive(Parser, Debug)]
pub struct Command {
@@ -34,21 +32,12 @@ enum Source {
impl Command {
/// Execute `db static-file-header` command
pub fn execute<N: CliNodeTypes, C: ChainSpecParser<ChainSpec = N::ChainSpec>>(
self,
env: EnvironmentArgs<C>,
) -> eyre::Result<()> {
// Try to initialize the environment as read-only. If it fails, try to initialize it as
// read-only without consistency checks.
let provider_factory = match env.init::<N>(AccessRights::RO) {
Ok(env) => env,
Err(err) => {
warn!(?err, "Failed to initialize environment");
env.init::<N>(AccessRights::RoInconsistent)?
}
pub fn execute<N: ProviderNodeTypes>(self, tool: &DbTool<N>) -> eyre::Result<()> {
let static_file_provider = tool.provider_factory.static_file_provider();
if let Err(err) = static_file_provider.check_consistency(&tool.provider_factory.provider()?)
{
warn!("Error checking consistency of static files: {err}");
}
.provider_factory;
let static_file_provider = provider_factory.static_file_provider();
// Get the provider based on the source
let provider = match self.source {

View File

@@ -18,6 +18,10 @@ use std::{sync::Arc, time::Duration};
#[derive(Parser, Debug)]
/// The arguments for the `reth db stats` command
pub struct Command {
/// Skip consistency checks for static files.
#[arg(long, default_value_t = false)]
pub(crate) skip_consistency_checks: bool,
/// Show only the total size for static files.
#[arg(long, default_value_t = false)]
detailed_sizes: bool,

View File

@@ -9,6 +9,9 @@ $ reth db stats --help
Usage: reth db stats [OPTIONS]
Options:
--skip-consistency-checks
Skip consistency checks for static files
--detailed-sizes
Show only the total size for static files