LCOV - differential code coverage report
Current view: top level - pageserver/ctl/src - layers.rs (source / functions) Coverage Total Hit UBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 0.0 % 117 0 117
Current Date: 2023-10-19 02:04:12 Functions: 0.0 % 28 0 28
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           TLA  Line data    Source code
       1                 : use std::path::{Path, PathBuf};
       2                 : 
       3                 : use anyhow::Result;
       4                 : use camino::Utf8Path;
       5                 : use clap::Subcommand;
       6                 : use pageserver::context::{DownloadBehavior, RequestContext};
       7                 : use pageserver::task_mgr::TaskKind;
       8                 : use pageserver::tenant::block_io::BlockCursor;
       9                 : use pageserver::tenant::disk_btree::DiskBtreeReader;
      10                 : use pageserver::tenant::storage_layer::delta_layer::{BlobRef, Summary};
      11                 : use pageserver::tenant::{TENANTS_SEGMENT_NAME, TIMELINES_SEGMENT_NAME};
      12                 : use pageserver::{page_cache, virtual_file};
      13                 : use pageserver::{
      14                 :     repository::{Key, KEY_SIZE},
      15                 :     tenant::{
      16                 :         block_io::FileBlockReader, disk_btree::VisitDirection,
      17                 :         storage_layer::delta_layer::DELTA_KEY_SIZE,
      18                 :     },
      19                 :     virtual_file::VirtualFile,
      20                 : };
      21                 : use std::fs;
      22                 : use utils::bin_ser::BeSer;
      23                 : 
      24                 : use crate::layer_map_analyzer::parse_filename;
      25                 : 
      26 UBC           0 : #[derive(Subcommand)]
      27                 : pub(crate) enum LayerCmd {
      28                 :     /// List all tenants and timelines under the pageserver path
      29                 :     ///
      30                 :     /// Example: `cargo run --bin pagectl layer list .neon/`
      31               0 :     List { path: PathBuf },
      32                 :     /// List all layers of a given tenant and timeline
      33                 :     ///
      34                 :     /// Example: `cargo run --bin pagectl layer list .neon/`
      35                 :     ListLayer {
      36               0 :         path: PathBuf,
      37               0 :         tenant: String,
      38               0 :         timeline: String,
      39                 :     },
      40                 :     /// Dump all information of a layer file
      41                 :     DumpLayer {
      42               0 :         path: PathBuf,
      43               0 :         tenant: String,
      44               0 :         timeline: String,
      45                 :         /// The id from list-layer command
      46               0 :         id: usize,
      47               0 :     },
      48                 : }
      49                 : 
      50               0 : async fn read_delta_file(path: impl AsRef<Path>, ctx: &RequestContext) -> Result<()> {
      51               0 :     let path = Utf8Path::from_path(path.as_ref()).expect("non-Unicode path");
      52               0 :     virtual_file::init(10);
      53               0 :     page_cache::init(100);
      54               0 :     let file = FileBlockReader::new(VirtualFile::open(path).await?);
      55               0 :     let summary_blk = file.read_blk(0, ctx).await?;
      56               0 :     let actual_summary = Summary::des_prefix(summary_blk.as_ref())?;
      57               0 :     let tree_reader = DiskBtreeReader::<_, DELTA_KEY_SIZE>::new(
      58               0 :         actual_summary.index_start_blk,
      59               0 :         actual_summary.index_root_blk,
      60               0 :         &file,
      61               0 :     );
      62               0 :     // TODO(chi): dedup w/ `delta_layer.rs` by exposing the API.
      63               0 :     let mut all = vec![];
      64               0 :     tree_reader
      65               0 :         .visit(
      66               0 :             &[0u8; DELTA_KEY_SIZE],
      67               0 :             VisitDirection::Forwards,
      68               0 :             |key, value_offset| {
      69               0 :                 let curr = Key::from_slice(&key[..KEY_SIZE]);
      70               0 :                 all.push((curr, BlobRef(value_offset)));
      71               0 :                 true
      72               0 :             },
      73               0 :             ctx,
      74               0 :         )
      75               0 :         .await?;
      76               0 :     let cursor = BlockCursor::new_fileblockreader(&file);
      77               0 :     for (k, v) in all {
      78               0 :         let value = cursor.read_blob(v.pos(), ctx).await?;
      79               0 :         println!("key:{} value_len:{}", k, value.len());
      80                 :     }
      81                 :     // TODO(chi): special handling for last key?
      82               0 :     Ok(())
      83               0 : }
      84                 : 
      85               0 : pub(crate) async fn main(cmd: &LayerCmd) -> Result<()> {
      86               0 :     let ctx = RequestContext::new(TaskKind::DebugTool, DownloadBehavior::Error);
      87               0 :     match cmd {
      88               0 :         LayerCmd::List { path } => {
      89               0 :             for tenant in fs::read_dir(path.join(TENANTS_SEGMENT_NAME))? {
      90               0 :                 let tenant = tenant?;
      91               0 :                 if !tenant.file_type()?.is_dir() {
      92               0 :                     continue;
      93               0 :                 }
      94               0 :                 println!("tenant {}", tenant.file_name().to_string_lossy());
      95               0 :                 for timeline in fs::read_dir(tenant.path().join(TIMELINES_SEGMENT_NAME))? {
      96               0 :                     let timeline = timeline?;
      97               0 :                     if !timeline.file_type()?.is_dir() {
      98               0 :                         continue;
      99               0 :                     }
     100               0 :                     println!("- timeline {}", timeline.file_name().to_string_lossy());
     101                 :                 }
     102                 :             }
     103                 :         }
     104                 :         LayerCmd::ListLayer {
     105               0 :             path,
     106               0 :             tenant,
     107               0 :             timeline,
     108               0 :         } => {
     109               0 :             let timeline_path = path
     110               0 :                 .join(TENANTS_SEGMENT_NAME)
     111               0 :                 .join(tenant)
     112               0 :                 .join(TIMELINES_SEGMENT_NAME)
     113               0 :                 .join(timeline);
     114               0 :             let mut idx = 0;
     115               0 :             for layer in fs::read_dir(timeline_path)? {
     116               0 :                 let layer = layer?;
     117               0 :                 if let Some(layer_file) = parse_filename(&layer.file_name().into_string().unwrap())
     118               0 :                 {
     119               0 :                     println!(
     120               0 :                         "[{:3}]  key:{}-{}\n       lsn:{}-{}\n       delta:{}",
     121               0 :                         idx,
     122               0 :                         layer_file.key_range.start,
     123               0 :                         layer_file.key_range.end,
     124               0 :                         layer_file.lsn_range.start,
     125               0 :                         layer_file.lsn_range.end,
     126               0 :                         layer_file.is_delta,
     127               0 :                     );
     128               0 :                     idx += 1;
     129               0 :                 }
     130                 :             }
     131                 :         }
     132                 :         LayerCmd::DumpLayer {
     133               0 :             path,
     134               0 :             tenant,
     135               0 :             timeline,
     136               0 :             id,
     137               0 :         } => {
     138               0 :             let timeline_path = path
     139               0 :                 .join("tenants")
     140               0 :                 .join(tenant)
     141               0 :                 .join("timelines")
     142               0 :                 .join(timeline);
     143               0 :             let mut idx = 0;
     144               0 :             for layer in fs::read_dir(timeline_path)? {
     145               0 :                 let layer = layer?;
     146               0 :                 if let Some(layer_file) = parse_filename(&layer.file_name().into_string().unwrap())
     147                 :                 {
     148               0 :                     if *id == idx {
     149                 :                         // TODO(chi): dedup code
     150               0 :                         println!(
     151               0 :                             "[{:3}]  key:{}-{}\n       lsn:{}-{}\n       delta:{}",
     152               0 :                             idx,
     153               0 :                             layer_file.key_range.start,
     154               0 :                             layer_file.key_range.end,
     155               0 :                             layer_file.lsn_range.start,
     156               0 :                             layer_file.lsn_range.end,
     157               0 :                             layer_file.is_delta,
     158               0 :                         );
     159               0 : 
     160               0 :                         if layer_file.is_delta {
     161               0 :                             read_delta_file(layer.path(), &ctx).await?;
     162                 :                         } else {
     163               0 :                             anyhow::bail!("not supported yet :(");
     164                 :                         }
     165                 : 
     166               0 :                         break;
     167               0 :                     }
     168               0 :                     idx += 1;
     169               0 :                 }
     170                 :             }
     171                 :         }
     172                 :     }
     173               0 :     Ok(())
     174               0 : }
        

Generated by: LCOV version 2.1-beta