LCOV - code coverage report
Current view: top level - pageserver/src/tenant/timeline - analysis.rs (source / functions) Coverage Total Hit
Test: 1e20c4f2b28aa592527961bb32170ebbd2c9172f.info Lines: 0.0 % 61 0
Test Date: 2025-07-16 12:29:03 Functions: 0.0 % 7 0

            Line data    Source code
       1              : use std::collections::BTreeSet;
       2              : use std::ops::Range;
       3              : 
       4              : use utils::lsn::Lsn;
       5              : 
       6              : use super::Timeline;
       7              : use crate::tenant::timeline::layer_manager::LayerManagerLockHolder;
       8              : 
       9              : #[derive(serde::Serialize)]
      10              : pub(crate) struct RangeAnalysis {
      11              :     start: String,
      12              :     end: String,
      13              :     has_image: bool,
      14              :     num_of_deltas_above_image: usize,
      15              :     total_num_of_deltas: usize,
      16              :     num_of_l0: usize,
      17              : }
      18              : 
      19              : impl Timeline {
      20            0 :     pub(crate) async fn perf_info(&self) -> Vec<RangeAnalysis> {
      21              :         // First, collect all split points of the layers.
      22            0 :         let mut split_points = BTreeSet::new();
      23            0 :         let mut delta_ranges = Vec::new();
      24            0 :         let mut image_ranges = Vec::new();
      25              : 
      26              :         let num_of_l0;
      27            0 :         let all_layer_files = {
      28            0 :             let guard = self
      29            0 :                 .layers
      30            0 :                 .read(LayerManagerLockHolder::GetLayerMapInfo)
      31            0 :                 .await;
      32            0 :             num_of_l0 = guard.layer_map().unwrap().level0_deltas().len();
      33            0 :             guard.all_persistent_layers()
      34              :         };
      35            0 :         let lsn = self.get_last_record_lsn();
      36              : 
      37            0 :         for key in all_layer_files {
      38            0 :             split_points.insert(key.key_range.start);
      39            0 :             split_points.insert(key.key_range.end);
      40            0 :             if key.is_delta {
      41            0 :                 delta_ranges.push((key.key_range.clone(), key.lsn_range.clone()));
      42            0 :             } else {
      43            0 :                 image_ranges.push((key.key_range.clone(), key.lsn_range.start));
      44            0 :             }
      45              :         }
      46              : 
      47              :         // For each split range, compute the estimated read amplification.
      48            0 :         let split_points = split_points.into_iter().collect::<Vec<_>>();
      49              : 
      50            0 :         let mut result = Vec::new();
      51              : 
      52            0 :         for i in 0..(split_points.len() - 1) {
      53            0 :             let start = split_points[i];
      54            0 :             let end = split_points[i + 1];
      55              :             // Find the latest image layer that contains the information.
      56            0 :             let mut maybe_image_layers = image_ranges
      57            0 :                 .iter()
      58              :                 // We insert split points for all image layers, and therefore a `contains` check for the start point should be enough.
      59            0 :                 .filter(|(key_range, img_lsn)| key_range.contains(&start) && img_lsn <= &lsn)
      60            0 :                 .cloned()
      61            0 :                 .collect::<Vec<_>>();
      62            0 :             maybe_image_layers.sort_by(|a, b| a.1.cmp(&b.1));
      63            0 :             let image_layer = maybe_image_layers.last().cloned();
      64            0 :             let lsn_filter_start = image_layer
      65            0 :                 .as_ref()
      66            0 :                 .map(|(_, lsn)| *lsn)
      67            0 :                 .unwrap_or(Lsn::INVALID);
      68              : 
      69            0 :             fn overlaps_with(lsn_range_a: &Range<Lsn>, lsn_range_b: &Range<Lsn>) -> bool {
      70            0 :                 !(lsn_range_a.end <= lsn_range_b.start || lsn_range_a.start >= lsn_range_b.end)
      71            0 :             }
      72              : 
      73            0 :             let maybe_delta_layers = delta_ranges
      74            0 :                 .iter()
      75            0 :                 .filter(|(key_range, lsn_range)| {
      76            0 :                     key_range.contains(&start) && overlaps_with(&(lsn_filter_start..lsn), lsn_range)
      77            0 :                 })
      78            0 :                 .cloned()
      79            0 :                 .collect::<Vec<_>>();
      80              : 
      81            0 :             let pitr_delta_layers = delta_ranges
      82            0 :                 .iter()
      83            0 :                 .filter(|(key_range, _)| key_range.contains(&start))
      84            0 :                 .cloned()
      85            0 :                 .collect::<Vec<_>>();
      86              : 
      87            0 :             result.push(RangeAnalysis {
      88            0 :                 start: start.to_string(),
      89            0 :                 end: end.to_string(),
      90            0 :                 has_image: image_layer.is_some(),
      91            0 :                 num_of_deltas_above_image: maybe_delta_layers.len(),
      92            0 :                 total_num_of_deltas: pitr_delta_layers.len(),
      93            0 :                 num_of_l0,
      94            0 :             });
      95              :         }
      96              : 
      97            0 :         result
      98            0 :     }
      99              : }
        

Generated by: LCOV version 2.1-beta