1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
39 // Test that recovery works correctly on a recovery log in a log directory.
40 
41 #include "test.h"
42 #include <libgen.h>
43 
44 static void run_recovery(const char *testdir) {
45     int r;
46 
47     int log_version;
48     char shutdown[32+1];
49     r = sscanf(testdir, "upgrade-recovery-logs-%d-%32s", &log_version, shutdown);
myrandom(int i)50     assert(r == 2);
51 
generate_random_input()52     char **logfiles = nullptr;
53     int n_logfiles = 0;
54     r = toku_logger_find_logfiles(testdir, &logfiles, &n_logfiles);
55     CKERR(r);
56     assert(n_logfiles > 0);
57 
58     FILE *f = fopen(logfiles[n_logfiles-1], "r");
59     assert(f);
60     uint32_t real_log_version;
61     r = toku_read_logmagic(f, &real_log_version);
62     CKERR(r);
63     assert((uint32_t)log_version == (uint32_t)real_log_version);
64     r = fclose(f);
test_insert_remove(void)65     CKERR(r);
66 
67     toku_logger_free_logfiles(logfiles, n_logfiles);
68 
69     // test needs recovery
70     r = tokuft_needs_recovery(testdir, false);
71     if (strcmp(shutdown, "clean") == 0) {
72         CKERR(r); // clean does not need recovery
73     } else if (strncmp(shutdown, "dirty", 5) == 0) {
74         CKERR2(r, 1); // dirty needs recovery
75     } else {
76         CKERR(EINVAL);
77     }
78 
79     // test maybe upgrade log
80     LSN lsn_of_clean_shutdown;
81     bool upgrade_in_progress;
82     r = toku_maybe_upgrade_log(testdir, testdir, &lsn_of_clean_shutdown, &upgrade_in_progress);
83     if (strcmp(shutdown, "dirty") == 0 && log_version <= 24) {
84         CKERR2(r, TOKUDB_UPGRADE_FAILURE); // we don't support dirty upgrade from versions <= 24
85         return;
86     } else {
87         CKERR(r);
88     }
89 
90     if (!verbose) {
91         // redirect stderr
92         int devnul = open(DEV_NULL_FILE, O_WRONLY);
93         assert(devnul >= 0);
94         int rr = toku_dup2(devnul, fileno(stderr));
95         assert(rr == fileno(stderr));
test_main(int argc,const char * argv[])96         rr = close(devnul);
97         assert(rr == 0);
98     }
99 
100     // run recovery
101     if (r == 0) {
102         r = tokuft_recover(NULL,
103                            NULL_prepared_txn_callback,
104                            NULL_keep_cachetable_callback,
105                            NULL_logger, testdir, testdir, 0, 0, 0, NULL, 0);
106         CKERR(r);
107     }
108 }
109 
110 int test_main(int argc, const char *argv[]) {
111     int i = 0;
112     for (i = 1; i < argc; i++) {
113         if (strcmp(argv[i], "-v") == 0) {
114             verbose++;
115             continue;
116         }
117         if (strcmp(argv[i], "-q") == 0) {
118             if (verbose > 0)
119                 verbose--;
120             continue;
121         }
122         break;
123     }
124     if (i < argc) {
125         const char *full_test_dir = argv[i];
126         const char *test_dir = basename((char *)full_test_dir);
127         if (strcmp(full_test_dir, test_dir) != 0) {
128             int r;
129             char cmd[32 + strlen(full_test_dir) + strlen(test_dir)];
130             sprintf(cmd, "rm -rf %s", test_dir);
131             r = system(cmd);
132             CKERR(r);
133             sprintf(cmd, "cp -r %s %s", full_test_dir, test_dir);
134             r = system(cmd);
135             CKERR(r);
136         }
137         run_recovery(test_dir);
138     }
139     return 0;
140 }
141