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 static const unsigned int NUM_KEYS = 100;
45
should_update(const unsigned int k)46 static inline bool should_update(const unsigned int k) { return k % 3 == 0; }
47
_v(const unsigned int k)48 static inline unsigned int _v(const unsigned int k) { return 10 - k; }
_e(const unsigned int k)49 static inline unsigned int _e(const unsigned int k) { return k + 4; }
_u(const unsigned int v,const unsigned int e)50 static inline unsigned int _u(const unsigned int v, const unsigned int e) { return v * v * e; }
51
update_fun(DB * UU (db),const DBT * key,const DBT * old_val,const DBT * extra,void (* set_val)(const DBT * new_val,void * set_extra),void * set_extra)52 static int update_fun(DB *UU(db),
53 const DBT *key,
54 const DBT *old_val, const DBT *extra,
55 void (*set_val)(const DBT *new_val,
56 void *set_extra),
57 void *set_extra)
58 {
59 unsigned int *k, *ov, *e, v;
60 assert(key->size == sizeof(*k));
61 CAST_FROM_VOIDP(k, key->data);
62 assert(old_val->size == sizeof(*ov));
63 CAST_FROM_VOIDP(ov, old_val->data);
64 assert(extra->size == sizeof(*e));
65 CAST_FROM_VOIDP(e, extra->data);
66 v = _u(*ov, *e);
67
68 {
69 DBT newval;
70 set_val(dbt_init(&newval, &v, sizeof(v)), set_extra);
71 }
72
73 return 0;
74 }
75
do_inserts(DB_TXN * txn,DB * db)76 static int do_inserts(DB_TXN *txn, DB *db)
77 {
78 int r = 0;
79 DBT key, val;
80 unsigned int i, v;
81 DBT *keyp = dbt_init(&key, &i, sizeof(i));
82 DBT *valp = dbt_init(&val, &v, sizeof(v));
83 for (i = 0; i < NUM_KEYS; ++i) {
84 v = _v(i);
85 r = db->put(db, txn, keyp, valp, 0);
86 CKERR(r);
87 }
88 return r;
89 }
90
do_updates(DB_TXN * txn,DB * db)91 static int do_updates(DB_TXN *txn, DB *db) {
92 int r = 0;
93 DBT key, extra;
94 unsigned int i, e;
95 DBT *keyp = dbt_init(&key, &i, sizeof(i));
96 DBT *extrap = dbt_init(&extra, &e, sizeof(e));
97 for (i = 0; i < NUM_KEYS; ++i) {
98 if (should_update(i)) {
99 e = _e(i);
100 r = db->update(db, txn, keyp, extrap, 0);
101 CKERR(r);
102 }
103 }
104 return r;
105 }
106
run_test(void)107 static void run_test(void)
108 {
109 DB_ENV *env;
110 DB *db;
111
112 toku_os_recursive_delete(TOKU_TEST_FILENAME);
113 { int chk_r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
114 { int chk_r = db_env_create(&env, 0); CKERR(chk_r); }
115 env->set_errfile(env, stderr);
116 env->set_update(env, update_fun);
117 { int chk_r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
118
119 IN_TXN_COMMIT(env, NULL, txn_1, 0, {
120 { int chk_r = db_create(&db, env, 0); CKERR(chk_r); }
121 { int chk_r = db->open(db, txn_1, "foo.db", NULL, DB_BTREE, DB_CREATE, 0666); CKERR(chk_r); }
122
123 { int chk_r = do_inserts(txn_1, db); CKERR(chk_r); }
124 });
125
126 { int chk_r = env->txn_checkpoint(env, 0, 0, 0); CKERR(chk_r); }
127
128 IN_TXN_ABORT(env, NULL, txn_2, 0, {
129 { int chk_r = do_updates(txn_2, db); CKERR(chk_r); }
130 });
131
132 toku_hard_crash_on_purpose();
133 }
134
verify_unchanged(DB_ENV * env,DB * db)135 static int verify_unchanged(DB_ENV *env, DB *db)
136 {
137 int r = 0;
138 DBT key, val;
139 unsigned int i, *vp;
140 DBT *keyp = dbt_init(&key, &i, sizeof(i));
141 DBT *valp = dbt_init(&val, NULL, 0);
142
143 IN_TXN_COMMIT(env, NULL, txn_1, 0, {
144 for (i = 0; i < NUM_KEYS; ++i) {
145 r = db->get(db, txn_1, keyp, valp, 0);
146 CKERR(r);
147 assert(val.size == sizeof(*vp));
148 CAST_FROM_VOIDP(vp, val.data);
149 assert(*vp == _v(i));
150 }
151 });
152
153 return r;
154 }
155
run_recover(void)156 static void run_recover(void)
157 {
158 DB_ENV *env;
159 DB *db;
160
161 { int chk_r = db_env_create(&env, 0); CKERR(chk_r); }
162 env->set_errfile(env, stderr);
163 env->set_update(env, update_fun);
164 { int chk_r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
165 { int chk_r = db_create(&db, env, 0); CKERR(chk_r); }
166 { int chk_r = db->open(db, NULL, "foo.db", NULL, DB_BTREE, DB_AUTO_COMMIT, 0666); CKERR(chk_r); }
167 { int chk_r = verify_unchanged(env, db); CKERR(chk_r); }
168 { int chk_r = db->close(db, 0); CKERR(chk_r); }
169 { int chk_r = env->close(env, 0); CKERR(chk_r); }
170 }
171
usage(void)172 static int usage(void)
173 {
174 return 1;
175 }
176
test_main(int argc,char * const argv[])177 int test_main(int argc, char * const argv[])
178 {
179 bool do_test = false;
180 bool do_recover = false;
181
182 for (int i = 1; i < argc; i++) {
183 char * const arg = argv[i];
184 if (strcmp(arg, "-v") == 0) {
185 verbose++;
186 continue;
187 }
188 if (strcmp(arg, "-q") == 0) {
189 verbose--;
190 if (verbose < 0)
191 verbose = 0;
192 continue;
193 }
194 if (strcmp(arg, "--test") == 0) {
195 do_test = true;
196 continue;
197 }
198 if (strcmp(arg, "--recover") == 0) {
199 do_recover = true;
200 continue;
201 }
202 if (strcmp(arg, "--help") == 0) {
203 return usage();
204 }
205 }
206
207 if (do_test) {
208 run_test();
209 }
210 if (do_recover) {
211 run_recover();
212 }
213
214 return 0;
215 }
216