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 : }
|