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