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
98 DB_ENV *env;
99 DB *db;
100
checkpoint_callback_1(void * extra)101 static void checkpoint_callback_1(void * extra) {
102 assert(extra == NULL);
103 IN_TXN_COMMIT(env, NULL, txn_2, 0, {
104 { int chk_r = do_updates(txn_2, db); CKERR(chk_r); }
105 });
106 }
107
108
run_test(void)109 static void run_test(void)
110 {
111 toku_os_recursive_delete(TOKU_TEST_FILENAME);
112 { int chk_r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
113 { int chk_r = db_env_create(&env, 0); CKERR(chk_r); }
114 db_env_set_checkpoint_callback2(checkpoint_callback_1, NULL);
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
129 toku_hard_crash_on_purpose();
130 }
131
verify_updated(void)132 static int verify_updated(void)
133 {
134 int r = 0;
135 DBT key, val;
136 unsigned int i, *vp;
137 DBT *keyp = dbt_init(&key, &i, sizeof(i));
138 DBT *valp = dbt_init(&val, NULL, 0);
139
140 IN_TXN_COMMIT(env, NULL, txn_1, 0, {
141 for (i = 0; i < NUM_KEYS; ++i) {
142 r = db->get(db, txn_1, keyp, valp, 0);
143 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 { int chk_r = db_env_create(&env, 0); CKERR(chk_r); }
160 env->set_errfile(env, stderr);
161 env->set_update(env, update_fun);
162 { int chk_r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
163 { int chk_r = db_create(&db, env, 0); CKERR(chk_r); }
164 { int chk_r = db->open(db, NULL, "foo.db", NULL, DB_BTREE, DB_AUTO_COMMIT, 0666); CKERR(chk_r); }
165 { int chk_r = verify_updated(); CKERR(chk_r); }
166 { int chk_r = db->close(db, 0); CKERR(chk_r); }
167 { int chk_r = env->close(env, 0); CKERR(chk_r); }
168 }
169
usage(void)170 static int usage(void)
171 {
172 return 1;
173 }
174
test_main(int argc,char * const argv[])175 int test_main(int argc, char * const argv[])
176 {
177 bool do_test = false;
178 bool do_recover = false;
179
180 for (int i = 1; i < argc; i++) {
181 char * const arg = argv[i];
182 if (strcmp(arg, "-v") == 0) {
183 verbose++;
184 continue;
185 }
186 if (strcmp(arg, "-q") == 0) {
187 verbose--;
188 if (verbose < 0)
189 verbose = 0;
190 continue;
191 }
192 if (strcmp(arg, "--test") == 0) {
193 do_test = true;
194 continue;
195 }
196 if (strcmp(arg, "--recover") == 0) {
197 do_recover = true;
198 continue;
199 }
200 if (strcmp(arg, "--help") == 0) {
201 return usage();
202 }
203 }
204
205 if (do_test) {
206 run_test();
207 }
208 if (do_recover) {
209 run_recover();
210 }
211
212 return 0;
213 }
214