Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ledger-tool for restoring roots to the Roots CF #17045

Merged
merged 3 commits into from
May 6, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions ledger-tool/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,7 @@ fn main() {
}

const DEFAULT_ROOT_COUNT: &str = "1";
const DEFAULT_MAX_SLOTS_ROOT_REPAIR: &str = "2000";
solana_logger::setup_with_default("solana=info");

let starting_slot_arg = Arg::with_name("starting_slot")
Expand Down Expand Up @@ -1336,6 +1337,34 @@ fn main() {
.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::with_name("analyze-storage")
.about("Output statistics in JSON format about \
Expand Down Expand Up @@ -2796,6 +2825,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() {
CriesofCarrots marked this conversation as resolved.
Show resolved Hide resolved
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!(
CriesofCarrots marked this conversation as resolved.
Show resolved Hide resolved
"No missing roots found in range {} to {}",
end_root, start_root
);
}
}
("bounds", Some(arg_matches)) => {
let blockstore = open_blockstore(
&ledger_path,
Expand Down