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