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