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