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