]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/test-journal-interleaving.c
journal: add void cast to fsync() calls
[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
919ce0b7 39noreturn static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) {
79008bdd
LP
40 log_internal(LOG_CRIT, 0, file, line, func,
41 "'%s' failed at %s:%u (%s): %s.",
42 text, file, line, func, strerror(eno));
7a050b54
MV
43 abort();
44}
45
46#define assert_ret(expr) \
47 do { \
48 int _r_ = (expr); \
49 if (_unlikely_(_r_ < 0)) \
50 log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
51 } while (false)
52
510b857f 53static JournalFile *test_open(const char *name) {
7a050b54 54 JournalFile *f;
5cb24cd3 55 assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
7a050b54
MV
56 return f;
57}
58
510b857f 59static void test_close(JournalFile *f) {
7a050b54
MV
60 journal_file_close (f);
61}
62
510b857f 63static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
7a050b54
MV
64 char *p;
65 dual_timestamp ts;
44cf96e3 66 static dual_timestamp previous_ts = {};
7a050b54
MV
67 struct iovec iovec[1];
68
69 dual_timestamp_get(&ts);
70
44cf96e3
LP
71 if (ts.monotonic <= previous_ts.monotonic)
72 ts.monotonic = previous_ts.monotonic + 1;
73
74 if (ts.realtime <= previous_ts.realtime)
75 ts.realtime = previous_ts.realtime + 1;
76
77 previous_ts = ts;
78
7a050b54
MV
79 assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
80 iovec[0].iov_base = p;
81 iovec[0].iov_len = strlen(p);
5cb24cd3 82 assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
510b857f 83 free(p);
7a050b54
MV
84}
85
510b857f 86static void test_check_number (sd_journal *j, int n) {
7a050b54 87 const void *d;
510b857f 88 _cleanup_free_ char *k;
7a050b54
MV
89 size_t l;
90 int x;
91
92 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
93 assert_se(k = strndup(d, l));
94 printf("%s\n", k);
95
96 assert_se(safe_atoi(k + 7, &x) >= 0);
97 assert_se(n == x);
98}
99
510b857f
LP
100static void test_check_numbers_down (sd_journal *j, int count) {
101 int i;
102
103 for (i = 1; i <= count; i++) {
7a050b54
MV
104 int r;
105 test_check_number(j, i);
106 assert_ret(r = sd_journal_next(j));
107 if (i == count)
108 assert_se(r == 0);
109 else
110 assert_se(r == 1);
111 }
112
113}
114
510b857f 115static void test_check_numbers_up (sd_journal *j, int count) {
7a050b54
MV
116 for (int i = count; i >= 1; i--) {
117 int r;
118 test_check_number(j, i);
119 assert_ret(r = sd_journal_previous(j));
120 if (i == 1)
121 assert_se(r == 0);
122 else
123 assert_se(r == 1);
124 }
125
126}
127
128static void setup_sequential(void) {
129 JournalFile *one, *two;
130 one = test_open("one.journal");
131 two = test_open("two.journal");
5cb24cd3
ZJS
132 append_number(one, 1, NULL);
133 append_number(one, 2, NULL);
134 append_number(two, 3, NULL);
135 append_number(two, 4, NULL);
7a050b54
MV
136 test_close(one);
137 test_close(two);
138}
139
140static void setup_interleaved(void) {
141 JournalFile *one, *two;
142 one = test_open("one.journal");
143 two = test_open("two.journal");
5cb24cd3
ZJS
144 append_number(one, 1, NULL);
145 append_number(two, 2, NULL);
146 append_number(one, 3, NULL);
147 append_number(two, 4, NULL);
7a050b54
MV
148 test_close(one);
149 test_close(two);
150}
151
510b857f 152static void test_skip(void (*setup)(void)) {
7a050b54
MV
153 char t[] = "/tmp/journal-skip-XXXXXX";
154 sd_journal *j;
155 int r;
156
7a050b54
MV
157 assert_se(mkdtemp(t));
158 assert_se(chdir(t) >= 0);
159
160 setup();
161
162 /* Seek to head, iterate down.
163 */
164 assert_ret(sd_journal_open_directory(&j, t, 0));
165 assert_ret(sd_journal_seek_head(j));
166 assert_ret(sd_journal_next(j));
167 test_check_numbers_down(j, 4);
168 sd_journal_close(j);
169
170 /* Seek to tail, iterate up.
171 */
172 assert_ret(sd_journal_open_directory(&j, t, 0));
173 assert_ret(sd_journal_seek_tail(j));
174 assert_ret(sd_journal_previous(j));
175 test_check_numbers_up(j, 4);
176 sd_journal_close(j);
177
178 /* Seek to tail, skip to head, iterate down.
179 */
180 assert_ret(sd_journal_open_directory(&j, t, 0));
181 assert_ret(sd_journal_seek_tail(j));
182 assert_ret(r = sd_journal_previous_skip(j, 4));
183 assert_se(r == 4);
184 test_check_numbers_down(j, 4);
185 sd_journal_close(j);
186
187 /* Seek to head, skip to tail, iterate up.
188 */
189 assert_ret(sd_journal_open_directory(&j, t, 0));
190 assert_ret(sd_journal_seek_head(j));
191 assert_ret(r = sd_journal_next_skip(j, 4));
192 assert_se(r == 4);
193 test_check_numbers_up(j, 4);
194 sd_journal_close(j);
195
5cb24cd3
ZJS
196 log_info("Done...");
197
198 if (arg_keep)
199 log_info("Not removing %s", t);
200 else {
8580d1f7 201 journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
5cb24cd3 202
c6878637 203 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
5cb24cd3
ZJS
204 }
205
206 puts("------------------------------------------------------------");
207}
208
209static void test_sequence_numbers(void) {
210
211 char t[] = "/tmp/journal-seq-XXXXXX";
212 JournalFile *one, *two;
213 uint64_t seqnum = 0;
214 sd_id128_t seqnum_id;
215
216 assert_se(mkdtemp(t));
217 assert_se(chdir(t) >= 0);
218
219 assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
220 true, false, NULL, NULL, NULL, &one) == 0);
221
222 append_number(one, 1, &seqnum);
223 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 224 assert_se(seqnum == 1);
5cb24cd3
ZJS
225 append_number(one, 2, &seqnum);
226 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 227 assert_se(seqnum == 2);
5cb24cd3 228
0c0cdb06
RC
229 assert_se(one->header->state == STATE_ONLINE);
230 assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
231 assert_se(!sd_id128_equal(one->header->file_id, one->header->boot_id));
232 assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
5cb24cd3
ZJS
233
234 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
235
236 assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
237 true, false, NULL, NULL, one, &two) == 0);
238
0c0cdb06
RC
239 assert_se(two->header->state == STATE_ONLINE);
240 assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
241 assert_se(sd_id128_equal(one->header->machine_id, one->header->machine_id));
242 assert_se(sd_id128_equal(one->header->boot_id, one->header->boot_id));
243 assert_se(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
5cb24cd3
ZJS
244
245 append_number(two, 3, &seqnum);
246 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 247 assert_se(seqnum == 3);
5cb24cd3
ZJS
248 append_number(two, 4, &seqnum);
249 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 250 assert_se(seqnum == 4);
5cb24cd3
ZJS
251
252 test_close(two);
253
254 append_number(one, 5, &seqnum);
255 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 256 assert_se(seqnum == 5);
5cb24cd3
ZJS
257
258 append_number(one, 6, &seqnum);
259 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 260 assert_se(seqnum == 6);
5cb24cd3
ZJS
261
262 test_close(one);
263
264 /* restart server */
265 seqnum = 0;
266
267 assert_se(journal_file_open("two.journal", O_RDWR, 0,
268 true, false, NULL, NULL, NULL, &two) == 0);
269
0c0cdb06 270 assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
5cb24cd3
ZJS
271
272 append_number(two, 7, &seqnum);
273 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 274 assert_se(seqnum == 5);
5cb24cd3
ZJS
275
276 /* So..., here we have the same seqnum in two files with the
277 * same seqnum_id. */
278
279 test_close(two);
280
281 log_info("Done...");
282
283 if (arg_keep)
284 log_info("Not removing %s", t);
285 else {
8580d1f7 286 journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
5cb24cd3 287
c6878637 288 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
5cb24cd3 289 }
7a050b54
MV
290}
291
292int main(int argc, char *argv[]) {
5cb24cd3
ZJS
293 log_set_max_level(LOG_DEBUG);
294
143bfdaf
HHPF
295 /* journal_file_open requires a valid machine id */
296 if (access("/etc/machine-id", F_OK) != 0)
297 return EXIT_TEST_SKIP;
298
5cb24cd3
ZJS
299 arg_keep = argc > 1;
300
7a050b54
MV
301 test_skip(setup_sequential);
302 test_skip(setup_interleaved);
303
5cb24cd3
ZJS
304 test_sequence_numbers();
305
7a050b54
MV
306 return 0;
307}