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