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