1
/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* Unit test of the control file module of the Maria engine WL#3234 */
19
Note that it is not possible to test the durability of the write (can't
20
pull the plug programmatically :)
23
#include <my_global.h>
27
#ifndef WITH_MARIA_STORAGE_ENGINE
29
If Maria is not compiled in, normally we don't come to building this test.
31
#error "Maria engine is not compiled in, test cannot be built"
35
#include "../../../storage/maria/maria_def.h"
36
#include <my_getopt.h>
38
#define EXTRACT_DEFINITIONS
39
#include "../ma_control_file.c"
40
#undef EXTRACT_DEFINITIONS
42
char file_name[FN_REFLEN];
44
/* The values we'll set and expect the control file module to return */
45
LSN expect_checkpoint_lsn;
48
uint8 expect_recovery_failures;
50
static int delete_file(myf my_flags);
52
Those are test-specific wrappers around the module's API functions: after
53
calling the module's API functions they perform checks on the result.
55
static int close_file(void); /* wraps ma_control_file_end */
56
/* wraps ma_control_file_open_or_create */
57
static int open_file(void);
58
/* wraps ma_control_file_write_and_force */
59
static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid,
63
static int test_one_log_and_recovery_failures(void);
64
static int test_five_logs_and_max_trid(void);
65
static int test_3_checkpoints_and_2_logs(void);
66
static int test_binary_content(void);
67
static int test_start_stop(void);
68
static int test_2_open_and_2_close(void);
69
static int test_bad_magic_string(void);
70
static int test_bad_checksum(void);
71
static int test_bad_hchecksum(void);
72
static int test_future_size(void);
73
static int test_bad_blocksize(void);
74
static int test_bad_size(void);
77
static int verify_module_values_match_expected(void);
78
static int verify_module_values_are_impossible(void);
79
static void usage(void);
80
static void get_options(int argc, char *argv[]);
83
If "expr" is FALSE, this macro will make the function print a diagnostic
84
message and immediately return 1.
85
This is inspired from assert() but does not crash the binary (sometimes we
86
may want to see how other tests go even if one fails).
87
RET_ERR means "return error".
90
#define RET_ERR_UNLESS(expr) \
91
{if (!(expr)) {diag("line %d: failure: '%s'", __LINE__, #expr); assert(0);return 1;}}
94
/* Used to ignore error messages from ma_control_file_open() */
96
static void my_ignore_message(uint error __attribute__((unused)),
97
const char *str __attribute__((unused)),
98
myf MyFlags __attribute__((unused)))
102
void (*default_error_handler_hook)(uint my_err, const char *str,
106
/* like ma_control_file_open(), but without error messages */
108
static CONTROL_FILE_ERROR local_ma_control_file_open(void)
110
CONTROL_FILE_ERROR error;
111
error_handler_hook= my_ignore_message;
112
error= ma_control_file_open(TRUE, TRUE);
113
error_handler_hook= default_error_handler_hook;
119
int main(int argc,char *argv[])
124
maria_data_root= (char *)".";
125
default_error_handler_hook= error_handler_hook;
129
diag("Unit tests for control file");
131
get_options(argc,argv);
133
diag("Deleting control file at startup, if there is an old one");
134
RET_ERR_UNLESS(0 == delete_file(0)); /* if fails, can't continue */
136
diag("Tests of normal conditions");
137
ok(0 == test_one_log_and_recovery_failures(),
138
"test of creating one log and recording recovery failures");
139
ok(0 == test_five_logs_and_max_trid(),
140
"test of creating five logs and many transactions");
141
ok(0 == test_3_checkpoints_and_2_logs(),
142
"test of creating three checkpoints and two logs");
143
ok(0 == test_binary_content(), "test of the binary content of the file");
144
ok(0 == test_start_stop(), "test of multiple starts and stops");
145
diag("Tests of abnormal conditions");
146
ok(0 == test_2_open_and_2_close(),
147
"test of two open and two close (strange call sequence)");
148
ok(0 == test_bad_magic_string(), "test of bad magic string");
149
ok(0 == test_bad_checksum(), "test of bad checksum");
150
ok(0 == test_bad_hchecksum(), "test of bad hchecksum");
151
ok(0 == test_future_size(), "test of ability to handlr future versions");
152
ok(0 == test_bad_blocksize(), "test of bad blocksize");
153
ok(0 == test_bad_size(), "test of too small/big file");
155
return exit_status();
159
static int delete_file(myf my_flags)
161
RET_ERR_UNLESS(fn_format(file_name, CONTROL_FILE_BASE_NAME,
162
maria_data_root, "", MYF(MY_WME)) != NullS);
164
Maybe file does not exist, ignore error.
165
The error will however be printed on stderr.
167
my_delete(file_name, my_flags);
168
expect_checkpoint_lsn= LSN_IMPOSSIBLE;
169
expect_logno= FILENO_IMPOSSIBLE;
170
expect_max_trid= expect_recovery_failures= 0;
176
Verifies that global values last_checkpoint_lsn, last_logno,
177
max_trid_in_control_file (belonging to the module) match what we expect.
179
static int verify_module_values_match_expected(void)
181
RET_ERR_UNLESS(last_logno == expect_logno);
182
RET_ERR_UNLESS(last_checkpoint_lsn == expect_checkpoint_lsn);
183
RET_ERR_UNLESS(max_trid_in_control_file == expect_max_trid);
184
RET_ERR_UNLESS(recovery_failures == expect_recovery_failures);
190
Verifies that global values last_checkpoint_lsn and last_logno (belonging
191
to the module) are impossible (this is used when the file has been closed).
193
static int verify_module_values_are_impossible(void)
195
RET_ERR_UNLESS(last_logno == FILENO_IMPOSSIBLE);
196
RET_ERR_UNLESS(last_checkpoint_lsn == LSN_IMPOSSIBLE);
197
RET_ERR_UNLESS(max_trid_in_control_file == 0);
202
static int close_file(void)
204
/* Simulate shutdown */
205
ma_control_file_end();
207
RET_ERR_UNLESS(verify_module_values_are_impossible() == 0);
211
static int open_file(void)
213
RET_ERR_UNLESS(local_ma_control_file_open() == CONTROL_FILE_OK);
214
/* Check that the module reports expected information */
215
RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
219
static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid,
222
RET_ERR_UNLESS(ma_control_file_write_and_force(checkpoint_lsn, logno, trid,
225
/* Check that the module reports expected information */
226
RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
230
static int test_one_log_and_recovery_failures(void)
232
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
234
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
235
max_trid_in_control_file,
236
recovery_failures) == 0);
237
expect_recovery_failures= 158;
238
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
239
max_trid_in_control_file,
240
expect_recovery_failures) == 0);
241
RET_ERR_UNLESS(close_file() == 0);
245
static int test_five_logs_and_max_trid(void)
249
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
251
expect_max_trid= ULL(14111978111);
255
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
257
recovery_failures) == 0);
259
RET_ERR_UNLESS(close_file() == 0);
263
static int test_3_checkpoints_and_2_logs(void)
266
Simulate one checkpoint, one log creation, two checkpoints, one
269
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
270
expect_checkpoint_lsn= MAKE_LSN(5, 10000);
271
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
272
max_trid_in_control_file,
273
recovery_failures) == 0);
276
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
277
max_trid_in_control_file,
278
recovery_failures) == 0);
280
expect_checkpoint_lsn= MAKE_LSN(17, 20000);
281
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
282
max_trid_in_control_file,
283
recovery_failures) == 0);
285
expect_checkpoint_lsn= MAKE_LSN(17, 45000);
286
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
287
max_trid_in_control_file,
288
recovery_failures) == 0);
291
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
292
max_trid_in_control_file,
293
recovery_failures) == 0);
294
RET_ERR_UNLESS(close_file() == 0);
298
static int test_binary_content(void)
304
TEST4: actually check by ourselves the content of the file.
305
Note that constants (offsets) are hard-coded here, precisely to prevent
306
someone from changing them in the control file module and breaking
307
backward-compatibility.
308
TODO: when we reach the format-freeze state, we may even just do a
309
comparison with a raw binary string, to not depend on any uint4korr
310
future change/breakage.
314
RET_ERR_UNLESS((fd= my_open(file_name,
317
RET_ERR_UNLESS(my_read(fd, buffer, 45, MYF(MY_FNABP | MY_WME)) == 0);
318
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
319
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
320
i= uint3korr(buffer + 34 );
321
RET_ERR_UNLESS(i == LSN_FILE_NO(last_checkpoint_lsn));
322
i= uint4korr(buffer + 37);
323
RET_ERR_UNLESS(i == LSN_OFFSET(last_checkpoint_lsn));
324
i= uint4korr(buffer + 41);
325
RET_ERR_UNLESS(i == last_logno);
326
RET_ERR_UNLESS(close_file() == 0);
330
static int test_start_stop(void)
332
/* TEST5: Simulate start/nothing/stop/start/nothing/stop/start */
334
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
335
RET_ERR_UNLESS(close_file() == 0);
336
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
337
RET_ERR_UNLESS(close_file() == 0);
338
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
339
RET_ERR_UNLESS(close_file() == 0);
343
static int test_2_open_and_2_close(void)
345
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
346
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
347
RET_ERR_UNLESS(close_file() == 0);
348
RET_ERR_UNLESS(close_file() == 0);
353
static int test_bad_magic_string(void)
358
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
359
RET_ERR_UNLESS(close_file() == 0);
361
/* Corrupt magic string */
362
RET_ERR_UNLESS((fd= my_open(file_name,
365
RET_ERR_UNLESS(my_pread(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0);
366
RET_ERR_UNLESS(my_pwrite(fd, (const uchar *)"papa", 4, 0,
367
MYF(MY_FNABP | MY_WME)) == 0);
369
/* Check that control file module sees the problem */
370
RET_ERR_UNLESS(local_ma_control_file_open() ==
371
CONTROL_FILE_BAD_MAGIC_STRING);
372
/* Restore magic string */
373
RET_ERR_UNLESS(my_pwrite(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0);
374
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
375
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
376
RET_ERR_UNLESS(close_file() == 0);
380
static int test_bad_checksum(void)
385
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
386
RET_ERR_UNLESS(close_file() == 0);
388
/* Corrupt checksum */
389
RET_ERR_UNLESS((fd= my_open(file_name,
392
RET_ERR_UNLESS(my_pread(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
393
buffer[0]+= 3; /* mangle checksum */
394
RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
395
/* Check that control file module sees the problem */
396
RET_ERR_UNLESS(local_ma_control_file_open() ==
397
CONTROL_FILE_BAD_CHECKSUM);
398
/* Restore checksum */
400
RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
401
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
407
static int test_bad_blocksize(void)
409
maria_block_size<<= 1;
410
/* Check that control file module sees the problem */
411
RET_ERR_UNLESS(local_ma_control_file_open() ==
412
CONTROL_FILE_WRONG_BLOCKSIZE);
413
/* Restore blocksize */
414
maria_block_size>>= 1;
416
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
417
RET_ERR_UNLESS(close_file() == 0);
422
static int test_future_size(void)
425
Here we check ability to add fields only so we can use
430
uchar buffer[CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE + 2];
431
RET_ERR_UNLESS((fd= my_open(file_name,
434
RET_ERR_UNLESS(my_read(fd, buffer,
435
CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE,
436
MYF(MY_FNABP | MY_WME)) == 0);
437
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
438
/* "add" new field of 1 byte (value 1) to header and variable part */
439
memmove(buffer + CF_CREATE_TIME_TOTAL_SIZE + 1,
440
buffer + CF_CREATE_TIME_TOTAL_SIZE,
441
CF_CHANGEABLE_TOTAL_SIZE);
442
buffer[CF_CREATE_TIME_TOTAL_SIZE - CF_CHECKSUM_SIZE]= '\1';
443
buffer[CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE + 1]= '\1';
445
int2store(buffer + CF_CREATE_TIME_SIZE_OFFSET, CF_CREATE_TIME_TOTAL_SIZE + 1);
446
int2store(buffer + CF_CHANGEABLE_SIZE_OFFSET, CF_CHANGEABLE_TOTAL_SIZE + 1);
447
/* recalculete checksums */
448
sum= (uint32) my_checksum(0, buffer, CF_CREATE_TIME_TOTAL_SIZE -
449
CF_CHECKSUM_SIZE + 1);
450
int4store(buffer + CF_CREATE_TIME_TOTAL_SIZE - CF_CHECKSUM_SIZE + 1, sum);
451
sum= (uint32) my_checksum(0, buffer + CF_CREATE_TIME_TOTAL_SIZE + 1 +
453
CF_CHANGEABLE_TOTAL_SIZE - CF_CHECKSUM_SIZE + 1);
454
int4store(buffer + CF_CREATE_TIME_TOTAL_SIZE + 1, sum);
455
/* write new file and check it */
456
RET_ERR_UNLESS((fd= my_open(file_name,
459
RET_ERR_UNLESS(my_pwrite(fd, buffer,
460
CF_CREATE_TIME_TOTAL_SIZE +
461
CF_CHANGEABLE_TOTAL_SIZE + 2,
462
0, MYF(MY_FNABP | MY_WME)) == 0);
463
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
464
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
465
RET_ERR_UNLESS(close_file() == 0);
470
static int test_bad_hchecksum(void)
475
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
476
RET_ERR_UNLESS(close_file() == 0);
478
/* Corrupt checksum */
479
RET_ERR_UNLESS((fd= my_open(file_name,
482
RET_ERR_UNLESS(my_pread(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
483
buffer[0]+= 3; /* mangle checksum */
484
RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
485
/* Check that control file module sees the problem */
486
RET_ERR_UNLESS(local_ma_control_file_open() ==
487
CONTROL_FILE_BAD_HEAD_CHECKSUM);
488
/* Restore checksum */
490
RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
491
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
497
static int test_bad_size(void)
500
"123456789012345678901234567890123456789012345678901234567890123456";
503
/* A too short file */
504
RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0);
505
RET_ERR_UNLESS((fd= my_open(file_name,
506
O_BINARY | O_RDWR | O_CREAT,
508
RET_ERR_UNLESS(my_write(fd, buffer, 10, MYF(MY_FNABP | MY_WME)) == 0);
509
/* Check that control file module sees the problem */
510
RET_ERR_UNLESS(local_ma_control_file_open() ==
511
CONTROL_FILE_TOO_SMALL);
512
for (i= 0; i < 8; i++)
514
RET_ERR_UNLESS(my_write(fd, buffer, 66, MYF(MY_FNABP | MY_WME)) == 0);
516
/* Check that control file module sees the problem */
517
RET_ERR_UNLESS(local_ma_control_file_open() ==
518
CONTROL_FILE_TOO_BIG);
519
RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
521
/* Leave a correct control file */
522
RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0);
523
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
524
RET_ERR_UNLESS(close_file() == 0);
530
static struct my_option my_long_options[] =
533
{"debug", '#', "Debug log.",
534
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
536
{"help", '?', "Display help and exit",
537
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
538
{"version", 'V', "Print version number and exit",
539
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
540
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
544
static void version(void)
546
printf("ma_control_file_test: unit test for the control file "
547
"module of the Maria storage engine. Ver 1.0 \n");
551
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
552
char *argument __attribute__((unused)))
559
DBUG_PUSH (argument);
572
static void get_options(int argc, char *argv[])
576
if ((ho_error=handle_options(&argc, &argv, my_long_options,
584
static void usage(void)
586
printf("Usage: %s [options]\n\n", my_progname);
587
my_print_help(my_long_options);
588
my_print_variables(my_long_options);
591
#include "../ma_check_standalone.h"