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 // test that an update, if called on a nonexistent key, will call back
40 // into update_function with the right arguments, and allows it to set a
41 // new value
42
43 #include "test.h"
44
45 const int envflags = DB_INIT_MPOOL|DB_CREATE|DB_THREAD |DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_PRIVATE;
46
47 DB_ENV *env;
48
49 const int to_insert[] = { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 };
50 const int to_update[] = { 0, 1, 1, 1, 0, 0, 1, 0, 1, 0 };
51
should_insert(const unsigned int i)52 static inline bool should_insert(const unsigned int i) { return to_insert[i]; }
should_update(const unsigned int i)53 static inline bool should_update(const unsigned int i) { return to_update[i]; }
_v(const unsigned int i)54 static inline unsigned int _v(const unsigned int i) { return 10 - i; }
_e(const unsigned int i)55 static inline unsigned int _e(const unsigned int i) { return i + 4; }
_u(const unsigned int v,const unsigned int e)56 static inline unsigned int _u(const unsigned int v, const unsigned int e) { return v * v * e; }
57
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)58 static int update_fun(DB *UU(db),
59 const DBT *key,
60 const DBT *old_val, const DBT *extra,
61 void (*set_val)(const DBT *new_val,
62 void *set_extra),
63 void *set_extra) {
64 unsigned int *k, *ov, *e, v;
65 assert(key->size == sizeof(*k));
66 CAST_FROM_VOIDP(k, key->data);
67 assert(extra->size == sizeof(*e));
68 CAST_FROM_VOIDP(e, extra->data);
69 if (!should_insert(*k)) {
70 assert(old_val == NULL);
71 v = _u(_v(*k), *e);
72 } else {
73 assert(old_val->size == sizeof(*ov));
74 CAST_FROM_VOIDP(ov, old_val->data);
75 v = _u(*ov, *e);
76 }
77
78 {
79 DBT newval;
80 set_val(dbt_init(&newval, &v, sizeof(v)), set_extra);
81 }
82
83 return 0;
84 }
85
setup(void)86 static void setup (void) {
87 toku_os_recursive_delete(TOKU_TEST_FILENAME);
88 { int chk_r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
89 { int chk_r = db_env_create(&env, 0); CKERR(chk_r); }
90 env->set_errfile(env, stderr);
91 env->set_update(env, update_fun);
92 { int chk_r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
93 }
94
cleanup(void)95 static void cleanup (void) {
96 { int chk_r = env->close(env, 0); CKERR(chk_r); }
97 }
98
do_inserts(DB_TXN * txn,DB * db)99 static int do_inserts(DB_TXN *txn, DB *db) {
100 int r = 0;
101 DBT key, val;
102 unsigned int i, v;
103 DBT *keyp = dbt_init(&key, &i, sizeof(i));
104 DBT *valp = dbt_init(&val, &v, sizeof(v));
105 for (i = 0; i < (sizeof(to_update) / sizeof(to_update[0])); ++i) {
106 if (should_insert(i)) {
107 v = _v(i);
108 r = db->put(db, txn, keyp, valp, 0); CKERR(r);
109 }
110 }
111 return r;
112 }
113
do_updates(DB_TXN * txn,DB * db)114 static int do_updates(DB_TXN *txn, DB *db) {
115 int r = 0;
116 DBT key, extra;
117 unsigned int i, e;
118 const DBT *keyp = dbt_init(&key, &i, sizeof(i));
119 const DBT *extrap = dbt_init(&extra, &e, sizeof(e));
120 for (i = 0; i < (sizeof(to_update) / sizeof(to_update[0])); ++i) {
121 if (should_update(i)) {
122 e = _e(i); // E I O
123 r = db->update(db, txn, keyp, extrap, 0); CKERR(r);
124 }
125 }
126 return r;
127 }
128
chk_updated(const unsigned int k,const unsigned int v)129 static void chk_updated(const unsigned int k, const unsigned int v) {
130 if (should_update(k)) {
131 assert(v == _u(_v(k), _e(k)));
132 } else {
133 assert(v == _v(k));
134 }
135 }
136
chk_original(const unsigned int k,const unsigned int v)137 static void chk_original(const unsigned int k, const unsigned int v) {
138 assert(v == _v(k));
139 }
140
do_verify_results(DB_TXN * txn,DB * db,void (* check_val)(const unsigned int k,const unsigned int v),bool after_update)141 static int do_verify_results(DB_TXN *txn, DB *db, void (*check_val)(const unsigned int k, const unsigned int v), bool after_update) {
142 int r = 0;
143 DBT key, val;
144 unsigned int i, v;
145 DBT *keyp = dbt_init(&key, &i, sizeof(i));
146 DBT *valp = dbt_init(&val, &v, sizeof(v));
147 for (i = 0; i < (sizeof(to_insert) / sizeof(to_insert[0])); ++i) {
148 r = db->get(db, txn, keyp, valp, 0);
149 if (should_insert(i) || (after_update && should_update(i))) {
150 CKERR(r);
151 assert(val.size == sizeof(v));
152 v = *(unsigned int *) val.data;
153
154 check_val(i, v);
155 } else {
156 CKERR2(r, DB_NOTFOUND);
157 r = 0;
158 }
159 }
160 return r;
161 }
162
test_main(int argc,char * const argv[])163 int test_main (int argc, char * const argv[]) {
164 parse_args(argc, argv);
165 setup();
166
167 DB *db;
168
169 IN_TXN_COMMIT(env, NULL, txn_1, 0, {
170 { int chk_r = db_create(&db, env, 0); CKERR(chk_r); }
171 { int chk_r = db->open(db, txn_1, "foo.db", NULL, DB_BTREE, DB_CREATE, 0666); CKERR(chk_r); }
172
173 { int chk_r = do_inserts(txn_1, db); CKERR(chk_r); }
174
175 IN_TXN_ABORT(env, txn_1, txn_11, 0, {
176 { int chk_r = do_verify_results(txn_11, db, chk_original, false); CKERR(chk_r); }
177 });
178 });
179
180 IN_TXN_COMMIT(env, NULL, txn_2, 0, {
181 { int chk_r = do_updates(txn_2, db); CKERR(chk_r); }
182 });
183
184 IN_TXN_COMMIT(env, NULL, txn_3, 0, {
185 { int chk_r = do_verify_results(txn_3, db, chk_updated, true); CKERR(chk_r); }
186 });
187
188 { int chk_r = db->close(db, 0); CKERR(chk_r); }
189
190 cleanup();
191
192 return 0;
193 }
194