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