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