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