LCOV - differential code coverage report
Current view: top level - pageserver/ctl/src - main.rs (source / functions) Coverage Total Hit UBC CBC
Current: cd44433dd675caa99df17a61b18949c8387e2242.info Lines: 11.8 % 102 12 90 12
Current Date: 2024-01-09 02:06:09 Functions: 17.3 % 52 9 43 9
Baseline: 66c52a629a0f4a503e193045e0df4c77139e344b.info
Baseline Date: 2024-01-08 15:34:46

           TLA  Line data    Source code
       1                 : //! A helper tool to manage pageserver binary files.
       2                 : //! Accepts a file as an argument, attempts to parse it with all ways possible
       3                 : //! and prints its interpreted context.
       4                 : //!
       5                 : //! Separate, `metadata` subcommand allows to print and update pageserver's metadata file.
       6                 : 
       7                 : mod draw_timeline_dir;
       8                 : mod index_part;
       9                 : mod layer_map_analyzer;
      10                 : mod layers;
      11                 : 
      12                 : use camino::{Utf8Path, Utf8PathBuf};
      13                 : use clap::{Parser, Subcommand};
      14                 : use index_part::IndexPartCmd;
      15                 : use layers::LayerCmd;
      16                 : use pageserver::{
      17                 :     context::{DownloadBehavior, RequestContext},
      18                 :     page_cache,
      19                 :     task_mgr::TaskKind,
      20                 :     tenant::{dump_layerfile_from_path, metadata::TimelineMetadata},
      21                 :     virtual_file,
      22                 : };
      23                 : use postgres_ffi::ControlFileData;
      24                 : use utils::{lsn::Lsn, project_git_version};
      25                 : 
      26                 : project_git_version!(GIT_VERSION);
      27                 : 
      28 CBC           6 : #[derive(Parser)]
      29                 : #[command(
      30                 :     version = GIT_VERSION,
      31                 :     about = "Neon Pageserver binutils",
      32                 :     long_about = "Reads pageserver (and related) binary files management utility"
      33                 : )]
      34                 : #[command(propagate_version = true)]
      35                 : struct CliOpts {
      36                 :     #[command(subcommand)]
      37                 :     command: Commands,
      38                 : }
      39                 : 
      40              12 : #[derive(Subcommand)]
      41                 : enum Commands {
      42                 :     Metadata(MetadataCmd),
      43                 :     #[command(subcommand)]
      44                 :     IndexPart(IndexPartCmd),
      45                 :     PrintLayerFile(PrintLayerFileCmd),
      46                 :     DrawTimeline {},
      47                 :     AnalyzeLayerMap(AnalyzeLayerMapCmd),
      48                 :     #[command(subcommand)]
      49                 :     Layer(LayerCmd),
      50                 : }
      51                 : 
      52                 : /// Read and update pageserver metadata file
      53               6 : #[derive(Parser)]
      54                 : struct MetadataCmd {
      55                 :     /// Input metadata file path
      56 UBC           0 :     metadata_path: Utf8PathBuf,
      57                 :     /// Replace disk consistent Lsn
      58                 :     disk_consistent_lsn: Option<Lsn>,
      59                 :     /// Replace previous record Lsn
      60                 :     prev_record_lsn: Option<Lsn>,
      61                 :     /// Replace latest gc cuttoff
      62                 :     latest_gc_cuttoff: Option<Lsn>,
      63                 : }
      64                 : 
      65 CBC           6 : #[derive(Parser)]
      66                 : struct PrintLayerFileCmd {
      67                 :     /// Pageserver data path
      68 UBC           0 :     path: Utf8PathBuf,
      69                 : }
      70                 : 
      71 CBC           6 : #[derive(Parser)]
      72                 : struct AnalyzeLayerMapCmd {
      73                 :     /// Pageserver data path
      74 UBC           0 :     path: Utf8PathBuf,
      75                 :     /// Max holes
      76                 :     max_holes: Option<usize>,
      77                 : }
      78                 : 
      79                 : #[tokio::main]
      80 CBC           6 : async fn main() -> anyhow::Result<()> {
      81               6 :     let cli = CliOpts::parse();
      82               6 : 
      83               6 :     match cli.command {
      84 UBC           0 :         Commands::Layer(cmd) => {
      85               0 :             layers::main(&cmd).await?;
      86                 :         }
      87               0 :         Commands::Metadata(cmd) => {
      88               0 :             handle_metadata(&cmd)?;
      89                 :         }
      90 CBC           6 :         Commands::IndexPart(cmd) => {
      91               6 :             index_part::main(&cmd).await?;
      92                 :         }
      93                 :         Commands::DrawTimeline {} => {
      94 UBC           0 :             draw_timeline_dir::main()?;
      95                 :         }
      96               0 :         Commands::AnalyzeLayerMap(cmd) => {
      97               0 :             layer_map_analyzer::main(&cmd).await?;
      98                 :         }
      99               0 :         Commands::PrintLayerFile(cmd) => {
     100               0 :             if let Err(e) = read_pg_control_file(&cmd.path) {
     101               0 :                 println!(
     102               0 :                     "Failed to read input file as a pg control one: {e:#}\n\
     103               0 :                     Attempting to read it as layer file"
     104               0 :                 );
     105               0 :                 print_layerfile(&cmd.path).await?;
     106               0 :             }
     107                 :         }
     108                 :     };
     109 CBC           6 :     Ok(())
     110                 : }
     111                 : 
     112 UBC           0 : fn read_pg_control_file(control_file_path: &Utf8Path) -> anyhow::Result<()> {
     113               0 :     let control_file = ControlFileData::decode(&std::fs::read(control_file_path)?)?;
     114               0 :     println!("{control_file:?}");
     115               0 :     let control_file_initdb = Lsn(control_file.checkPoint);
     116               0 :     println!(
     117               0 :         "pg_initdb_lsn: {}, aligned: {}",
     118               0 :         control_file_initdb,
     119               0 :         control_file_initdb.align()
     120               0 :     );
     121               0 :     Ok(())
     122               0 : }
     123                 : 
     124               0 : async fn print_layerfile(path: &Utf8Path) -> anyhow::Result<()> {
     125               0 :     // Basic initialization of things that don't change after startup
     126               0 :     virtual_file::init(10);
     127               0 :     page_cache::init(100);
     128               0 :     let ctx = RequestContext::new(TaskKind::DebugTool, DownloadBehavior::Error);
     129               0 :     dump_layerfile_from_path(path, true, &ctx).await
     130               0 : }
     131                 : 
     132               0 : fn handle_metadata(
     133               0 :     MetadataCmd {
     134               0 :         metadata_path: path,
     135               0 :         disk_consistent_lsn,
     136               0 :         prev_record_lsn,
     137               0 :         latest_gc_cuttoff,
     138               0 :     }: &MetadataCmd,
     139               0 : ) -> Result<(), anyhow::Error> {
     140               0 :     let metadata_bytes = std::fs::read(path)?;
     141               0 :     let mut meta = TimelineMetadata::from_bytes(&metadata_bytes)?;
     142               0 :     println!("Current metadata:\n{meta:?}");
     143               0 :     let mut update_meta = false;
     144               0 :     if let Some(disk_consistent_lsn) = disk_consistent_lsn {
     145               0 :         meta = TimelineMetadata::new(
     146               0 :             *disk_consistent_lsn,
     147               0 :             meta.prev_record_lsn(),
     148               0 :             meta.ancestor_timeline(),
     149               0 :             meta.ancestor_lsn(),
     150               0 :             meta.latest_gc_cutoff_lsn(),
     151               0 :             meta.initdb_lsn(),
     152               0 :             meta.pg_version(),
     153               0 :         );
     154               0 :         update_meta = true;
     155               0 :     }
     156               0 :     if let Some(prev_record_lsn) = prev_record_lsn {
     157               0 :         meta = TimelineMetadata::new(
     158               0 :             meta.disk_consistent_lsn(),
     159               0 :             Some(*prev_record_lsn),
     160               0 :             meta.ancestor_timeline(),
     161               0 :             meta.ancestor_lsn(),
     162               0 :             meta.latest_gc_cutoff_lsn(),
     163               0 :             meta.initdb_lsn(),
     164               0 :             meta.pg_version(),
     165               0 :         );
     166               0 :         update_meta = true;
     167               0 :     }
     168               0 :     if let Some(latest_gc_cuttoff) = latest_gc_cuttoff {
     169               0 :         meta = TimelineMetadata::new(
     170               0 :             meta.disk_consistent_lsn(),
     171               0 :             meta.prev_record_lsn(),
     172               0 :             meta.ancestor_timeline(),
     173               0 :             meta.ancestor_lsn(),
     174               0 :             *latest_gc_cuttoff,
     175               0 :             meta.initdb_lsn(),
     176               0 :             meta.pg_version(),
     177               0 :         );
     178               0 :         update_meta = true;
     179               0 :     }
     180                 : 
     181               0 :     if update_meta {
     182               0 :         let metadata_bytes = meta.to_bytes()?;
     183               0 :         std::fs::write(path, metadata_bytes)?;
     184               0 :     }
     185                 : 
     186               0 :     Ok(())
     187               0 : }
        

Generated by: LCOV version 2.1-beta