Add ledger tool command print-file-metadata (#26790)
Add ledger-tool command print-file-metadata #### Summary of Changes This PR adds a ledger tool subcommand print-file-metadata. ``` USAGE: solana-ledger-tool print-file-metadata [FLAGS] [OPTIONS] [SST_FILE_NAME] Prints the metadata of the specified ledger-store file. If no file name is unspecified, then it will print the metadata of all ledger files ```
This commit is contained in:
parent
204f272412
commit
ed00365101
|
@ -26,7 +26,7 @@ use {
|
|||
ancestor_iterator::AncestorIterator,
|
||||
bank_forks_utils,
|
||||
blockstore::{create_new_ledger, Blockstore, BlockstoreError, PurgeType},
|
||||
blockstore_db::{self, Database},
|
||||
blockstore_db::{self, columns as cf, Column, ColumnName, Database},
|
||||
blockstore_options::{
|
||||
AccessType, BlockstoreOptions, BlockstoreRecoveryMode, LedgerColumnOptions,
|
||||
ShredStorageType,
|
||||
|
@ -900,6 +900,74 @@ fn open_blockstore(
|
|||
}
|
||||
}
|
||||
|
||||
fn raw_key_to_slot(key: &[u8], column_name: &str) -> Option<Slot> {
|
||||
match column_name {
|
||||
cf::SlotMeta::NAME => Some(cf::SlotMeta::slot(cf::SlotMeta::index(key))),
|
||||
cf::Orphans::NAME => Some(cf::Orphans::slot(cf::Orphans::index(key))),
|
||||
cf::DeadSlots::NAME => Some(cf::SlotMeta::slot(cf::SlotMeta::index(key))),
|
||||
cf::DuplicateSlots::NAME => Some(cf::SlotMeta::slot(cf::SlotMeta::index(key))),
|
||||
cf::ErasureMeta::NAME => Some(cf::ErasureMeta::slot(cf::ErasureMeta::index(key))),
|
||||
cf::BankHash::NAME => Some(cf::BankHash::slot(cf::BankHash::index(key))),
|
||||
cf::Root::NAME => Some(cf::Root::slot(cf::Root::index(key))),
|
||||
cf::Index::NAME => Some(cf::Index::slot(cf::Index::index(key))),
|
||||
cf::ShredData::NAME => Some(cf::ShredData::slot(cf::ShredData::index(key))),
|
||||
cf::ShredCode::NAME => Some(cf::ShredCode::slot(cf::ShredCode::index(key))),
|
||||
cf::TransactionStatus::NAME => Some(cf::TransactionStatus::slot(
|
||||
cf::TransactionStatus::index(key),
|
||||
)),
|
||||
cf::AddressSignatures::NAME => Some(cf::AddressSignatures::slot(
|
||||
cf::AddressSignatures::index(key),
|
||||
)),
|
||||
cf::TransactionMemos::NAME => None, // does not implement slot()
|
||||
cf::TransactionStatusIndex::NAME => None, // does not implement slot()
|
||||
cf::Rewards::NAME => Some(cf::Rewards::slot(cf::Rewards::index(key))),
|
||||
cf::Blocktime::NAME => Some(cf::Blocktime::slot(cf::Blocktime::index(key))),
|
||||
cf::PerfSamples::NAME => Some(cf::PerfSamples::slot(cf::PerfSamples::index(key))),
|
||||
cf::BlockHeight::NAME => Some(cf::BlockHeight::slot(cf::BlockHeight::index(key))),
|
||||
cf::ProgramCosts::NAME => None, // does not implement slot()
|
||||
cf::OptimisticSlots::NAME => {
|
||||
Some(cf::OptimisticSlots::slot(cf::OptimisticSlots::index(key)))
|
||||
}
|
||||
&_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn print_blockstore_file_metadata(
|
||||
blockstore: &Blockstore,
|
||||
file_name: &Option<&str>,
|
||||
) -> Result<(), String> {
|
||||
let live_files = blockstore
|
||||
.live_files_metadata()
|
||||
.map_err(|err| format!("{:?}", err))?;
|
||||
|
||||
// All files under live_files_metadata are prefixed with "/".
|
||||
let sst_file_name = file_name.as_ref().map(|name| format!("/{}", name));
|
||||
for file in live_files {
|
||||
if sst_file_name.is_none() || file.name.eq(sst_file_name.as_ref().unwrap()) {
|
||||
println!(
|
||||
"[{}] cf_name: {}, level: {}, start_slot: {:?}, end_slot: {:?}, size: {}, num_entries: {}",
|
||||
file.name,
|
||||
file.column_family_name,
|
||||
file.level,
|
||||
raw_key_to_slot(&file.start_key.unwrap(), &file.column_family_name),
|
||||
raw_key_to_slot(&file.end_key.unwrap(), &file.column_family_name),
|
||||
file.size,
|
||||
file.num_entries,
|
||||
);
|
||||
if sst_file_name.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
if sst_file_name.is_some() {
|
||||
return Err(format!(
|
||||
"Failed to find or load the metadata of the specified file {:?}",
|
||||
file_name
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This function is duplicated in validator/src/main.rs...
|
||||
fn hardforks_of(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<Slot>> {
|
||||
if matches.is_present(name) {
|
||||
|
@ -2107,6 +2175,19 @@ fn main() {
|
|||
.help("Slots that their blocks are computed for cost, default to all slots in ledger"),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("print-file-metadata")
|
||||
.about("Print the metadata of the specified ledger-store file. \
|
||||
If no file name is specified, it will print the metadata of all ledger files.")
|
||||
.arg(
|
||||
Arg::with_name("file_name")
|
||||
.long("file-name")
|
||||
.takes_value(true)
|
||||
.value_name("SST_FILE_NAME")
|
||||
.help("The ledger file name (e.g. 011080.sst.) \
|
||||
If no file name is specified, it will print the metadata of all ledger files.")
|
||||
)
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
info!("{} {}", crate_name!(), solana_version::version!());
|
||||
|
@ -4131,6 +4212,19 @@ fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
("print-file-metadata", Some(arg_matches)) => {
|
||||
let blockstore = open_blockstore(
|
||||
&ledger_path,
|
||||
AccessType::Secondary,
|
||||
wal_recovery_mode,
|
||||
&shred_storage_type,
|
||||
false,
|
||||
);
|
||||
let sst_file_name = arg_matches.value_of("file_name");
|
||||
if let Err(err) = print_blockstore_file_metadata(&blockstore, &sst_file_name) {
|
||||
eprintln!("{}", err);
|
||||
}
|
||||
}
|
||||
("", _) => {
|
||||
eprintln!("{}", matches.usage());
|
||||
exit(1);
|
||||
|
|
|
@ -30,7 +30,7 @@ use {
|
|||
iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator},
|
||||
ThreadPool,
|
||||
},
|
||||
rocksdb::DBRawIterator,
|
||||
rocksdb::{DBRawIterator, LiveFile},
|
||||
solana_entry::entry::{create_ticks, Entry},
|
||||
solana_measure::measure::Measure,
|
||||
solana_metrics::{
|
||||
|
@ -500,6 +500,10 @@ impl Blockstore {
|
|||
root_forks.chain(orphans_iter.flat_map(move |orphan| NextSlotsIterator::new(orphan, self)))
|
||||
}
|
||||
|
||||
pub fn live_files_metadata(&self) -> Result<Vec<LiveFile>> {
|
||||
self.db.live_files_metadata()
|
||||
}
|
||||
|
||||
pub fn slot_data_iterator(
|
||||
&self,
|
||||
slot: Slot,
|
||||
|
|
|
@ -21,7 +21,7 @@ use {
|
|||
compaction_filter_factory::{CompactionFilterContext, CompactionFilterFactory},
|
||||
properties as RocksProperties, ColumnFamily, ColumnFamilyDescriptor, CompactionDecision,
|
||||
DBCompactionStyle, DBIterator, DBRawIterator, FifoCompactOptions,
|
||||
IteratorMode as RocksIteratorMode, Options, WriteBatch as RWriteBatch, DB,
|
||||
IteratorMode as RocksIteratorMode, LiveFile, Options, WriteBatch as RWriteBatch, DB,
|
||||
},
|
||||
serde::{de::DeserializeOwned, Serialize},
|
||||
solana_runtime::hardened_unpack::UnpackError,
|
||||
|
@ -527,6 +527,13 @@ impl Rocks {
|
|||
Err(e) => Err(BlockstoreError::RocksDb(e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn live_files_metadata(&self) -> Result<Vec<LiveFile>> {
|
||||
match self.db.live_files() {
|
||||
Ok(live_files) => Ok(live_files),
|
||||
Err(e) => Err(BlockstoreError::RocksDb(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Column {
|
||||
|
@ -1155,6 +1162,10 @@ impl Database {
|
|||
pub fn set_oldest_slot(&self, oldest_slot: Slot) {
|
||||
self.backend.oldest_slot.set(oldest_slot);
|
||||
}
|
||||
|
||||
pub fn live_files_metadata(&self) -> Result<Vec<LiveFile>> {
|
||||
self.backend.live_files_metadata()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> LedgerColumn<C>
|
||||
|
|
Loading…
Reference in New Issue