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 // force a checkpoint to span multiple tokulog files.  in other words, the begin checkpoint log entry and the
40 // end checkpoint log entry for the same checkpoint are in different log files.
41 
42 #include <sys/stat.h>
43 #include "test.h"
44 
45 const int envflags = DB_INIT_MPOOL|DB_CREATE|DB_THREAD |DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_PRIVATE;
46 
test_checkpoint_callback(void * extra)47 static void test_checkpoint_callback(void *extra) {
48     int r;
49     DB_ENV *env = (DB_ENV *) extra;
50 
51     // create and commit a bunch of transactions.  the last commit fsync's the log.  since the log is
52     // really small, a new log file is created before the end checkpoint is logged.
53     int i;
54     for (i=0; i<100; i++) {
55         DB_TXN *txn = NULL;
56         r = env->txn_begin(env, NULL, &txn, 0);                                        CKERR(r);
57         r = txn->commit(txn, i == 99 ? DB_TXN_SYNC : 0);                               CKERR(r);
58     }
59 }
60 
test_checkpoint_callback2(void * extra)61 static void test_checkpoint_callback2(void *extra) {
62     (void) extra;
63 }
64 
run_test(bool do_commit,bool do_abort)65 static void run_test (bool do_commit, bool do_abort) {
66     int r;
67     toku_os_recursive_delete(TOKU_TEST_FILENAME);
68     toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);
69 
70     DB_ENV *env = NULL;
71     r = db_env_create(&env, 0);                                                         CKERR(r);
72 
73     db_env_set_checkpoint_callback(test_checkpoint_callback, env);
74     db_env_set_checkpoint_callback2(test_checkpoint_callback2, env);
75 
76     r = env->set_lg_max(env, 1024);                                                     CKERR(r);
77     r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO);                      CKERR(r);
78 
79     DB_TXN *txn = NULL;
80     r = env->txn_begin(env, NULL, &txn, 0);                                             CKERR(r);
81 
82     r = env->txn_checkpoint(env, 0, 0, 0);                                              CKERR(r);
83 
84     if (do_commit) {
85 	r = txn->commit(txn, 0);                                                        CKERR(r);
86     } else if (do_abort) {
87         r = txn->abort(txn);                                                            CKERR(r);
88 
89         // force an fsync of the log
90         r = env->txn_begin(env, NULL, &txn, 0);                                         CKERR(r);
91         r = txn->commit(txn, 0);                                                        CKERR(r);
92     }
93     //printf("shutdown\n");
94     toku_hard_crash_on_purpose();
95 }
96 
run_recover(bool did_commit)97 static void run_recover (bool did_commit) {
98     (void) did_commit;
99     int r;
100     DB_ENV *env = NULL;
101     r = db_env_create(&env, 0);                                                             CKERR(r);
102     r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);               CKERR(r);
103     r = env->close(env, 0);                                                                 CKERR(r);
104 }
105 
run_recover_only(void)106 static void run_recover_only (void) {
107     int r;
108     DB_ENV *env = NULL;
109     r = db_env_create(&env, 0);                                                             CKERR(r);
110     r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);               CKERR(r);
111     r = env->close(env, 0);                                                                 CKERR(r);
112 }
113 
run_no_recover(void)114 static void run_no_recover (void) {
115     int r;
116     DB_ENV *env = NULL;
117     r = db_env_create(&env, 0);                                                             CKERR(r);
118     r = env->open(env, TOKU_TEST_FILENAME, envflags & ~DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);
119     assert(r == DB_RUNRECOVERY);
120     r = env->close(env, 0);                                                                 CKERR(r);
121 }
122 
123 const char *cmd;
124 
125 
126 bool do_commit=false, do_abort=false, do_explicit_abort=false, do_recover_committed=false,  do_recover_aborted=false, do_recover_only=false, do_no_recover = false;
127 
test_parse_args(int argc,char * const argv[])128 static void test_parse_args (int argc, char * const argv[]) {
129     int resultcode;
130     cmd = argv[0];
131     argc--; argv++;
132     while (argc>0) {
133 	if (strcmp(argv[0], "-v") == 0) {
134 	    verbose++;
135 	} else if (strcmp(argv[0],"-q")==0) {
136 	    verbose--;
137 	    if (verbose<0) verbose=0;
138 	} else if (strcmp(argv[0], "--commit")==0 || strcmp(argv[0], "--test") == 0) {
139 	    do_commit=true;
140 	} else if (strcmp(argv[0], "--abort")==0) {
141 	    do_abort=true;
142 	} else if (strcmp(argv[0], "--explicit-abort")==0) {
143 	    do_explicit_abort=true;
144 	} else if (strcmp(argv[0], "--recover-committed")==0 || strcmp(argv[0], "--recover") == 0) {
145 	    do_recover_committed=true;
146 	} else if (strcmp(argv[0], "--recover-aborted")==0) {
147 	    do_recover_aborted=true;
148         } else if (strcmp(argv[0], "--recover-only") == 0) {
149             do_recover_only=true;
150         } else if (strcmp(argv[0], "--no-recover") == 0) {
151             do_no_recover=true;
152 	} else if (strcmp(argv[0], "-h")==0) {
153 	    resultcode=0;
154 	do_usage:
155 	    fprintf(stderr, "Usage:\n%s [-v|-q]* [-h] {--commit | --abort | --explicit-abort | --recover-committed | --recover-aborted } \n", cmd);
156 	    exit(resultcode);
157 	} else {
158 	    fprintf(stderr, "Unknown arg: %s\n", argv[0]);
159 	    resultcode=1;
160 	    goto do_usage;
161 	}
162 	argc--;
163 	argv++;
164     }
165     {
166 	int n_specified=0;
167 	if (do_commit)            n_specified++;
168 	if (do_abort)             n_specified++;
169 	if (do_explicit_abort)    n_specified++;
170 	if (do_recover_committed) n_specified++;
171 	if (do_recover_aborted)   n_specified++;
172 	if (do_recover_only)      n_specified++;
173 	if (do_no_recover)        n_specified++;
174 	if (n_specified>1) {
175 	    printf("Specify only one of --commit or --abort or --recover-committed or --recover-aborted\n");
176 	    resultcode=1;
177 	    goto do_usage;
178 	}
179     }
180 }
181 
test_main(int argc,char * const argv[])182 int test_main (int argc, char * const argv[]) {
183     test_parse_args(argc, argv);
184     if (do_commit) {
185 	run_test(true, false);
186     } else if (do_abort) {
187         run_test(false, true);
188     } else if (do_recover_committed) {
189         run_recover(true);
190     } else if (do_recover_aborted) {
191         run_recover(false);
192     } else if (do_recover_only) {
193         run_recover_only();
194     } else if (do_no_recover) {
195         run_no_recover();
196     }
197     return 0;
198 }
199