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