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 #include "test.h"
40
41 // verify that update_multiple where we only change key0
42
43 static int
get_key(int i,int dbnum)44 get_key(int i, int dbnum) {
45 return htonl(i + dbnum);
46 }
47
48 static void
get_data(int * v,int i,int ndbs)49 get_data(int *v, int i, int ndbs) {
50 for (int dbnum = 0; dbnum < ndbs; dbnum++) {
51 v[dbnum] = get_key(i, dbnum);
52 }
53 }
54
55 static int
put_callback(DB * dest_db,DB * src_db,DBT_ARRAY * dest_key_arrays,DBT_ARRAY * dest_val_arrays,const DBT * src_key,const DBT * src_val)56 put_callback(DB *dest_db, DB *src_db, DBT_ARRAY *dest_key_arrays, DBT_ARRAY *dest_val_arrays, const DBT *src_key, const DBT *src_val) {
57 toku_dbt_array_resize(dest_key_arrays, 1);
58 DBT *dest_key = &dest_key_arrays->dbts[0];
59 DBT *dest_val = NULL;
60 if (dest_val_arrays) {
61 toku_dbt_array_resize(dest_val_arrays, 1);
62 dest_val = &dest_val_arrays->dbts[0];
63 }
64
65 (void) dest_db; (void) src_db; (void) dest_key; (void) dest_val; (void) src_key; (void) src_val;
66
67 unsigned int dbnum;
68 assert(dest_db->descriptor->dbt.size == sizeof dbnum);
69 memcpy(&dbnum, dest_db->descriptor->dbt.data, sizeof dbnum);
70 assert(dbnum < src_val->size / sizeof (int));
71
72 int *pri_key = (int *) src_key->data;
73 int *pri_data = (int *) src_val->data;
74
75 switch (dest_key->flags) {
76 case 0:
77 dest_key->size = sizeof (int);
78 dest_key->data = dbnum == 0 ? &pri_key[dbnum] : &pri_data[dbnum];
79 break;
80 case DB_DBT_REALLOC:
81 dest_key->size = sizeof (int);
82 dest_key->data = toku_realloc(dest_key->data, dest_key->size);
83 memcpy(dest_key->data, dbnum == 0 ? &pri_key[dbnum] : &pri_data[dbnum], dest_key->size);
84 break;
85 default:
86 assert(0);
87 }
88
89 if (dest_val) {
90 switch (dest_val->flags) {
91 case 0:
92 if (dbnum == 0) {
93 dest_val->size = src_val->size;
94 dest_val->data = src_val->data;
95 } else
96 dest_val->size = 0;
97 break;
98 case DB_DBT_REALLOC:
99 if (dbnum == 0) {
100 dest_val->size = src_val->size;
101 dest_val->data = toku_realloc(dest_val->data, dest_val->size);
102 memcpy(dest_val->data, src_val->data, dest_val->size);
103 } else
104 dest_val->size = 0;
105 break;
106 default:
107 assert(0);
108 }
109 }
110
111 return 0;
112 }
113
114 static int
del_callback(DB * dest_db,DB * src_db,DBT_ARRAY * dest_key_arrays,const DBT * src_key,const DBT * src_data)115 del_callback(DB *dest_db, DB *src_db, DBT_ARRAY *dest_key_arrays, const DBT *src_key, const DBT *src_data) {
116 return put_callback(dest_db, src_db, dest_key_arrays, NULL, src_key, src_data);
117 }
118
119 static void
verify_locked(DB_ENV * env,DB * db,int k)120 verify_locked(DB_ENV *env, DB *db, int k) {
121 int r;
122 DB_TXN *txn = NULL;
123 r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r);
124 DBT key; dbt_init(&key, &k, sizeof k);
125 r = db->del(db, txn, &key, DB_DELETE_ANY); assert(r == DB_LOCK_NOTGRANTED);
126 r = txn->abort(txn); assert_zero(r);
127 }
128
129 #if 0
130 static void
131 verify_empty(DB_ENV *env, DB *db) {
132 int r;
133 DB_TXN *txn = NULL;
134 r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r);
135
136 DBC *cursor = NULL;
137 r = db->cursor(db, txn, &cursor, 0); assert_zero(r);
138 int i;
139 for (i = 0; ; i++) {
140 DBT key; memset(&key, 0, sizeof key);
141 DBT val; memset(&val, 0, sizeof val);
142 r = cursor->c_get(cursor, &key, &val, DB_NEXT);
143 if (r != 0)
144 break;
145 }
146 assert_zero(i);
147 r = cursor->c_close(cursor); assert_zero(r);
148 r = txn->commit(txn, 0); assert_zero(r);
149 }
150 #endif
151
152 static void
verify_seq(DB_ENV * env,DB * db,int dbnum,int ndbs,int nrows)153 verify_seq(DB_ENV *env, DB *db, int dbnum, int ndbs, int nrows) {
154 int r;
155 DB_TXN *txn = NULL;
156 r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r);
157
158 DBC *cursor = NULL;
159 r = db->cursor(db, txn, &cursor, 0); assert_zero(r);
160 int i;
161 for (i = 0; ; i++) {
162 DBT key; memset(&key, 0, sizeof key);
163 DBT val; memset(&val, 0, sizeof val);
164 r = cursor->c_get(cursor, &key, &val, DB_NEXT);
165 if (r != 0)
166 break;
167 int k;
168 int expectk = dbnum == 0 ? get_key(i + nrows, dbnum) : get_key(i, dbnum);
169 assert(key.size == sizeof k);
170 memcpy(&k, key.data, key.size);
171 assert(k == expectk);
172
173 if (dbnum == 0) {
174 assert(val.size == ndbs * sizeof (int));
175 int v[ndbs]; get_data(v, i, ndbs);
176 assert(memcmp(val.data, v, val.size) == 0);
177 } else
178 assert(val.size == 0);
179 }
180 assert(i == nrows);
181 r = cursor->c_close(cursor); assert_zero(r);
182 r = txn->commit(txn, 0); assert_zero(r);
183 }
184
185 static void
update_key0(DB_ENV * env,DB * db[],int ndbs,int nrows)186 update_key0(DB_ENV *env, DB *db[], int ndbs, int nrows) {
187 assert(ndbs > 0);
188 int r;
189 DB_TXN *txn = NULL;
190 r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r);
191 for (int i = 0; i < nrows; i++) {
192
193 // update where new key0 = old key0 + nrows
194
195 int k = get_key(i, 0);
196 DBT old_key; dbt_init(&old_key, &k, sizeof k);
197 int newk = get_key(i + nrows, 0);
198 DBT new_key; dbt_init(&new_key, &newk, sizeof newk);
199
200 int v[ndbs]; get_data(v, i, ndbs);
201 DBT old_data; dbt_init(&old_data, &v[0], sizeof v);
202 DBT new_data = old_data;
203
204 int ndbts = 2 * ndbs;
205 DBT keys[ndbts]; memset(keys, 0, sizeof keys);
206 DBT vals[ndbts]; memset(vals, 0, sizeof vals);
207 uint32_t flags_array[ndbs]; memset(flags_array, 0, sizeof(flags_array));
208
209 r = env_update_multiple_test_no_array(env, ndbs > 0 ? db[0] : NULL, txn, &old_key, &old_data, &new_key, &new_data, ndbs, db, flags_array, ndbts, keys, ndbts, vals);
210 assert_zero(r);
211
212 verify_locked(env, db[0], k);
213 verify_locked(env, db[0], newk);
214 }
215 r = txn->commit(txn, 0); assert_zero(r);
216 }
217
218 static void
populate_primary(DB_ENV * env,DB * db,int ndbs,int nrows)219 populate_primary(DB_ENV *env, DB *db, int ndbs, int nrows) {
220 int r;
221 DB_TXN *txn = NULL;
222 r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r);
223
224 // populate
225 for (int i = 0; i < nrows; i++) {
226 int k = get_key(i, 0);
227 int v[ndbs]; get_data(v, i, ndbs);
228 DBT key; dbt_init(&key, &k, sizeof k);
229 DBT val; dbt_init(&val, &v[0], sizeof v);
230 r = db->put(db, txn, &key, &val, 0); assert_zero(r);
231 }
232
233 r = txn->commit(txn, 0); assert_zero(r);
234 }
235
236 static void
populate_secondary(DB_ENV * env,DB * db,int dbnum,int nrows)237 populate_secondary(DB_ENV *env, DB *db, int dbnum, int nrows) {
238 int r;
239 DB_TXN *txn = NULL;
240 r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r);
241
242 // populate
243 for (int i = 0; i < nrows; i++) {
244 int k = get_key(i, dbnum);
245 DBT key; dbt_init(&key, &k, sizeof k);
246 DBT val; dbt_init(&val, NULL, 0);
247 r = db->put(db, txn, &key, &val, 0); assert_zero(r);
248 }
249
250 r = txn->commit(txn, 0); assert_zero(r);
251 }
252
253 static void
run_test(int ndbs,int nrows)254 run_test(int ndbs, int nrows) {
255 int r;
256 DB_ENV *env = NULL;
257 r = db_env_create(&env, 0); assert_zero(r);
258
259 r = env->set_generate_row_callback_for_put(env, put_callback); assert_zero(r);
260 r = env->set_generate_row_callback_for_del(env, del_callback); assert_zero(r);
261
262 r = env->open(env, TOKU_TEST_FILENAME, DB_INIT_MPOOL|DB_CREATE|DB_THREAD |DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_PRIVATE, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r);
263
264 DB *db[ndbs];
265 for (int dbnum = 0; dbnum < ndbs; dbnum++) {
266 r = db_create(&db[dbnum], env, 0); assert_zero(r);
267
268 DBT dbt_dbnum; dbt_init(&dbt_dbnum, &dbnum, sizeof dbnum);
269 char dbname[32]; sprintf(dbname, "%d.tdb", dbnum);
270 r = db[dbnum]->open(db[dbnum], NULL, dbname, NULL, DB_BTREE, DB_AUTO_COMMIT+DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r);
271 IN_TXN_COMMIT(env, NULL, txn_desc, 0, {
272 { int chk_r = db[dbnum]->change_descriptor(db[dbnum], txn_desc, &dbt_dbnum, 0); CKERR(chk_r); }
273 });
274 }
275
276 for (int dbnum = 0; dbnum < ndbs; dbnum++) {
277 if (dbnum == 0)
278 populate_primary(env, db[dbnum], ndbs, nrows);
279 else
280 populate_secondary(env, db[dbnum], dbnum, nrows);
281 }
282
283 update_key0(env, db, ndbs, nrows);
284 for (int dbnum = 0; dbnum < ndbs; dbnum++)
285 verify_seq(env, db[dbnum], dbnum, ndbs, nrows);
286
287 for (int dbnum = 0; dbnum < ndbs; dbnum++)
288 r = db[dbnum]->close(db[dbnum], 0); assert_zero(r);
289
290 r = env->close(env, 0); assert_zero(r);
291 }
292
293 int
test_main(int argc,char * const argv[])294 test_main(int argc, char * const argv[]) {
295 int r;
296 int ndbs = 2;
297 int nrows = 2;
298
299 // parse_args(argc, argv);
300 for (int i = 1; i < argc; i++) {
301 char * const arg = argv[i];
302 if (strcmp(arg, "-v") == 0) {
303 verbose++;
304 continue;
305 }
306 if (strcmp(arg, "-q") == 0) {
307 verbose = 0;
308 continue;
309 }
310 if (strcmp(arg, "--ndbs") == 0 && i+1 < argc) {
311 ndbs = atoi(argv[++i]);
312 continue;
313 }
314 if (strcmp(arg, "--nrows") == 0 && i+1 < argc) {
315 nrows = atoi(argv[++i]);
316 continue;
317 }
318 }
319
320 toku_os_recursive_delete(TOKU_TEST_FILENAME);
321 r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r);
322
323 run_test(ndbs, nrows);
324
325 return 0;
326 }
327
328