]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-journal/test-journal-interleaving.c
tree-wide: use normal spelling of "reopen"
[thirdparty/systemd.git] / src / libsystemd / sd-journal / test-journal-interleaving.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
7a050b54 2
7a050b54 3#include <fcntl.h>
cf0fbc49 4#include <unistd.h>
7a050b54 5
3a9ca230 6#include "sd-id128.h"
c6878637 7#include "sd-journal.h"
6bedfcbb 8
b5efdb8a 9#include "alloc-util.h"
949082ac 10#include "chattr-util.h"
bd1ae178 11#include "iovec-util.h"
1e094703 12#include "journal-file-util.h"
5cb24cd3 13#include "journal-vacuum.h"
7a050b54 14#include "log.h"
7c1784db 15#include "logs-show.h"
6bedfcbb 16#include "parse-util.h"
f3714bd5 17#include "random-util.h"
c6878637 18#include "rm-rf.h"
317bb217 19#include "tests.h"
7a050b54 20
317bb217 21/* This program tests skipping around in a multi-file journal. */
7a050b54 22
5cb24cd3 23static bool arg_keep = false;
bb83c7c6 24static dual_timestamp previous_ts = {};
5cb24cd3 25
c0f86d66 26_noreturn_ static void log_assert_errno(const char *text, int error, const char *file, unsigned line, const char *func) {
9eec7d12
ZJS
27 log_internal(LOG_CRIT, error, file, line, func,
28 "'%s' failed at %s:%u (%s): %m", text, file, line, func);
7a050b54
MV
29 abort();
30}
31
32#define assert_ret(expr) \
33 do { \
34 int _r_ = (expr); \
35 if (_unlikely_(_r_ < 0)) \
5a9b9157 36 log_assert_errno(#expr, -_r_, PROJECT_FILE, __LINE__, __func__); \
7a050b54
MV
37 } while (false)
38
45c0ecba 39static JournalFile *test_open_internal(const char *name, JournalFileFlags flags) {
74fb5be6 40 _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
45c0ecba 41 JournalFile *f;
74fb5be6
VC
42
43 m = mmap_cache_new();
44 assert_se(m != NULL);
45
45c0ecba 46 assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, flags, 0644, UINT64_MAX, NULL, m, NULL, &f));
7a050b54
MV
47 return f;
48}
49
45c0ecba 50static JournalFile *test_open(const char *name) {
bb83c7c6
YW
51 return test_open_internal(name, JOURNAL_COMPRESS);
52}
53
45c0ecba 54static JournalFile *test_open_strict(const char *name) {
bb83c7c6
YW
55 return test_open_internal(name, JOURNAL_COMPRESS | JOURNAL_STRICT_ORDER);
56}
57
45c0ecba
YW
58static void test_close(JournalFile *f) {
59 (void) journal_file_offline_close(f);
7a050b54
MV
60}
61
76b7a346
YW
62static void test_done(const char *t) {
63 log_info("Done...");
64
65 if (arg_keep)
66 log_info("Not removing %s", t);
67 else {
68 journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
69
70 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
71 }
72
73 log_info("------------------------------------------------------------");
74}
75
1f21bc58 76static void append_number(JournalFile *f, int n, const sd_id128_t *boot_id, uint64_t *seqnum, uint64_t *ret_offset) {
7c1784db 77 _cleanup_free_ char *p = NULL, *q = NULL;
7a050b54 78 dual_timestamp ts;
7c1784db
YW
79 struct iovec iovec[2];
80 size_t n_iov = 0;
7a050b54 81
fa5a0251 82 dual_timestamp_now(&ts);
7a050b54 83
44cf96e3
LP
84 if (ts.monotonic <= previous_ts.monotonic)
85 ts.monotonic = previous_ts.monotonic + 1;
86
87 if (ts.realtime <= previous_ts.realtime)
88 ts.realtime = previous_ts.realtime + 1;
89
90 previous_ts = ts;
91
7a050b54 92 assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
7c1784db
YW
93 iovec[n_iov++] = IOVEC_MAKE_STRING(p);
94
95 if (boot_id) {
96 assert_se(q = strjoin("_BOOT_ID=", SD_ID128_TO_STRING(*boot_id)));
97 iovec[n_iov++] = IOVEC_MAKE_STRING(q);
98 }
99
1f21bc58 100 assert_ret(journal_file_append_entry(f, &ts, boot_id, iovec, n_iov, seqnum, NULL, NULL, ret_offset));
7a050b54
MV
101}
102
45c0ecba 103static void append_unreferenced_data(JournalFile *f, const sd_id128_t *boot_id) {
bb83c7c6
YW
104 _cleanup_free_ char *q = NULL;
105 dual_timestamp ts;
106 struct iovec iovec;
107
108 assert(boot_id);
109
110 ts.monotonic = usec_sub_unsigned(previous_ts.monotonic, 10);
111 ts.realtime = usec_sub_unsigned(previous_ts.realtime, 10);
112
113 assert_se(q = strjoin("_BOOT_ID=", SD_ID128_TO_STRING(*boot_id)));
114 iovec = IOVEC_MAKE_STRING(q);
115
45c0ecba 116 assert_se(journal_file_append_entry(f, &ts, boot_id, &iovec, 1, NULL, NULL, NULL, NULL) == -EREMCHG);
bb83c7c6
YW
117}
118
68da8adf 119static void test_check_number(sd_journal *j, int n) {
7c1784db 120 sd_id128_t boot_id;
7a050b54 121 const void *d;
3d41b6b8 122 _cleanup_free_ char *k = NULL;
7a050b54
MV
123 size_t l;
124 int x;
125
7c1784db 126 assert_se(sd_journal_get_monotonic_usec(j, NULL, &boot_id) >= 0);
7a050b54
MV
127 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
128 assert_se(k = strndup(d, l));
7c1784db 129 printf("%s %s (expected=%i)\n", SD_ID128_TO_STRING(boot_id), k, n);
7a050b54 130
43e460a5 131 assert_se(safe_atoi(k + STRLEN("NUMBER="), &x) >= 0);
7a050b54
MV
132 assert_se(n == x);
133}
134
68da8adf 135static void test_check_numbers_down(sd_journal *j, int count) {
510b857f
LP
136 int i;
137
138 for (i = 1; i <= count; i++) {
7a050b54
MV
139 int r;
140 test_check_number(j, i);
141 assert_ret(r = sd_journal_next(j));
142 if (i == count)
143 assert_se(r == 0);
144 else
145 assert_se(r == 1);
146 }
147
148}
149
68da8adf 150static void test_check_numbers_up(sd_journal *j, int count) {
7a050b54
MV
151 for (int i = count; i >= 1; i--) {
152 int r;
153 test_check_number(j, i);
154 assert_ret(r = sd_journal_previous(j));
155 if (i == 1)
156 assert_se(r == 0);
157 else
158 assert_se(r == 1);
159 }
160
161}
162
163static void setup_sequential(void) {
45c0ecba 164 JournalFile *f1, *f2, *f3;
7c1784db 165 sd_id128_t id;
43e460a5
YW
166
167 f1 = test_open("one.journal");
168 f2 = test_open("two.journal");
169 f3 = test_open("three.journal");
7c1784db
YW
170 assert_se(sd_id128_randomize(&id) >= 0);
171 log_info("boot_id: %s", SD_ID128_TO_STRING(id));
1f21bc58
YW
172 append_number(f1, 1, &id, NULL, NULL);
173 append_number(f1, 2, &id, NULL, NULL);
174 append_number(f1, 3, &id, NULL, NULL);
175 append_number(f2, 4, &id, NULL, NULL);
7c1784db
YW
176 assert_se(sd_id128_randomize(&id) >= 0);
177 log_info("boot_id: %s", SD_ID128_TO_STRING(id));
1f21bc58
YW
178 append_number(f2, 5, &id, NULL, NULL);
179 append_number(f2, 6, &id, NULL, NULL);
180 append_number(f3, 7, &id, NULL, NULL);
181 append_number(f3, 8, &id, NULL, NULL);
7c1784db
YW
182 assert_se(sd_id128_randomize(&id) >= 0);
183 log_info("boot_id: %s", SD_ID128_TO_STRING(id));
1f21bc58 184 append_number(f3, 9, &id, NULL, NULL);
43e460a5
YW
185 test_close(f1);
186 test_close(f2);
187 test_close(f3);
7a050b54
MV
188}
189
190static void setup_interleaved(void) {
45c0ecba 191 JournalFile *f1, *f2, *f3;
7c1784db 192 sd_id128_t id;
43e460a5
YW
193
194 f1 = test_open("one.journal");
195 f2 = test_open("two.journal");
196 f3 = test_open("three.journal");
7c1784db
YW
197 assert_se(sd_id128_randomize(&id) >= 0);
198 log_info("boot_id: %s", SD_ID128_TO_STRING(id));
1f21bc58
YW
199 append_number(f1, 1, &id, NULL, NULL);
200 append_number(f2, 2, &id, NULL, NULL);
201 append_number(f3, 3, &id, NULL, NULL);
202 append_number(f1, 4, &id, NULL, NULL);
203 append_number(f2, 5, &id, NULL, NULL);
204 append_number(f3, 6, &id, NULL, NULL);
205 append_number(f1, 7, &id, NULL, NULL);
206 append_number(f2, 8, &id, NULL, NULL);
207 append_number(f3, 9, &id, NULL, NULL);
43e460a5
YW
208 test_close(f1);
209 test_close(f2);
210 test_close(f3);
7a050b54
MV
211}
212
bb83c7c6 213static void setup_unreferenced_data(void) {
45c0ecba 214 JournalFile *f1, *f2, *f3;
bb83c7c6
YW
215 sd_id128_t id;
216
217 /* For issue #29275. */
218
219 f1 = test_open_strict("one.journal");
220 f2 = test_open_strict("two.journal");
221 f3 = test_open_strict("three.journal");
222 assert_se(sd_id128_randomize(&id) >= 0);
223 log_info("boot_id: %s", SD_ID128_TO_STRING(id));
1f21bc58
YW
224 append_number(f1, 1, &id, NULL, NULL);
225 append_number(f1, 2, &id, NULL, NULL);
226 append_number(f1, 3, &id, NULL, NULL);
bb83c7c6
YW
227 assert_se(sd_id128_randomize(&id) >= 0);
228 log_info("boot_id: %s", SD_ID128_TO_STRING(id));
229 append_unreferenced_data(f1, &id);
1f21bc58
YW
230 append_number(f2, 4, &id, NULL, NULL);
231 append_number(f2, 5, &id, NULL, NULL);
232 append_number(f2, 6, &id, NULL, NULL);
bb83c7c6
YW
233 assert_se(sd_id128_randomize(&id) >= 0);
234 log_info("boot_id: %s", SD_ID128_TO_STRING(id));
235 append_unreferenced_data(f2, &id);
1f21bc58
YW
236 append_number(f3, 7, &id, NULL, NULL);
237 append_number(f3, 8, &id, NULL, NULL);
238 append_number(f3, 9, &id, NULL, NULL);
bb83c7c6
YW
239 test_close(f1);
240 test_close(f2);
241 test_close(f3);
242}
243
949082ac
LP
244static void mkdtemp_chdir_chattr(char *path) {
245 assert_se(mkdtemp(path));
246 assert_se(chdir(path) >= 0);
247
248 /* Speed up things a bit on btrfs, ensuring that CoW is turned off for all files created in our
249 * directory during the test run */
250 (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
251}
252
68da8adf 253static void test_skip_one(void (*setup)(void)) {
949082ac 254 char t[] = "/var/tmp/journal-skip-XXXXXX";
7a050b54
MV
255 sd_journal *j;
256 int r;
257
949082ac 258 mkdtemp_chdir_chattr(t);
7a050b54
MV
259
260 setup();
261
43e460a5 262 /* Seek to head, iterate down. */
7a050b54
MV
263 assert_ret(sd_journal_open_directory(&j, t, 0));
264 assert_ret(sd_journal_seek_head(j));
836809d1 265 assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
43e460a5 266 test_check_numbers_down(j, 9);
7a050b54
MV
267 sd_journal_close(j);
268
43e460a5
YW
269 /* Seek to head, iterate down. */
270 assert_ret(sd_journal_open_directory(&j, t, 0));
271 assert_ret(sd_journal_seek_head(j));
836809d1
YW
272 assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
273 assert_se(sd_journal_previous(j) == 0); /* no-op */
43e460a5
YW
274 test_check_numbers_down(j, 9);
275 sd_journal_close(j);
276
45689fd2
YW
277 /* Seek to head twice, iterate down. */
278 assert_ret(sd_journal_open_directory(&j, t, 0));
279 assert_ret(sd_journal_seek_head(j));
280 assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
281 assert_ret(sd_journal_seek_head(j));
282 assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
283 test_check_numbers_down(j, 9);
284 sd_journal_close(j);
285
43e460a5
YW
286 /* Seek to head, move to previous, then iterate down. */
287 assert_ret(sd_journal_open_directory(&j, t, 0));
288 assert_ret(sd_journal_seek_head(j));
836809d1
YW
289 assert_se(sd_journal_previous(j) == 0); /* no-op */
290 assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
43e460a5
YW
291 test_check_numbers_down(j, 9);
292 sd_journal_close(j);
293
294 /* Seek to head, walk several steps, then iterate down. */
295 assert_ret(sd_journal_open_directory(&j, t, 0));
296 assert_ret(sd_journal_seek_head(j));
836809d1
YW
297 assert_se(sd_journal_previous(j) == 0); /* no-op */
298 assert_se(sd_journal_previous(j) == 0); /* no-op */
299 assert_se(sd_journal_previous(j) == 0); /* no-op */
300 assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
301 assert_se(sd_journal_previous(j) == 0); /* no-op */
302 assert_se(sd_journal_previous(j) == 0); /* no-op */
43e460a5
YW
303 test_check_numbers_down(j, 9);
304 sd_journal_close(j);
305
306 /* Seek to tail, iterate up. */
7a050b54
MV
307 assert_ret(sd_journal_open_directory(&j, t, 0));
308 assert_ret(sd_journal_seek_tail(j));
836809d1 309 assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
43e460a5
YW
310 test_check_numbers_up(j, 9);
311 sd_journal_close(j);
312
45689fd2
YW
313 /* Seek to tail twice, iterate up. */
314 assert_ret(sd_journal_open_directory(&j, t, 0));
315 assert_ret(sd_journal_seek_tail(j));
316 assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
4aa33df8
YW
317 assert_ret(sd_journal_seek_tail(j));
318 assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
45689fd2
YW
319 test_check_numbers_up(j, 9);
320 sd_journal_close(j);
321
43e460a5
YW
322 /* Seek to tail, move to next, then iterate up. */
323 assert_ret(sd_journal_open_directory(&j, t, 0));
324 assert_ret(sd_journal_seek_tail(j));
836809d1
YW
325 assert_se(sd_journal_next(j) == 0); /* no-op */
326 assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
43e460a5 327 test_check_numbers_up(j, 9);
7a050b54
MV
328 sd_journal_close(j);
329
43e460a5 330 /* Seek to tail, walk several steps, then iterate up. */
7a050b54
MV
331 assert_ret(sd_journal_open_directory(&j, t, 0));
332 assert_ret(sd_journal_seek_tail(j));
836809d1
YW
333 assert_se(sd_journal_next(j) == 0); /* no-op */
334 assert_se(sd_journal_next(j) == 0); /* no-op */
335 assert_se(sd_journal_next(j) == 0); /* no-op */
336 assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry. */
337 assert_se(sd_journal_next(j) == 0); /* no-op */
338 assert_se(sd_journal_next(j) == 0); /* no-op */
43e460a5
YW
339 test_check_numbers_up(j, 9);
340 sd_journal_close(j);
341
342 /* Seek to tail, skip to head, iterate down. */
343 assert_ret(sd_journal_open_directory(&j, t, 0));
344 assert_ret(sd_journal_seek_tail(j));
836809d1 345 assert_se(sd_journal_previous_skip(j, 9) == 9); /* pointing to the first entry. */
43e460a5
YW
346 test_check_numbers_down(j, 9);
347 sd_journal_close(j);
348
9a27ef09 349 /* Seek to tail, skip to head in a more complex way, then iterate down. */
43e460a5
YW
350 assert_ret(sd_journal_open_directory(&j, t, 0));
351 assert_ret(sd_journal_seek_tail(j));
836809d1
YW
352 assert_se(sd_journal_next(j) == 0);
353 assert_se(sd_journal_previous_skip(j, 4) == 4);
354 assert_se(sd_journal_previous_skip(j, 5) == 5);
355 assert_se(sd_journal_previous(j) == 0);
356 assert_se(sd_journal_previous_skip(j, 5) == 0);
357 assert_se(sd_journal_next(j) == 1);
358 assert_se(sd_journal_previous_skip(j, 5) == 1);
359 assert_se(sd_journal_next(j) == 1);
360 assert_se(sd_journal_next(j) == 1);
361 assert_se(sd_journal_previous(j) == 1);
362 assert_se(sd_journal_next(j) == 1);
363 assert_se(sd_journal_next(j) == 1);
364 assert_se(sd_journal_previous_skip(j, 5) == 3);
43e460a5
YW
365 test_check_numbers_down(j, 9);
366 sd_journal_close(j);
367
368 /* Seek to head, skip to tail, iterate up. */
369 assert_ret(sd_journal_open_directory(&j, t, 0));
370 assert_ret(sd_journal_seek_head(j));
836809d1 371 assert_se(sd_journal_next_skip(j, 9) == 9);
43e460a5 372 test_check_numbers_up(j, 9);
7a050b54
MV
373 sd_journal_close(j);
374
43e460a5 375 /* Seek to head, skip to tail in a more complex way, then iterate up. */
7a050b54
MV
376 assert_ret(sd_journal_open_directory(&j, t, 0));
377 assert_ret(sd_journal_seek_head(j));
836809d1
YW
378 assert_se(sd_journal_previous(j) == 0);
379 assert_se(sd_journal_next_skip(j, 4) == 4);
380 assert_se(sd_journal_next_skip(j, 5) == 5);
381 assert_se(sd_journal_next(j) == 0);
382 assert_se(sd_journal_next_skip(j, 5) == 0);
383 assert_se(sd_journal_previous(j) == 1);
384 assert_se(sd_journal_next_skip(j, 5) == 1);
385 assert_se(sd_journal_previous(j) == 1);
386 assert_se(sd_journal_previous(j) == 1);
387 assert_se(sd_journal_next(j) == 1);
388 assert_se(sd_journal_previous(j) == 1);
389 assert_se(sd_journal_previous(j) == 1);
390 assert_se(r = sd_journal_next_skip(j, 5) == 3);
43e460a5 391 test_check_numbers_up(j, 9);
7a050b54
MV
392 sd_journal_close(j);
393
76b7a346 394 test_done(t);
5cb24cd3
ZJS
395}
396
68da8adf
JJ
397TEST(skip) {
398 test_skip_one(setup_sequential);
399 test_skip_one(setup_interleaved);
400}
5cb24cd3 401
7c1784db
YW
402static void test_boot_id_one(void (*setup)(void), size_t n_boots_expected) {
403 char t[] = "/var/tmp/journal-boot-id-XXXXXX";
404 sd_journal *j;
405 _cleanup_free_ BootId *boots = NULL;
406 size_t n_boots;
407
408 mkdtemp_chdir_chattr(t);
409
410 setup();
411
412 assert_ret(sd_journal_open_directory(&j, t, 0));
413 assert_se(journal_get_boots(j, &boots, &n_boots) >= 0);
414 assert_se(boots);
415 assert_se(n_boots == n_boots_expected);
416 sd_journal_close(j);
417
418 FOREACH_ARRAY(b, boots, n_boots) {
419 assert_ret(sd_journal_open_directory(&j, t, 0));
420 assert_se(journal_find_boot_by_id(j, b->id) == 1);
421 sd_journal_close(j);
422 }
423
424 for (int i = - (int) n_boots + 1; i <= (int) n_boots; i++) {
425 sd_id128_t id;
426
427 assert_ret(sd_journal_open_directory(&j, t, 0));
428 assert_se(journal_find_boot_by_offset(j, i, &id) == 1);
429 if (i <= 0)
430 assert_se(sd_id128_equal(id, boots[n_boots + i - 1].id));
431 else
432 assert_se(sd_id128_equal(id, boots[i - 1].id));
433 sd_journal_close(j);
434 }
435
76b7a346 436 test_done(t);
7c1784db
YW
437}
438
439TEST(boot_id) {
440 test_boot_id_one(setup_sequential, 3);
bb83c7c6 441 test_boot_id_one(setup_unreferenced_data, 3);
7c1784db
YW
442}
443
c92f1ebe 444static void test_sequence_numbers_one(void) {
74fb5be6 445 _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
949082ac 446 char t[] = "/var/tmp/journal-seq-XXXXXX";
45c0ecba 447 JournalFile *one, *two;
5cb24cd3
ZJS
448 uint64_t seqnum = 0;
449 sd_id128_t seqnum_id;
450
74fb5be6
VC
451 m = mmap_cache_new();
452 assert_se(m != NULL);
453
949082ac 454 mkdtemp_chdir_chattr(t);
5cb24cd3 455
45c0ecba
YW
456 assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
457 UINT64_MAX, NULL, m, NULL, &one) == 0);
5cb24cd3 458
1f21bc58 459 append_number(one, 1, NULL, &seqnum, NULL);
5cb24cd3 460 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 461 assert_se(seqnum == 1);
1f21bc58 462 append_number(one, 2, NULL, &seqnum, NULL);
5cb24cd3 463 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 464 assert_se(seqnum == 2);
5cb24cd3 465
45c0ecba
YW
466 assert_se(one->header->state == STATE_ONLINE);
467 assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
468 assert_se(!sd_id128_equal(one->header->file_id, one->header->tail_entry_boot_id));
469 assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
5cb24cd3 470
45c0ecba 471 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
5cb24cd3 472
45c0ecba
YW
473 assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
474 UINT64_MAX, NULL, m, one, &two) == 0);
5cb24cd3 475
45c0ecba
YW
476 assert_se(two->header->state == STATE_ONLINE);
477 assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
478 assert_se(sd_id128_equal(two->header->machine_id, one->header->machine_id));
479 assert_se(sd_id128_is_null(two->header->tail_entry_boot_id)); /* Not written yet. */
480 assert_se(sd_id128_equal(two->header->seqnum_id, one->header->seqnum_id));
5cb24cd3 481
1f21bc58 482 append_number(two, 3, NULL, &seqnum, NULL);
5cb24cd3 483 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 484 assert_se(seqnum == 3);
1f21bc58 485 append_number(two, 4, NULL, &seqnum, NULL);
5cb24cd3 486 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 487 assert_se(seqnum == 4);
5cb24cd3 488
1fa2ebbe 489 /* Verify tail_entry_boot_id. */
45c0ecba 490 assert_se(sd_id128_equal(two->header->tail_entry_boot_id, one->header->tail_entry_boot_id));
1fa2ebbe 491
5cb24cd3
ZJS
492 test_close(two);
493
1f21bc58 494 append_number(one, 5, NULL, &seqnum, NULL);
5cb24cd3 495 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 496 assert_se(seqnum == 5);
5cb24cd3 497
1f21bc58 498 append_number(one, 6, NULL, &seqnum, NULL);
5cb24cd3 499 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 500 assert_se(seqnum == 6);
5cb24cd3
ZJS
501
502 test_close(one);
503
3a9ca230 504 /* If the machine-id is not initialized, the header file verification
f7862b2a 505 * (which happens when reopening a journal file) will fail. */
3a9ca230
NR
506 if (sd_id128_get_machine(NULL) >= 0) {
507 /* restart server */
508 seqnum = 0;
5cb24cd3 509
45c0ecba
YW
510 assert_se(journal_file_open(-1, "two.journal", O_RDWR, JOURNAL_COMPRESS, 0,
511 UINT64_MAX, NULL, m, NULL, &two) == 0);
5cb24cd3 512
45c0ecba 513 assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
5cb24cd3 514
1f21bc58 515 append_number(two, 7, NULL, &seqnum, NULL);
3a9ca230
NR
516 printf("seqnum=%"PRIu64"\n", seqnum);
517 assert_se(seqnum == 5);
5cb24cd3 518
3a9ca230
NR
519 /* So..., here we have the same seqnum in two files with the
520 * same seqnum_id. */
5cb24cd3 521
3a9ca230
NR
522 test_close(two);
523 }
5cb24cd3 524
76b7a346 525 test_done(t);
7a050b54
MV
526}
527
c92f1ebe
DDM
528TEST(sequence_numbers) {
529 assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "0", 1) >= 0);
530 test_sequence_numbers_one();
531
532 assert_se(setenv("SYSTEMD_JOURNAL_COMPACT", "1", 1) >= 0);
533 test_sequence_numbers_one();
534}
535
f3714bd5
YW
536static int expected_result(uint64_t needle, const uint64_t *candidates, const uint64_t *offset, size_t n, direction_t direction, uint64_t *ret) {
537 switch (direction) {
538 case DIRECTION_DOWN:
539 for (size_t i = 0; i < n; i++) {
540 if (candidates[i] == 0) {
541 *ret = 0;
542 return 0;
543 }
544 if (needle <= candidates[i]) {
545 *ret = offset[i];
546 return 1;
547 }
548 }
549 *ret = 0;
550 return 0;
551
552 case DIRECTION_UP:
553 for (size_t i = 0; i < n; i++)
554 if (needle < candidates[i] || candidates[i] == 0) {
555 if (i == 0) {
556 *ret = 0;
557 return 0;
558 }
559 *ret = offset[i - 1];
560 return 1;
561 }
562 *ret = offset[n - 1];
563 return 1;
564
565 default:
566 assert_not_reached();
567 }
568}
569
570static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offset, size_t n) {
571 uint64_t p, q;
572 int r, e;
573
574 /* by seqnum (sequential) */
575 for (uint64_t i = 0; i < n + 2; i++) {
576 p = 0;
577 r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_DOWN, NULL, &p);
578 e = expected_result(i, seqnum, offset, n, DIRECTION_DOWN, &q);
579 assert_se(r == e);
580 assert_se(p == q);
581
582 p = 0;
583 r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_UP, NULL, &p);
584 e = expected_result(i, seqnum, offset, n, DIRECTION_UP, &q);
585 assert_se(r == e);
586 assert_se(p == q);
587 }
588
589 /* by seqnum (random) */
590 for (size_t trial = 0; trial < 3 * n; trial++) {
591 uint64_t i = random_u64_range(n + 2);
592
593 p = 0;
594 r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_DOWN, NULL, &p);
595 e = expected_result(i, seqnum, offset, n, DIRECTION_DOWN, &q);
596 assert_se(r == e);
597 assert_se(p == q);
598 }
599 for (size_t trial = 0; trial < 3 * n; trial++) {
600 uint64_t i = random_u64_range(n + 2);
601
602 p = 0;
603 r = journal_file_move_to_entry_by_seqnum(f, i, DIRECTION_UP, NULL, &p);
604 e = expected_result(i, seqnum, offset, n, DIRECTION_UP, &q);
605 assert_se(r == e);
606 assert_se(p == q);
607 }
608
609 /* by offset (sequential) */
610 for (size_t i = 0; i < n; i++) {
611 p = 0;
612 r = journal_file_move_to_entry_by_offset(f, offset[i] - 1, DIRECTION_DOWN, NULL, &p);
613 e = expected_result(offset[i] - 1, offset, offset, n, DIRECTION_DOWN, &q);
614 assert_se(r == e);
615 assert_se(p == q);
616
617 p = 0;
618 r = journal_file_move_to_entry_by_offset(f, offset[i], DIRECTION_DOWN, NULL, &p);
619 e = expected_result(offset[i], offset, offset, n, DIRECTION_DOWN, &q);
620 assert_se(r == e);
621 assert_se(p == q);
622
623 p = 0;
624 r = journal_file_move_to_entry_by_offset(f, offset[i] + 1, DIRECTION_DOWN, NULL, &p);
625 e = expected_result(offset[i] + 1, offset, offset, n, DIRECTION_DOWN, &q);
626 assert_se(r == e);
627 assert_se(p == q);
628
629 p = 0;
630 r = journal_file_move_to_entry_by_offset(f, offset[i] - 1, DIRECTION_UP, NULL, &p);
631 e = expected_result(offset[i] - 1, offset, offset, n, DIRECTION_UP, &q);
632 assert_se(r == e);
633 assert_se(p == q);
634
635 p = 0;
636 r = journal_file_move_to_entry_by_offset(f, offset[i], DIRECTION_UP, NULL, &p);
637 e = expected_result(offset[i], offset, offset, n, DIRECTION_UP, &q);
638 assert_se(r == e);
639 assert_se(p == q);
640
641 p = 0;
642 r = journal_file_move_to_entry_by_offset(f, offset[i] + 1, DIRECTION_UP, NULL, &p);
643 e = expected_result(offset[i] + 1, offset, offset, n, DIRECTION_UP, &q);
644 assert_se(r == e);
645 assert_se(p == q);
646 }
647
648 /* by offset (random) */
649 for (size_t trial = 0; trial < 3 * n; trial++) {
650 uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2);
651
652 p = 0;
653 r = journal_file_move_to_entry_by_offset(f, i, DIRECTION_DOWN, NULL, &p);
654 e = expected_result(i, offset, offset, n, DIRECTION_DOWN, &q);
655 assert_se(r == e);
656 assert_se(p == q);
657 }
658 for (size_t trial = 0; trial < 3 * n; trial++) {
659 uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2);
660
661 p = 0;
662 r = journal_file_move_to_entry_by_offset(f, i, DIRECTION_UP, NULL, &p);
663 e = expected_result(i, offset, offset, n, DIRECTION_UP, &q);
664 assert_se(r == e);
665 assert_se(p == q);
666 }
667}
668
669static void test_generic_array_bisect_one(size_t n, size_t num_corrupted) {
670 _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
671 char t[] = "/var/tmp/journal-seq-XXXXXX";
672 _cleanup_free_ uint64_t *seqnum = NULL, *offset = NULL;
673 JournalFile *f;
674
675 log_info("/* %s(%zu, %zu) */", __func__, n, num_corrupted);
676
677 assert_se(m = mmap_cache_new());
678
679 mkdtemp_chdir_chattr(t);
680
681 assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
682 UINT64_MAX, NULL, m, NULL, &f) == 0);
683
684 assert_se(seqnum = new0(uint64_t, n));
685 assert_se(offset = new0(uint64_t, n));
686
687 for (size_t i = 0; i < n; i++) {
688 append_number(f, i, NULL, seqnum + i, offset + i);
689 if (i == 0) {
690 assert_se(seqnum[i] > 0);
691 assert_se(offset[i] > 0);
692 } else {
693 assert_se(seqnum[i] > seqnum[i-1]);
694 assert_se(offset[i] > offset[i-1]);
695 }
696 }
697
698 verify(f, seqnum, offset, n);
699
700 /* Reset chain cache. */
701 assert_se(journal_file_move_to_entry_by_offset(f, offset[0], DIRECTION_DOWN, NULL, NULL) > 0);
702
703 /* make journal corrupted by clearing seqnum. */
704 for (size_t i = n - num_corrupted; i < n; i++) {
705 Object *o;
706
707 assert_se(journal_file_move_to_object(f, OBJECT_ENTRY, offset[i], &o) >= 0);
708 assert_se(o);
709 o->entry.seqnum = 0;
710 seqnum[i] = 0;
711 }
712
713 verify(f, seqnum, offset, n);
714
715 test_close(f);
716 test_done(t);
717}
718
719TEST(generic_array_bisect) {
720 for (size_t n = 1; n < 10; n++)
721 for (size_t m = 1; m <= n; m++)
722 test_generic_array_bisect_one(n, m);
723
724 test_generic_array_bisect_one(100, 40);
725}
726
68da8adf 727static int intro(void) {
45c0ecba 728 /* journal_file_open() requires a valid machine id */
317bb217
ZJS
729 if (access("/etc/machine-id", F_OK) != 0)
730 return log_tests_skipped("/etc/machine-id not found");
143bfdaf 731
68da8adf 732 arg_keep = saved_argc > 1;
7a050b54 733
68da8adf 734 return EXIT_SUCCESS;
7a050b54 735}
68da8adf
JJ
736
737DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro);