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