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