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:
		@@ -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,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user