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