mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: introduce reth db stats --checksum (#7581)
This commit is contained in:
@ -5,7 +5,10 @@ use reth_db::{
|
||||
cursor::DbCursorRO, database::Database, table::Table, transaction::DbTx, DatabaseEnv, RawKey,
|
||||
RawTable, RawValue, TableViewer, Tables,
|
||||
};
|
||||
use std::{hash::Hasher, time::Instant};
|
||||
use std::{
|
||||
hash::Hasher,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tracing::{info, warn};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
@ -18,20 +21,21 @@ pub struct Command {
|
||||
impl Command {
|
||||
/// Execute `db checksum` command
|
||||
pub fn execute(self, tool: &DbTool<DatabaseEnv>) -> eyre::Result<()> {
|
||||
warn!("This command should be run without the node running!");
|
||||
self.table.view(&ChecksumViewer { tool })
|
||||
}
|
||||
}
|
||||
|
||||
struct ChecksumViewer<'a, DB: Database> {
|
||||
pub(crate) struct ChecksumViewer<'a, DB: Database> {
|
||||
tool: &'a DbTool<DB>,
|
||||
}
|
||||
|
||||
impl<DB: Database> TableViewer<()> for ChecksumViewer<'_, DB> {
|
||||
type Error = eyre::Report;
|
||||
|
||||
fn view<T: Table>(&self) -> Result<(), Self::Error> {
|
||||
warn!("This command should be run without the node running!");
|
||||
impl<DB: Database> ChecksumViewer<'_, DB> {
|
||||
pub(crate) fn new(tool: &'_ DbTool<DB>) -> ChecksumViewer<'_, DB> {
|
||||
ChecksumViewer { tool }
|
||||
}
|
||||
|
||||
pub(crate) fn get_checksum<T: Table>(&self) -> Result<(u64, Duration), eyre::Report> {
|
||||
let provider =
|
||||
self.tool.provider_factory.provider()?.disable_long_read_transaction_safety();
|
||||
let tx = provider.tx_ref();
|
||||
@ -52,8 +56,19 @@ impl<DB: Database> TableViewer<()> for ChecksumViewer<'_, DB> {
|
||||
hasher.write(v.raw_value());
|
||||
}
|
||||
|
||||
let checksum = hasher.finish();
|
||||
let elapsed = start_time.elapsed();
|
||||
info!("{} checksum: {:x}, took {:?}", T::NAME, hasher.finish(), elapsed);
|
||||
|
||||
Ok((checksum, elapsed))
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB: Database> TableViewer<()> for ChecksumViewer<'_, DB> {
|
||||
type Error = eyre::Report;
|
||||
|
||||
fn view<T: Table>(&self) -> Result<(), Self::Error> {
|
||||
let (checksum, elapsed) = self.get_checksum::<T>()?;
|
||||
info!("Checksum for table `{}`: {:#x} (elapsed: {:?})", T::NAME, checksum, elapsed);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,13 +1,24 @@
|
||||
use crate::utils::DbTool;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{commands::db::checksum::ChecksumViewer, utils::DbTool};
|
||||
use clap::Parser;
|
||||
use comfy_table::{Cell, Row, Table as ComfyTable};
|
||||
use eyre::WrapErr;
|
||||
use human_bytes::human_bytes;
|
||||
use itertools::Itertools;
|
||||
use reth_db::{database::Database, mdbx, static_file::iter_static_files, DatabaseEnv, Tables};
|
||||
use reth_db::{
|
||||
database::Database, mdbx, static_file::iter_static_files, AccountChangeSets, AccountsHistory,
|
||||
AccountsTrie, BlockBodyIndices, BlockOmmers, BlockWithdrawals, Bytecodes, CanonicalHeaders,
|
||||
DatabaseEnv, HashedAccounts, HashedStorages, HeaderNumbers, HeaderTerminalDifficulties,
|
||||
Headers, PlainAccountState, PlainStorageState, PruneCheckpoints, Receipts,
|
||||
StageCheckpointProgresses, StageCheckpoints, StorageChangeSets, StoragesHistory, StoragesTrie,
|
||||
Tables, TransactionBlocks, TransactionHashNumbers, TransactionSenders, Transactions,
|
||||
VersionHistory,
|
||||
};
|
||||
use reth_node_core::dirs::{ChainPath, DataDirPath};
|
||||
use reth_primitives::static_file::{find_fixed_range, SegmentRangeInclusive};
|
||||
use reth_provider::providers::StaticFileProvider;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
/// The arguments for the `reth db stats` command
|
||||
@ -15,9 +26,19 @@ pub struct Command {
|
||||
/// Show only the total size for static files.
|
||||
#[arg(long, default_value_t = false)]
|
||||
only_total_size: bool,
|
||||
|
||||
/// Show only the summary per static file segment.
|
||||
#[arg(long, default_value_t = false)]
|
||||
summary: bool,
|
||||
|
||||
/// Show a checksum of each table in the database.
|
||||
///
|
||||
/// WARNING: this option will take a long time to run, as it needs to traverse and hash the
|
||||
/// entire database.
|
||||
///
|
||||
/// For individual table checksums, use the `reth db checksum` command.
|
||||
#[arg(long, default_value_t = false)]
|
||||
checksum: bool,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
@ -27,6 +48,12 @@ impl Command {
|
||||
data_dir: ChainPath<DataDirPath>,
|
||||
tool: &DbTool<DatabaseEnv>,
|
||||
) -> eyre::Result<()> {
|
||||
if self.checksum {
|
||||
let checksum_report = self.checksum_report(tool)?;
|
||||
println!("{checksum_report}");
|
||||
println!("\n");
|
||||
}
|
||||
|
||||
let static_files_stats_table = self.static_files_stats_table(data_dir)?;
|
||||
println!("{static_files_stats_table}");
|
||||
|
||||
@ -285,4 +312,81 @@ impl Command {
|
||||
|
||||
Ok(table)
|
||||
}
|
||||
|
||||
fn checksum_report(&self, tool: &DbTool<DatabaseEnv>) -> eyre::Result<ComfyTable> {
|
||||
let mut table = ComfyTable::new();
|
||||
table.load_preset(comfy_table::presets::ASCII_MARKDOWN);
|
||||
table.set_header(vec![Cell::new("Table"), Cell::new("Checksum"), Cell::new("Elapsed")]);
|
||||
|
||||
let db_tables = Tables::ALL;
|
||||
let mut total_elapsed = Duration::default();
|
||||
|
||||
for db_table in db_tables {
|
||||
info!("Calculating checksum for table: {}", db_table);
|
||||
|
||||
let viewer = ChecksumViewer::new(tool);
|
||||
let (checksum, elapsed) = match db_table {
|
||||
Tables::AccountsHistory => viewer.get_checksum::<AccountsHistory>().unwrap(),
|
||||
Tables::AccountChangeSets => viewer.get_checksum::<AccountChangeSets>().unwrap(),
|
||||
Tables::AccountsTrie => viewer.get_checksum::<AccountsTrie>().unwrap(),
|
||||
Tables::BlockBodyIndices => viewer.get_checksum::<BlockBodyIndices>().unwrap(),
|
||||
Tables::BlockOmmers => viewer.get_checksum::<BlockOmmers>().unwrap(),
|
||||
Tables::BlockWithdrawals => viewer.get_checksum::<BlockWithdrawals>().unwrap(),
|
||||
Tables::Bytecodes => viewer.get_checksum::<Bytecodes>().unwrap(),
|
||||
Tables::CanonicalHeaders => viewer.get_checksum::<CanonicalHeaders>().unwrap(),
|
||||
Tables::HashedAccounts => viewer.get_checksum::<HashedAccounts>().unwrap(),
|
||||
Tables::HashedStorages => viewer.get_checksum::<HashedStorages>().unwrap(),
|
||||
Tables::HeaderNumbers => viewer.get_checksum::<HeaderNumbers>().unwrap(),
|
||||
Tables::HeaderTerminalDifficulties => {
|
||||
viewer.get_checksum::<HeaderTerminalDifficulties>().unwrap()
|
||||
}
|
||||
Tables::Headers => viewer.get_checksum::<Headers>().unwrap(),
|
||||
Tables::PlainAccountState => viewer.get_checksum::<PlainAccountState>().unwrap(),
|
||||
Tables::PlainStorageState => viewer.get_checksum::<PlainStorageState>().unwrap(),
|
||||
Tables::PruneCheckpoints => viewer.get_checksum::<PruneCheckpoints>().unwrap(),
|
||||
Tables::Receipts => viewer.get_checksum::<Receipts>().unwrap(),
|
||||
Tables::StageCheckpointProgresses => {
|
||||
viewer.get_checksum::<StageCheckpointProgresses>().unwrap()
|
||||
}
|
||||
Tables::StageCheckpoints => viewer.get_checksum::<StageCheckpoints>().unwrap(),
|
||||
Tables::StorageChangeSets => viewer.get_checksum::<StorageChangeSets>().unwrap(),
|
||||
Tables::StoragesHistory => viewer.get_checksum::<StoragesHistory>().unwrap(),
|
||||
Tables::StoragesTrie => viewer.get_checksum::<StoragesTrie>().unwrap(),
|
||||
Tables::TransactionBlocks => viewer.get_checksum::<TransactionBlocks>().unwrap(),
|
||||
Tables::TransactionHashNumbers => {
|
||||
viewer.get_checksum::<TransactionHashNumbers>().unwrap()
|
||||
}
|
||||
Tables::TransactionSenders => viewer.get_checksum::<TransactionSenders>().unwrap(),
|
||||
Tables::Transactions => viewer.get_checksum::<Transactions>().unwrap(),
|
||||
Tables::VersionHistory => viewer.get_checksum::<VersionHistory>().unwrap(),
|
||||
};
|
||||
|
||||
// increment duration for final report
|
||||
total_elapsed += elapsed;
|
||||
|
||||
// add rows containing checksums to the table
|
||||
let mut row = Row::new();
|
||||
row.add_cell(Cell::new(db_table));
|
||||
row.add_cell(Cell::new(format!("{:x}", checksum)));
|
||||
row.add_cell(Cell::new(format!("{:?}", elapsed)));
|
||||
table.add_row(row);
|
||||
}
|
||||
|
||||
// add a separator for the final report
|
||||
let max_widths = table.column_max_content_widths();
|
||||
let mut separator = Row::new();
|
||||
for width in max_widths {
|
||||
separator.add_cell(Cell::new(&"-".repeat(width as usize)));
|
||||
}
|
||||
table.add_row(separator);
|
||||
|
||||
// add the final report
|
||||
let mut row = Row::new();
|
||||
row.add_cell(Cell::new("Total elapsed"));
|
||||
row.add_cell(Cell::new(""));
|
||||
row.add_cell(Cell::new(format!("{:?}", total_elapsed)));
|
||||
table.add_row(row);
|
||||
|
||||
Ok(table)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user