Line data Source code
1 : use super::*;
2 : use std::collections::HashMap;
3 :
4 : #[test]
5 6 : fn startup_collected_timeline_metrics_before_advancing() {
6 6 : let tenant_id = TenantId::generate();
7 6 : let timeline_id = TimelineId::generate();
8 6 :
9 6 : let mut metrics = Vec::new();
10 6 : let cache = HashMap::new();
11 6 :
12 6 : let initdb_lsn = Lsn(0x10000);
13 6 : let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2);
14 6 :
15 6 : let snap = TimelineSnapshot {
16 6 : loaded_at: (disk_consistent_lsn, SystemTime::now()),
17 6 : last_record_lsn: disk_consistent_lsn,
18 6 : current_exact_logical_size: Some(0x42000),
19 6 : };
20 6 :
21 6 : let now = DateTime::<Utc>::from(SystemTime::now());
22 6 :
23 6 : snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
24 6 :
25 6 : assert_eq!(
26 6 : metrics,
27 6 : &[
28 6 : MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(
29 6 : snap.loaded_at.1.into(),
30 6 : now,
31 6 : 0
32 6 : ),
33 6 : MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0),
34 6 : MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000)
35 6 : ]
36 6 : );
37 6 : }
38 :
39 : #[test]
40 6 : fn startup_collected_timeline_metrics_second_round() {
41 6 : let tenant_id = TenantId::generate();
42 6 : let timeline_id = TimelineId::generate();
43 6 :
44 6 : let [now, before, init] = time_backwards();
45 6 :
46 6 : let now = DateTime::<Utc>::from(now);
47 6 : let before = DateTime::<Utc>::from(before);
48 6 :
49 6 : let initdb_lsn = Lsn(0x10000);
50 6 : let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2);
51 6 :
52 6 : let mut metrics = Vec::new();
53 6 : let cache = HashMap::from([
54 6 : MetricsKey::written_size(tenant_id, timeline_id).at(before, disk_consistent_lsn.0)
55 6 : ]);
56 6 :
57 6 : let snap = TimelineSnapshot {
58 6 : loaded_at: (disk_consistent_lsn, init),
59 6 : last_record_lsn: disk_consistent_lsn,
60 6 : current_exact_logical_size: Some(0x42000),
61 6 : };
62 6 :
63 6 : snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
64 6 :
65 6 : assert_eq!(
66 6 : metrics,
67 6 : &[
68 6 : MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(before, now, 0),
69 6 : MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0),
70 6 : MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000)
71 6 : ]
72 6 : );
73 6 : }
74 :
75 : #[test]
76 6 : fn startup_collected_timeline_metrics_nth_round_at_same_lsn() {
77 6 : let tenant_id = TenantId::generate();
78 6 : let timeline_id = TimelineId::generate();
79 6 :
80 6 : let [now, just_before, before, init] = time_backwards();
81 6 :
82 6 : let now = DateTime::<Utc>::from(now);
83 6 : let just_before = DateTime::<Utc>::from(just_before);
84 6 : let before = DateTime::<Utc>::from(before);
85 6 :
86 6 : let initdb_lsn = Lsn(0x10000);
87 6 : let disk_consistent_lsn = Lsn(initdb_lsn.0 * 2);
88 6 :
89 6 : let mut metrics = Vec::new();
90 6 : let cache = HashMap::from([
91 6 : // at t=before was the last time the last_record_lsn changed
92 6 : MetricsKey::written_size(tenant_id, timeline_id).at(before, disk_consistent_lsn.0),
93 6 : // end time of this event is used for the next ones
94 6 : MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(before, just_before, 0),
95 6 : ]);
96 6 :
97 6 : let snap = TimelineSnapshot {
98 6 : loaded_at: (disk_consistent_lsn, init),
99 6 : last_record_lsn: disk_consistent_lsn,
100 6 : current_exact_logical_size: Some(0x42000),
101 6 : };
102 6 :
103 6 : snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
104 6 :
105 6 : assert_eq!(
106 6 : metrics,
107 6 : &[
108 6 : MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(just_before, now, 0),
109 6 : MetricsKey::written_size(tenant_id, timeline_id).at(now, disk_consistent_lsn.0),
110 6 : MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0x42000)
111 6 : ]
112 6 : );
113 6 : }
114 :
115 : #[test]
116 6 : fn post_restart_written_sizes_with_rolled_back_last_record_lsn() {
117 6 : // it can happen that we lose the inmemorylayer but have previously sent metrics and we
118 6 : // should never go backwards
119 6 :
120 6 : let tenant_id = TenantId::generate();
121 6 : let timeline_id = TimelineId::generate();
122 6 :
123 6 : let [later, now, at_restart] = time_backwards();
124 6 :
125 6 : // FIXME: tests would be so much easier if we did not need to juggle back and forth
126 6 : // SystemTime and DateTime::<Utc> ... Could do the conversion only at upload time?
127 6 : let now = DateTime::<Utc>::from(now);
128 6 : let later = DateTime::<Utc>::from(later);
129 6 : let before_restart = at_restart - std::time::Duration::from_secs(5 * 60);
130 6 : let way_before = before_restart - std::time::Duration::from_secs(10 * 60);
131 6 : let before_restart = DateTime::<Utc>::from(before_restart);
132 6 : let way_before = DateTime::<Utc>::from(way_before);
133 6 :
134 6 : let snap = TimelineSnapshot {
135 6 : loaded_at: (Lsn(50), at_restart),
136 6 : last_record_lsn: Lsn(50),
137 6 : current_exact_logical_size: None,
138 6 : };
139 6 :
140 6 : let mut cache = HashMap::from([
141 6 : MetricsKey::written_size(tenant_id, timeline_id).at(before_restart, 100),
142 6 : MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(
143 6 : way_before,
144 6 : before_restart,
145 6 : // not taken into account, but the timestamps are important
146 6 : 999_999_999,
147 6 : ),
148 6 : ]);
149 6 :
150 6 : let mut metrics = Vec::new();
151 6 : snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
152 6 :
153 6 : assert_eq!(
154 6 : metrics,
155 6 : &[
156 6 : MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(
157 6 : before_restart,
158 6 : now,
159 6 : 0
160 6 : ),
161 6 : MetricsKey::written_size(tenant_id, timeline_id).at(now, 100),
162 6 : ]
163 6 : );
164 :
165 : // now if we cache these metrics, and re-run while "still in recovery"
166 6 : cache.extend(metrics.drain(..));
167 6 :
168 6 : // "still in recovery", because our snapshot did not change
169 6 : snap.to_metrics(tenant_id, timeline_id, later, &mut metrics, &cache);
170 6 :
171 6 : assert_eq!(
172 6 : metrics,
173 6 : &[
174 6 : MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(now, later, 0),
175 6 : MetricsKey::written_size(tenant_id, timeline_id).at(later, 100),
176 6 : ]
177 6 : );
178 6 : }
179 :
180 : #[test]
181 6 : fn post_restart_current_exact_logical_size_uses_cached() {
182 6 : let tenant_id = TenantId::generate();
183 6 : let timeline_id = TimelineId::generate();
184 6 :
185 6 : let [now, at_restart] = time_backwards();
186 6 :
187 6 : let now = DateTime::<Utc>::from(now);
188 6 : let before_restart = at_restart - std::time::Duration::from_secs(5 * 60);
189 6 : let before_restart = DateTime::<Utc>::from(before_restart);
190 6 :
191 6 : let snap = TimelineSnapshot {
192 6 : loaded_at: (Lsn(50), at_restart),
193 6 : last_record_lsn: Lsn(50),
194 6 : current_exact_logical_size: None,
195 6 : };
196 6 :
197 6 : let cache = HashMap::from([
198 6 : MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(before_restart, 100)
199 6 : ]);
200 6 :
201 6 : let mut metrics = Vec::new();
202 6 : snap.to_metrics(tenant_id, timeline_id, now, &mut metrics, &cache);
203 6 :
204 18 : metrics.retain(|(key, _)| key.metric == Name::LogicalSize);
205 6 :
206 6 : assert_eq!(
207 6 : metrics,
208 6 : &[MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 100)]
209 6 : );
210 6 : }
211 :
212 : #[test]
213 6 : fn post_restart_synthetic_size_uses_cached_if_available() {
214 6 : let tenant_id = TenantId::generate();
215 6 :
216 6 : let ts = TenantSnapshot {
217 6 : resident_size: 1000,
218 6 : remote_size: 1000,
219 6 : // not yet calculated
220 6 : synthetic_size: 0,
221 6 : };
222 6 :
223 6 : let now = SystemTime::now();
224 6 : let before_restart = DateTime::<Utc>::from(now - std::time::Duration::from_secs(5 * 60));
225 6 : let now = DateTime::<Utc>::from(now);
226 6 :
227 6 : let cached = HashMap::from([MetricsKey::synthetic_size(tenant_id).at(before_restart, 1000)]);
228 6 :
229 6 : let mut metrics = Vec::new();
230 6 : ts.to_metrics(tenant_id, now, &cached, &mut metrics);
231 6 :
232 6 : assert_eq!(
233 6 : metrics,
234 6 : &[
235 6 : MetricsKey::remote_storage_size(tenant_id).at(now, 1000),
236 6 : MetricsKey::resident_size(tenant_id).at(now, 1000),
237 6 : MetricsKey::synthetic_size(tenant_id).at(now, 1000),
238 6 : ]
239 6 : );
240 6 : }
241 :
242 : #[test]
243 6 : fn post_restart_synthetic_size_is_not_sent_when_not_cached() {
244 6 : let tenant_id = TenantId::generate();
245 6 :
246 6 : let ts = TenantSnapshot {
247 6 : resident_size: 1000,
248 6 : remote_size: 1000,
249 6 : // not yet calculated
250 6 : synthetic_size: 0,
251 6 : };
252 6 :
253 6 : let now = SystemTime::now();
254 6 : let now = DateTime::<Utc>::from(now);
255 6 :
256 6 : let cached = HashMap::new();
257 6 :
258 6 : let mut metrics = Vec::new();
259 6 : ts.to_metrics(tenant_id, now, &cached, &mut metrics);
260 6 :
261 6 : assert_eq!(
262 6 : metrics,
263 6 : &[
264 6 : MetricsKey::remote_storage_size(tenant_id).at(now, 1000),
265 6 : MetricsKey::resident_size(tenant_id).at(now, 1000),
266 6 : // no synthetic size here
267 6 : ]
268 6 : );
269 6 : }
270 :
271 24 : fn time_backwards<const N: usize>() -> [std::time::SystemTime; N] {
272 24 : let mut times = [std::time::SystemTime::UNIX_EPOCH; N];
273 24 : times[0] = std::time::SystemTime::now();
274 72 : for behind in 1..N {
275 48 : times[behind] = times[0] - std::time::Duration::from_secs(behind as u64);
276 48 : }
277 :
278 24 : times
279 24 : }
280 :
281 12 : pub(crate) const fn metric_examples(
282 12 : tenant_id: TenantId,
283 12 : timeline_id: TimelineId,
284 12 : now: DateTime<Utc>,
285 12 : before: DateTime<Utc>,
286 12 : ) -> [RawMetric; 6] {
287 12 : [
288 12 : MetricsKey::written_size(tenant_id, timeline_id).at(now, 0),
289 12 : MetricsKey::written_size_delta(tenant_id, timeline_id).from_until(before, now, 0),
290 12 : MetricsKey::timeline_logical_size(tenant_id, timeline_id).at(now, 0),
291 12 : MetricsKey::remote_storage_size(tenant_id).at(now, 0),
292 12 : MetricsKey::resident_size(tenant_id).at(now, 0),
293 12 : MetricsKey::synthetic_size(tenant_id).at(now, 1),
294 12 : ]
295 12 : }
|