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