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