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