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 doesn't infringe on the values read by another txn
40 // started with TXN_SNAPSHOT
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_update[] = { 0, 1, 1, 1, 0, 0, 1, 0, 1, 0 };
49
_v(const unsigned int i)50 static inline unsigned int _v(const unsigned int i) { return 10 - i; }
_e(const unsigned int i)51 static inline unsigned int _e(const unsigned int i) { return i + 4; }
_u(const unsigned int v,const unsigned int e)52 static inline unsigned int _u(const unsigned int v, const unsigned int e) { return v * v * e; }
53
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)54 static int update_fun(DB *UU(db),
55 const DBT *key,
56 const DBT *old_val, const DBT *extra,
57 void (*set_val)(const DBT *new_val,
58 void *set_extra),
59 void *set_extra) {
60 unsigned int *k, *ov, *e, v;
61 assert(key->size == sizeof(*k));
62 CAST_FROM_VOIDP(k, key->data);
63 assert(old_val->size == sizeof(*ov));
64 CAST_FROM_VOIDP(ov, old_val->data);
65 assert(extra->size == sizeof(*e));
66 CAST_FROM_VOIDP(e, extra->data);
67 v = _u(*ov, *e);
68
69 {
70 DBT newval;
71 set_val(dbt_init(&newval, &v, sizeof(v)), set_extra);
72 }
73
74 return 0;
75 }
76
setup(void)77 static void setup (void) {
78 toku_os_recursive_delete(TOKU_TEST_FILENAME);
79 { int chk_r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
80 { int chk_r = db_env_create(&env, 0); CKERR(chk_r); }
81 env->set_errfile(env, stderr);
82 env->set_update(env, update_fun);
83 { int chk_r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(chk_r); }
84 }
85
cleanup(void)86 static void cleanup (void) {
87 { int chk_r = env->close(env, 0); CKERR(chk_r); }
88 }
89
do_inserts(DB_TXN * txn,DB * db)90 static int do_inserts(DB_TXN *txn, DB *db) {
91 int r = 0;
92 DBT key, val;
93 unsigned int i, v;
94 DBT *keyp = dbt_init(&key, &i, sizeof(i));
95 DBT *valp = dbt_init(&val, &v, sizeof(v));
96 for (i = 0; i < (sizeof(to_update) / sizeof(to_update[0])); ++i) {
97 v = _v(i);
98 r = db->put(db, txn, keyp, valp, 0); CKERR(r);
99 }
100 return r;
101 }
102
do_updates(DB_TXN * txn,DB * db)103 static int do_updates(DB_TXN *txn, DB *db) {
104 int r = 0;
105 DBT key, extra;
106 unsigned int i, e;
107 DBT *keyp = dbt_init(&key, &i, sizeof(i));
108 DBT *extrap = dbt_init(&extra, &e, sizeof(e));
109 for (i = 0; i < (sizeof(to_update) / sizeof(to_update[0])); ++i) {
110 if (to_update[i] == 1) {
111 e = _e(i); // E I O
112 r = db->update(db, txn, keyp, extrap, 0); CKERR(r);
113 }
114 }
115 return r;
116 }
117
chk_updated(const unsigned int k,const unsigned int v)118 static void chk_updated(const unsigned int k, const unsigned int v) {
119 if (to_update[k]) {
120 assert(v == _u(_v(k), _e(k)));
121 } else {
122 assert(v == _v(k));
123 }
124 }
125
chk_original(const unsigned int k,const unsigned int v)126 static void chk_original(const unsigned int k, const unsigned int v) {
127 assert(v == _v(k));
128 }
129
do_verify_results(DB_TXN * txn,DB * db,void (* check_val)(const unsigned int k,const unsigned int v))130 static int do_verify_results(DB_TXN *txn, DB *db, void (*check_val)(const unsigned int k, const unsigned int v)) {
131 int r = 0;
132 DBT key, val;
133 unsigned int i, *vp;
134 DBT *keyp = dbt_init(&key, &i, sizeof(i));
135 DBT *valp = dbt_init(&val, NULL, 0);
136 for (i = 0; i < (sizeof(to_update) / sizeof(to_update[0])); ++i) {
137 r = db->get(db, txn, keyp, valp, 0); CKERR(r);
138 assert(val.size == sizeof(*vp));
139 CAST_FROM_VOIDP(vp, val.data);
140 check_val(i, *vp);
141 }
142 return r;
143 }
144
test_main(int argc,char * const argv[])145 int test_main(int argc, char * const argv[]) {
146 parse_args(argc, argv);
147 setup();
148
149 DB *db;
150
151 IN_TXN_COMMIT(env, NULL, txn_1, 0, {
152 { int chk_r = db_create(&db, env, 0); CKERR(chk_r); }
153 { int chk_r = db->open(db, txn_1, "foo.db", NULL, DB_BTREE, DB_CREATE, 0666); CKERR(chk_r); }
154
155 { int chk_r = do_inserts(txn_1, db); CKERR(chk_r); }
156
157 IN_TXN_COMMIT(env, txn_1, txn_11, 0, {
158 { int chk_r = do_verify_results(txn_11, db, chk_original); CKERR(chk_r); }
159 });
160 });
161
162 {
163 DB_TXN *txn_2, *txn_3;
164 { int chk_r = env->txn_begin(env, NULL, &txn_2, DB_TXN_SNAPSHOT); CKERR(chk_r); }
165 { int chk_r = do_verify_results(txn_2, db, chk_original); CKERR(chk_r); }
166 { int chk_r = env->txn_begin(env, NULL, &txn_3, 0); CKERR(chk_r); }
167 { int chk_r = do_updates(txn_3, db); CKERR(chk_r); }
168 { int chk_r = do_verify_results(txn_2, db, chk_original); CKERR(chk_r); }
169 { int chk_r = do_verify_results(txn_3, db, chk_updated); CKERR(chk_r); }
170 { int chk_r = txn_2->abort(txn_2); CKERR(chk_r); }
171 { int chk_r = txn_3->abort(txn_3); CKERR(chk_r); }
172 }
173
174 IN_TXN_COMMIT(env, NULL, txn_4, 0, {
175 { int chk_r = do_verify_results(txn_4, db, chk_original); CKERR(chk_r); }
176 });
177
178 { int chk_r = db->close(db, 0); CKERR(chk_r); }
179
180 cleanup();
181
182 return 0;
183 }
184