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