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 #include "test.h"
40 
41 // verify recovery of an update log entry which changes values at keys
42 
43 static const int envflags = DB_INIT_MPOOL|DB_CREATE|DB_THREAD|DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_PRIVATE;
44 uint32_t four_byte_desc = 101;
45 uint64_t eight_byte_desc = 10101;
46 
assert_desc_four(DB * db)47 static void assert_desc_four (DB* db) {
48     assert(db->descriptor->dbt.size == sizeof(four_byte_desc));
49     assert(*(uint32_t *)(db->descriptor->dbt.data) == four_byte_desc);
50 }
assert_desc_eight(DB * db)51 static void assert_desc_eight (DB* db) {
52     assert(db->descriptor->dbt.size == sizeof(eight_byte_desc));
53     assert(*(uint32_t *)(db->descriptor->dbt.data) == eight_byte_desc);
54 }
55 
56 bool do_crash;
57 
checkpoint_callback_1(void * extra)58 static void checkpoint_callback_1(void * extra) {
59     assert(extra == NULL);
60     if (do_crash) {
61        toku_hard_crash_on_purpose();
62     }
63 }
64 
run_test(void)65 static void run_test(void)
66 {
67     DB_ENV *env;
68     DB *db;
69     DB *db2;
70     DB *db3;
71     DB_TXN* txn;
72     DB_TXN* txn2;
73     DB_TXN* txn3;
74     DBT desc;
75 
76     do_crash = false;
77 
78     memset(&desc, 0, sizeof(desc));
79     desc.size = sizeof(four_byte_desc);
80     desc.data = &four_byte_desc;
81 
82     DBT other_desc;
83     memset(&other_desc, 0, sizeof(other_desc));
84     other_desc.size = sizeof(eight_byte_desc);
85     other_desc.data = &eight_byte_desc;
86 
87     toku_os_recursive_delete(TOKU_TEST_FILENAME);
88     { int chk_r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
89     { int chk_r = db_env_create(&env, 0); CKERR(chk_r); }
90     db_env_set_checkpoint_callback2(checkpoint_callback_1, NULL);
91     env->set_errfile(env, stderr);
92     { int chk_r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
93 
94     IN_TXN_COMMIT(env, NULL, txn_1, 0, {
95             { int chk_r = db_create(&db, env, 0); CKERR(chk_r); }
96             { int chk_r = db->open(db, txn_1, "foo.db", NULL, DB_BTREE, DB_CREATE, 0666); CKERR(chk_r); }
97         });
98     IN_TXN_COMMIT(env, NULL, txn_2, 0, {
99             { int chk_r = db_create(&db2, env, 0); CKERR(chk_r); }
100             { int chk_r = db2->open(db2, txn_2, "foo2.db", NULL, DB_BTREE, DB_CREATE, 0666); CKERR(chk_r); }
101             { int chk_r = db2->change_descriptor(db2, txn_2, &other_desc, 0); CKERR(chk_r); }
102             assert_desc_eight(db2);
103         });
104     IN_TXN_COMMIT(env, NULL, txn_3, 0, {
105             { int chk_r = db_create(&db3, env, 0); CKERR(chk_r); }
106             { int chk_r = db3->open(db3, txn_3, "foo3.db", NULL, DB_BTREE, DB_CREATE, 0666); CKERR(chk_r); }
107             { int chk_r = db3->change_descriptor(db3, txn_3, &other_desc, 0); CKERR(chk_r); }
108             assert_desc_eight(db3);
109         });
110 
111     { int chk_r = env->txn_begin(env, NULL, &txn, 0); CKERR(chk_r); }
112     { int chk_r = db->change_descriptor(db, txn, &desc, 0); CKERR(chk_r); }
113 
114     { int chk_r = env->txn_begin(env, NULL, &txn2, 0); CKERR(chk_r); }
115     { int chk_r = db2->change_descriptor(db2, txn2, &desc, 0); CKERR(chk_r); }
116 
117     { int chk_r = env->txn_begin(env, NULL, &txn3, 0); CKERR(chk_r); }
118     { int chk_r = db3->change_descriptor(db3, txn3, &desc, 0); CKERR(chk_r); }
119 
120     { int chk_r = env->txn_checkpoint(env,0,0,0); CKERR(chk_r); }
121     { int chk_r = txn2->abort(txn2); CKERR(chk_r); }
122     { int chk_r = txn->commit(txn,0); CKERR(chk_r); }
123 
124     do_crash = true;
125     env->txn_checkpoint(env,0,0,0);
126 }
127 
128 
run_recover(void)129 static void run_recover(void)
130 {
131     DB_ENV *env;
132     DB *db;
133     DB *db2;
134     DB *db3;
135 
136     { int chk_r = db_env_create(&env, 0); CKERR(chk_r); }
137     env->set_errfile(env, stderr);
138     { int chk_r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
139 
140     { int chk_r = db_create(&db, env, 0); CKERR(chk_r); }
141     { int chk_r = db->open(db, NULL, "foo.db", NULL, DB_BTREE, DB_AUTO_COMMIT, 0666); CKERR(chk_r); }
142     assert_desc_four(db);
143     { int chk_r = db->close(db, 0); CKERR(chk_r); }
144 
145     { int chk_r = db_create(&db2, env, 0); CKERR(chk_r); }
146     { int chk_r = db2->open(db2, NULL, "foo2.db", NULL, DB_BTREE, DB_AUTO_COMMIT, 0666); CKERR(chk_r); }
147     assert_desc_eight(db2);
148     { int chk_r = db2->close(db2, 0); CKERR(chk_r); }
149 
150     { int chk_r = db_create(&db3, env, 0); CKERR(chk_r); }
151     { int chk_r = db3->open(db3, NULL, "foo3.db", NULL, DB_BTREE, DB_AUTO_COMMIT, 0666); CKERR(chk_r); }
152     assert_desc_eight(db3);
153     { int chk_r = db3->close(db3, 0); CKERR(chk_r); }
154 
155     { int chk_r = env->close(env, 0); CKERR(chk_r); }
156 }
157 
usage(void)158 static int usage(void)
159 {
160     return 1;
161 }
162 
test_main(int argc,char * const argv[])163 int test_main(int argc, char * const argv[])
164 {
165     bool do_test = false;
166     bool do_recover = false;
167 
168     for (int i = 1; i < argc; i++) {
169         char * const arg = argv[i];
170         if (strcmp(arg, "-v") == 0) {
171             verbose++;
172             continue;
173         }
174         if (strcmp(arg, "-q") == 0) {
175             verbose--;
176             if (verbose < 0)
177                 verbose = 0;
178             continue;
179         }
180         if (strcmp(arg, "--test") == 0) {
181             do_test = true;
182             continue;
183         }
184         if (strcmp(arg, "--recover") == 0) {
185             do_recover = true;
186             continue;
187         }
188         if (strcmp(arg, "--help") == 0) {
189             return usage();
190         }
191     }
192 
193     if (do_test) {
194         run_test();
195     }
196     if (do_recover) {
197         run_recover();
198     }
199 
200     return 0;
201 }
202