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