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