]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/test-journal-interleaving.c
tree-wide: sort includes
[thirdparty/systemd.git] / src / journal / test-journal-interleaving.c
CommitLineData
7a050b54
MV
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Marius Vollmer
5cb24cd3 7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
7a050b54
MV
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
7a050b54 23#include <fcntl.h>
cf0fbc49 24#include <unistd.h>
7a050b54 25
c6878637 26#include "sd-journal.h"
6bedfcbb 27
b5efdb8a 28#include "alloc-util.h"
7a050b54 29#include "journal-file.h"
5cb24cd3 30#include "journal-vacuum.h"
7a050b54 31#include "log.h"
6bedfcbb 32#include "parse-util.h"
c6878637 33#include "rm-rf.h"
6bedfcbb 34#include "util.h"
7a050b54
MV
35
36/* This program tests skipping around in a multi-file journal.
37 */
38
5cb24cd3
ZJS
39static bool arg_keep = false;
40
919ce0b7 41noreturn static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) {
79008bdd
LP
42 log_internal(LOG_CRIT, 0, file, line, func,
43 "'%s' failed at %s:%u (%s): %s.",
44 text, file, line, func, strerror(eno));
7a050b54
MV
45 abort();
46}
47
48#define assert_ret(expr) \
49 do { \
50 int _r_ = (expr); \
51 if (_unlikely_(_r_ < 0)) \
52 log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
53 } while (false)
54
510b857f 55static JournalFile *test_open(const char *name) {
7a050b54 56 JournalFile *f;
5cb24cd3 57 assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
7a050b54
MV
58 return f;
59}
60
510b857f 61static void test_close(JournalFile *f) {
7a050b54
MV
62 journal_file_close (f);
63}
64
510b857f 65static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
7a050b54
MV
66 char *p;
67 dual_timestamp ts;
44cf96e3 68 static dual_timestamp previous_ts = {};
7a050b54
MV
69 struct iovec iovec[1];
70
71 dual_timestamp_get(&ts);
72
44cf96e3
LP
73 if (ts.monotonic <= previous_ts.monotonic)
74 ts.monotonic = previous_ts.monotonic + 1;
75
76 if (ts.realtime <= previous_ts.realtime)
77 ts.realtime = previous_ts.realtime + 1;
78
79 previous_ts = ts;
80
7a050b54
MV
81 assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
82 iovec[0].iov_base = p;
83 iovec[0].iov_len = strlen(p);
5cb24cd3 84 assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
510b857f 85 free(p);
7a050b54
MV
86}
87
510b857f 88static void test_check_number (sd_journal *j, int n) {
7a050b54 89 const void *d;
510b857f 90 _cleanup_free_ char *k;
7a050b54
MV
91 size_t l;
92 int x;
93
94 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
95 assert_se(k = strndup(d, l));
96 printf("%s\n", k);
97
98 assert_se(safe_atoi(k + 7, &x) >= 0);
99 assert_se(n == x);
100}
101
510b857f
LP
102static void test_check_numbers_down (sd_journal *j, int count) {
103 int i;
104
105 for (i = 1; i <= count; i++) {
7a050b54
MV
106 int r;
107 test_check_number(j, i);
108 assert_ret(r = sd_journal_next(j));
109 if (i == count)
110 assert_se(r == 0);
111 else
112 assert_se(r == 1);
113 }
114
115}
116
510b857f 117static void test_check_numbers_up (sd_journal *j, int count) {
7a050b54
MV
118 for (int i = count; i >= 1; i--) {
119 int r;
120 test_check_number(j, i);
121 assert_ret(r = sd_journal_previous(j));
122 if (i == 1)
123 assert_se(r == 0);
124 else
125 assert_se(r == 1);
126 }
127
128}
129
130static void setup_sequential(void) {
131 JournalFile *one, *two;
132 one = test_open("one.journal");
133 two = test_open("two.journal");
5cb24cd3
ZJS
134 append_number(one, 1, NULL);
135 append_number(one, 2, NULL);
136 append_number(two, 3, NULL);
137 append_number(two, 4, NULL);
7a050b54
MV
138 test_close(one);
139 test_close(two);
140}
141
142static void setup_interleaved(void) {
143 JournalFile *one, *two;
144 one = test_open("one.journal");
145 two = test_open("two.journal");
5cb24cd3
ZJS
146 append_number(one, 1, NULL);
147 append_number(two, 2, NULL);
148 append_number(one, 3, NULL);
149 append_number(two, 4, NULL);
7a050b54
MV
150 test_close(one);
151 test_close(two);
152}
153
510b857f 154static void test_skip(void (*setup)(void)) {
7a050b54
MV
155 char t[] = "/tmp/journal-skip-XXXXXX";
156 sd_journal *j;
157 int r;
158
7a050b54
MV
159 assert_se(mkdtemp(t));
160 assert_se(chdir(t) >= 0);
161
162 setup();
163
164 /* Seek to head, iterate down.
165 */
166 assert_ret(sd_journal_open_directory(&j, t, 0));
167 assert_ret(sd_journal_seek_head(j));
168 assert_ret(sd_journal_next(j));
169 test_check_numbers_down(j, 4);
170 sd_journal_close(j);
171
172 /* Seek to tail, iterate up.
173 */
174 assert_ret(sd_journal_open_directory(&j, t, 0));
175 assert_ret(sd_journal_seek_tail(j));
176 assert_ret(sd_journal_previous(j));
177 test_check_numbers_up(j, 4);
178 sd_journal_close(j);
179
180 /* Seek to tail, skip to head, iterate down.
181 */
182 assert_ret(sd_journal_open_directory(&j, t, 0));
183 assert_ret(sd_journal_seek_tail(j));
184 assert_ret(r = sd_journal_previous_skip(j, 4));
185 assert_se(r == 4);
186 test_check_numbers_down(j, 4);
187 sd_journal_close(j);
188
189 /* Seek to head, skip to tail, iterate up.
190 */
191 assert_ret(sd_journal_open_directory(&j, t, 0));
192 assert_ret(sd_journal_seek_head(j));
193 assert_ret(r = sd_journal_next_skip(j, 4));
194 assert_se(r == 4);
195 test_check_numbers_up(j, 4);
196 sd_journal_close(j);
197
5cb24cd3
ZJS
198 log_info("Done...");
199
200 if (arg_keep)
201 log_info("Not removing %s", t);
202 else {
8580d1f7 203 journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
5cb24cd3 204
c6878637 205 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
5cb24cd3
ZJS
206 }
207
208 puts("------------------------------------------------------------");
209}
210
211static void test_sequence_numbers(void) {
212
213 char t[] = "/tmp/journal-seq-XXXXXX";
214 JournalFile *one, *two;
215 uint64_t seqnum = 0;
216 sd_id128_t seqnum_id;
217
218 assert_se(mkdtemp(t));
219 assert_se(chdir(t) >= 0);
220
221 assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
222 true, false, NULL, NULL, NULL, &one) == 0);
223
224 append_number(one, 1, &seqnum);
225 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 226 assert_se(seqnum == 1);
5cb24cd3
ZJS
227 append_number(one, 2, &seqnum);
228 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 229 assert_se(seqnum == 2);
5cb24cd3 230
0c0cdb06
RC
231 assert_se(one->header->state == STATE_ONLINE);
232 assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
233 assert_se(!sd_id128_equal(one->header->file_id, one->header->boot_id));
234 assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
5cb24cd3
ZJS
235
236 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
237
238 assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
239 true, false, NULL, NULL, one, &two) == 0);
240
0c0cdb06
RC
241 assert_se(two->header->state == STATE_ONLINE);
242 assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
243 assert_se(sd_id128_equal(one->header->machine_id, one->header->machine_id));
244 assert_se(sd_id128_equal(one->header->boot_id, one->header->boot_id));
245 assert_se(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
5cb24cd3
ZJS
246
247 append_number(two, 3, &seqnum);
248 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 249 assert_se(seqnum == 3);
5cb24cd3
ZJS
250 append_number(two, 4, &seqnum);
251 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 252 assert_se(seqnum == 4);
5cb24cd3
ZJS
253
254 test_close(two);
255
256 append_number(one, 5, &seqnum);
257 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 258 assert_se(seqnum == 5);
5cb24cd3
ZJS
259
260 append_number(one, 6, &seqnum);
261 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 262 assert_se(seqnum == 6);
5cb24cd3
ZJS
263
264 test_close(one);
265
266 /* restart server */
267 seqnum = 0;
268
269 assert_se(journal_file_open("two.journal", O_RDWR, 0,
270 true, false, NULL, NULL, NULL, &two) == 0);
271
0c0cdb06 272 assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
5cb24cd3
ZJS
273
274 append_number(two, 7, &seqnum);
275 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 276 assert_se(seqnum == 5);
5cb24cd3
ZJS
277
278 /* So..., here we have the same seqnum in two files with the
279 * same seqnum_id. */
280
281 test_close(two);
282
283 log_info("Done...");
284
285 if (arg_keep)
286 log_info("Not removing %s", t);
287 else {
8580d1f7 288 journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
5cb24cd3 289
c6878637 290 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
5cb24cd3 291 }
7a050b54
MV
292}
293
294int main(int argc, char *argv[]) {
5cb24cd3
ZJS
295 log_set_max_level(LOG_DEBUG);
296
143bfdaf
HHPF
297 /* journal_file_open requires a valid machine id */
298 if (access("/etc/machine-id", F_OK) != 0)
299 return EXIT_TEST_SKIP;
300
5cb24cd3
ZJS
301 arg_keep = argc > 1;
302
7a050b54
MV
303 test_skip(setup_sequential);
304 test_skip(setup_interleaved);
305
5cb24cd3
ZJS
306 test_sequence_numbers();
307
7a050b54
MV
308 return 0;
309}