LCOV - code coverage report
Current view: top level - pageserver/src/tenant/timeline - analysis.rs (source / functions) Coverage Total Hit
Test: 49aa928ec5b4b510172d8b5c6d154da28e70a46c.info Lines: 0.0 % 68 0
Test Date: 2024-11-13 18:23:39 Functions: 0.0 % 8 0

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

Generated by: LCOV version 2.1-beta