Add ledger-tool for restoring roots to the Roots CF (#17045)
* Add ledger-tool for restoring roots to the Roots CF * Print successful repair data, and repair in chunks * Add parameter to limit num slots checked for root repair
This commit is contained in:
parent
dc0429f5e6
commit
ddfbae260f
|
@ -729,6 +729,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_ROOT_COUNT: &str = "1";
|
const DEFAULT_ROOT_COUNT: &str = "1";
|
||||||
|
const DEFAULT_MAX_SLOTS_ROOT_REPAIR: &str = "2000";
|
||||||
solana_logger::setup_with_default("solana=info");
|
solana_logger::setup_with_default("solana=info");
|
||||||
|
|
||||||
let starting_slot_arg = Arg::with_name("starting_slot")
|
let starting_slot_arg = Arg::with_name("starting_slot")
|
||||||
|
@ -1336,6 +1337,34 @@ fn main() {
|
||||||
.help("Number of roots in the output"),
|
.help("Number of roots in the output"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("repair-roots")
|
||||||
|
.about("Traverses the AncestorIterator backward from a last known root \
|
||||||
|
to restore missing roots to the Root column")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("start_root")
|
||||||
|
.long("before")
|
||||||
|
.value_name("NUM")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("First good root after the range to repair")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("end_root")
|
||||||
|
.long("until")
|
||||||
|
.value_name("NUM")
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Last slot to check for root repair")
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("max_slots")
|
||||||
|
.long("repair-limit")
|
||||||
|
.value_name("NUM")
|
||||||
|
.takes_value(true)
|
||||||
|
.default_value(DEFAULT_MAX_SLOTS_ROOT_REPAIR)
|
||||||
|
.required(true)
|
||||||
|
.help("Override the maximum number of slots to check for root repair")
|
||||||
|
)
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("analyze-storage")
|
SubCommand::with_name("analyze-storage")
|
||||||
.about("Output statistics in JSON format about \
|
.about("Output statistics in JSON format about \
|
||||||
|
@ -2798,6 +2827,56 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
("repair-roots", Some(arg_matches)) => {
|
||||||
|
let blockstore = open_blockstore(
|
||||||
|
&ledger_path,
|
||||||
|
AccessType::TryPrimaryThenSecondary,
|
||||||
|
wal_recovery_mode,
|
||||||
|
);
|
||||||
|
let start_root = if let Some(root) = arg_matches.value_of("start_root") {
|
||||||
|
Slot::from_str(root).expect("Before root must be a number")
|
||||||
|
} else {
|
||||||
|
blockstore.max_root()
|
||||||
|
};
|
||||||
|
let max_slots = value_t_or_exit!(arg_matches, "max_slots", u64);
|
||||||
|
let end_root = if let Some(root) = arg_matches.value_of("end_root") {
|
||||||
|
Slot::from_str(root).expect("Until root must be a number")
|
||||||
|
} else {
|
||||||
|
start_root.saturating_sub(max_slots)
|
||||||
|
};
|
||||||
|
assert!(start_root > end_root);
|
||||||
|
assert!(blockstore.is_root(start_root));
|
||||||
|
let num_slots = start_root - end_root - 1; // Adjust by one since start_root need not be checked
|
||||||
|
if arg_matches.is_present("end_root") && num_slots > max_slots {
|
||||||
|
eprintln!(
|
||||||
|
"Requested range {} too large, max {}. \
|
||||||
|
Either adjust `--until` value, or pass a larger `--repair-limit` \
|
||||||
|
to override the limit",
|
||||||
|
num_slots, max_slots,
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let ancestor_iterator =
|
||||||
|
AncestorIterator::new(start_root, &blockstore).take_while(|&slot| slot >= end_root);
|
||||||
|
let roots_to_fix: Vec<_> = ancestor_iterator
|
||||||
|
.filter(|slot| !blockstore.is_root(*slot))
|
||||||
|
.collect();
|
||||||
|
if !roots_to_fix.is_empty() {
|
||||||
|
eprintln!("{} slots to be rooted", roots_to_fix.len());
|
||||||
|
for chunk in roots_to_fix.chunks(100) {
|
||||||
|
eprintln!("{:?}", chunk);
|
||||||
|
blockstore.set_roots(&roots_to_fix).unwrap_or_else(|err| {
|
||||||
|
eprintln!("Unable to set roots {:?}: {}", roots_to_fix, err);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
"No missing roots found in range {} to {}",
|
||||||
|
end_root, start_root
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
("bounds", Some(arg_matches)) => {
|
("bounds", Some(arg_matches)) => {
|
||||||
let blockstore = open_blockstore(
|
let blockstore = open_blockstore(
|
||||||
&ledger_path,
|
&ledger_path,
|
||||||
|
|
Loading…
Reference in New Issue