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 #pragma once
40
41 #include <toku_portability.h>
42
43 #include <string.h>
44 #include <stdlib.h>
45 #include <toku_stdint.h>
46 #include <stdio.h>
47 #include <db.h>
48 #include <limits.h>
49 #include <errno.h>
50 #include <toku_htonl.h>
51 #include <portability/toku_path.h>
52 #include <portability/toku_crash.h>
53 #include "toku_assert.h"
54 #include <signal.h>
55 #include <time.h>
56
57 #include "ydb.h"
58 //TDB uses DB_NOTFOUND for c_del and DB_CURRENT errors.
59 #ifdef DB_KEYEMPTY
60 #error
61 #endif
62 #define DB_KEYEMPTY DB_NOTFOUND
63
64 // Certain tests fail when row locks taken for read are not shared.
65 // This switch prevents them from failing so long as read locks are not shared.
66 #define BLOCKING_ROW_LOCKS_READS_NOT_SHARED
67
68 int verbose=0;
69
70 #define UU(x) x __attribute__((__unused__))
71
72 #define CKERR(r) ({ int __r = r; if (__r!=0) fprintf(stderr, "%s:%d error %d %s\n", __FILE__, __LINE__, __r, db_strerror(r)); assert(__r==0); })
73 #define CKERR2(r,r2) do { if (r!=r2) fprintf(stderr, "%s:%d error %d %s, expected %d\n", __FILE__, __LINE__, r, db_strerror(r), r2); assert(r==r2); } while (0)
74 #define CKERR2s(r,r2,r3) do { if (r!=r2 && r!=r3) fprintf(stderr, "%s:%d error %d %s, expected %d or %d\n", __FILE__, __LINE__, r, db_strerror(r), r2,r3); assert(r==r2||r==r3); } while (0)
75
76 /*
77 * Helpers for defining pseudo-hygienic macros using a (gensym)-like
78 * technique.
79 */
80 #define _CONCAT(x, y) x ## y
81 #define CONCAT(x, y) _CONCAT(x, y)
82 #define GS(symbol) CONCAT(CONCAT(__gensym_, __LINE__), CONCAT(_, symbol))
83
84 #define DEBUG_LINE do { \
85 fprintf(stderr, "%s() %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
86 fflush(stderr); \
87 } while (0)
88
89 static __attribute__((__unused__)) void
parse_args(int argc,char * const argv[])90 parse_args (int argc, char * const argv[]) {
91 const char *argv0=argv[0];
92 while (argc>1) {
93 int resultcode=0;
94 if (strcmp(argv[1], "-v")==0) {
95 verbose++;
96 } else if (strcmp(argv[1],"-q")==0) {
97 verbose--;
98 if (verbose<0) verbose=0;
99 } else if (strcmp(argv[1], "-h")==0) {
100 do_usage:
101 fprintf(stderr, "Usage:\n%s [-v|-q] [-h]\n", argv0);
102 exit(resultcode);
103 } else {
104 resultcode=1;
105 goto do_usage;
106 }
107 argc--;
108 argv++;
109 }
110 }
111
112 static __attribute__((__unused__)) void
print_engine_status(DB_ENV * UU (env))113 print_engine_status(DB_ENV * UU(env)) {
114 if (verbose) { // verbose declared statically in this file
115 uint64_t nrows;
116 env->get_engine_status_num_rows(env, &nrows);
117 int bufsiz = nrows * 128; // assume 128 characters per row
118 char buff[bufsiz];
119 env->get_engine_status_text(env, buff, bufsiz);
120 printf("Engine status:\n");
121 printf("%s", buff);
122 }
123 }
124
125 static __attribute__((__unused__)) uint64_t
get_engine_status_val(DB_ENV * UU (env),const char * keyname)126 get_engine_status_val(DB_ENV * UU(env), const char * keyname) {
127 uint64_t rval = 0;
128 uint64_t nrows;
129 uint64_t max_rows;
130 env->get_engine_status_num_rows(env, &max_rows);
131 TOKU_ENGINE_STATUS_ROW_S mystat[max_rows];
132 fs_redzone_state redzone_state;
133 uint64_t panic;
134 uint32_t panic_string_len = 1024;
135 char panic_string[panic_string_len];
136 int r = env->get_engine_status (env, mystat, max_rows, &nrows, &redzone_state, &panic, panic_string, panic_string_len, TOKU_ENGINE_STATUS);
137 CKERR(r);
138 int found = 0;
139 for (uint64_t i = 0; i < nrows && !found; i++) {
140 if (strcmp(keyname, mystat[i].keyname) == 0) {
141 found++;
142 rval = mystat[i].value.num;
143 }
144 }
145 CKERR2(found, 1);
146 return rval;
147 }
148
149 static __attribute__((__unused__)) DBT *
dbt_init(DBT * dbt,const void * data,uint32_t size)150 dbt_init(DBT *dbt, const void *data, uint32_t size) {
151 memset(dbt, 0, sizeof *dbt);
152 dbt->data = (void*)data;
153 dbt->size = size;
154 return dbt;
155 }
156
157 static __attribute__((__unused__)) DBT *
dbt_init_malloc(DBT * dbt)158 dbt_init_malloc (DBT *dbt) {
159 memset(dbt, 0, sizeof *dbt);
160 dbt->flags = DB_DBT_MALLOC;
161 return dbt;
162 }
163
164 static __attribute__((__unused__)) DBT *
dbt_init_realloc(DBT * dbt)165 dbt_init_realloc (DBT *dbt) {
166 memset(dbt, 0, sizeof *dbt);
167 dbt->flags = DB_DBT_REALLOC;
168 return dbt;
169 }
170
171 // Simple LCG random number generator. Not high quality, but good enough.
172 static uint32_t rstate=1;
mysrandom(int s)173 static inline void mysrandom (int s) {
174 rstate=s;
175 }
myrandom(void)176 static inline uint32_t myrandom (void) {
177 rstate = (279470275ull*(uint64_t)rstate)%4294967291ull;
178 return rstate;
179 }
180
181 static __attribute__((__unused__)) int
int64_dbt_cmp(DB * db UU (),const DBT * a,const DBT * b)182 int64_dbt_cmp (DB *db UU(), const DBT *a, const DBT *b) {
183 // assert(db && a && b);
184 assert(a);
185 assert(b);
186 // assert(db);
187
188 assert(a->size == sizeof(int64_t));
189 assert(b->size == sizeof(int64_t));
190
191 int64_t x = *(int64_t *) a->data;
192 int64_t y = *(int64_t *) b->data;
193
194 if (x<y) return -1;
195 if (x>y) return 1;
196 return 0;
197 }
198
199 static __attribute__((__unused__)) int
int_dbt_cmp(DB * db,const DBT * a,const DBT * b)200 int_dbt_cmp (DB *db, const DBT *a, const DBT *b) {
201 assert(db && a && b);
202 assert(a->size == sizeof(int));
203 assert(b->size == sizeof(int));
204
205 int x = *(int *) a->data;
206 int y = *(int *) b->data;
207
208 if (x<y) return -1;
209 if (x>y) return 1;
210 return 0;
211 }
212
213 static __attribute__((__unused__)) int
uint_dbt_cmp(DB * db,const DBT * a,const DBT * b)214 uint_dbt_cmp (DB *db, const DBT *a, const DBT *b) {
215 assert(db && a && b);
216 assert(a->size == sizeof(unsigned int));
217 assert(b->size == sizeof(unsigned int));
218
219 unsigned int x = *(unsigned int *) a->data;
220 unsigned int y = *(unsigned int *) b->data;
221
222 if (x<y) return -1;
223 if (x>y) return 1;
224 return 0;
225 }
226
227 #define SET_TRACE_FILE(x) toku_set_trace_file(x)
228 #define CLOSE_TRACE_FILE(x) toku_close_trace_file()
229
230 #include <memory.h>
231
232 static uint64_t __attribute__((__unused__))
random64(void)233 random64(void) {
234 const unsigned int seed = 0xFEEDFACE;
235 static int seeded = 0;
236 if (!seeded) {
237 seeded = 1;
238 srandom(seed);
239 }
240 //random() generates 31 bits of randomness (low order)
241 uint64_t low = random();
242 uint64_t high = random();
243 uint64_t twobits = random();
244 uint64_t ret = low | (high<<31) | (twobits<<62);
245 return ret;
246 }
247
248 static __attribute__((__unused__))
get_tdiff(void)249 double get_tdiff(void) {
250 static struct timeval prev={0,0};
251 if (prev.tv_sec==0) {
252 gettimeofday(&prev, 0);
253 return 0.0;
254 } else {
255 struct timeval now;
256 gettimeofday(&now, 0);
257 double diff = now.tv_sec - prev.tv_sec + 1e-6*(now.tv_usec - prev.tv_usec);
258 prev = now;
259 return diff;
260 }
261 }
262
263 static __attribute__((__unused__))
format_time(const time_t * timer,char * buf)264 void format_time(const time_t *timer, char *buf) {
265 ctime_r(timer, buf);
266 size_t len = strlen(buf);
267 assert(len < 26);
268 char end;
269
270 assert(len>=1);
271 end = buf[len-1];
272 while (end == '\n' || end == '\r') {
273 buf[len-1] = '\0';
274 len--;
275 assert(len>=1);
276 end = buf[len-1];
277 }
278 }
279
280 static __attribute__((__unused__))
print_time_now(void)281 void print_time_now(void) {
282 char timestr[80];
283 time_t now = time(NULL);
284 format_time(&now, timestr);
285 printf("%s", timestr);
286 }
287
UU()288 static void UU()
289 multiply_locks_for_n_dbs(DB_ENV *env, int num_dbs) {
290 uint64_t current_max_lock_memory;
291 int r = env->get_lk_max_memory(env, ¤t_max_lock_memory);
292 CKERR(r);
293 r = env->set_lk_max_memory(env, current_max_lock_memory * num_dbs);
294 CKERR(r);
295 }
296
297 static inline void
default_parse_args(int argc,char * const argv[])298 default_parse_args (int argc, char * const argv[]) {
299 const char *progname=argv[0];
300 argc--; argv++;
301 while (argc>0) {
302 if (strcmp(argv[0],"-v")==0) {
303 ++verbose;
304 } else if (strcmp(argv[0],"-q")==0) {
305 verbose=0;
306 } else {
307 fprintf(stderr, "Usage:\n %s [-v] [-q]\n", progname);
308 exit(1);
309 }
310 argc--; argv++;
311 }
312 }
313
UU()314 UU()
315 static void copy_dbt(DBT *dest, const DBT *src) {
316 assert(dest->flags & DB_DBT_REALLOC);
317 dest->data = toku_xrealloc(dest->data, src->size);
318 dest->size = src->size;
319 memcpy(dest->data, src->data, src->size);
320 }
321
322 // DBT_ARRAY is a toku-specific type
UU()323 UU()
324 static int
325 env_update_multiple_test_no_array(
326 DB_ENV *env,
327 DB *src_db,
328 DB_TXN *txn,
329 DBT *old_src_key, DBT *old_src_data,
330 DBT *new_src_key, DBT *new_src_data,
331 uint32_t num_dbs, DB **db_array, uint32_t* flags_array,
332 uint32_t num_keys, DBT keys[],
333 uint32_t num_vals, DBT vals[]) {
334 int r;
335 DBT_ARRAY key_arrays[num_keys];
336 DBT_ARRAY val_arrays[num_vals];
337 for (uint32_t i = 0; i < num_keys; i++) {
338 toku_dbt_array_init(&key_arrays[i], 1);
339 key_arrays[i].dbts[0] = keys[i];
340 }
341 for (uint32_t i = 0; i < num_vals; i++) {
342 toku_dbt_array_init(&val_arrays[i], 1);
343 val_arrays[i].dbts[0] = vals[i];
344 }
345 r = env->update_multiple(env, src_db, txn, old_src_key, old_src_data, new_src_key, new_src_data,
346 num_dbs, db_array, flags_array,
347 num_keys, &key_arrays[0],
348 num_vals, &val_arrays[0]);
349 for (uint32_t i = 0; i < num_keys; i++) {
350 invariant(key_arrays[i].size == 1);
351 invariant(key_arrays[i].capacity == 1);
352 keys[i] = key_arrays[i].dbts[0];
353 toku_dbt_array_destroy_shallow(&key_arrays[i]);
354 }
355 for (uint32_t i = 0; i < num_vals; i++) {
356 invariant(val_arrays[i].size == 1);
357 invariant(val_arrays[i].capacity == 1);
358 vals[i] = val_arrays[i].dbts[0];
359 toku_dbt_array_destroy_shallow(&val_arrays[i]);
360 }
361 return r;
362 }
363
UU()364 UU()
365 static int env_put_multiple_test_no_array(
366 DB_ENV *env,
367 DB *src_db,
368 DB_TXN *txn,
369 const DBT *src_key,
370 const DBT *src_val,
371 uint32_t num_dbs,
372 DB **db_array,
373 DBT *keys,
374 DBT *vals,
375 uint32_t *flags_array)
376 {
377 int r;
378 DBT_ARRAY key_arrays[num_dbs];
379 DBT_ARRAY val_arrays[num_dbs];
380 for (uint32_t i = 0; i < num_dbs; i++) {
381 toku_dbt_array_init(&key_arrays[i], 1);
382 toku_dbt_array_init(&val_arrays[i], 1);
383 key_arrays[i].dbts[0] = keys[i];
384 val_arrays[i].dbts[0] = vals[i];
385 }
386 r = env->put_multiple(env, src_db, txn, src_key, src_val, num_dbs, db_array, &key_arrays[0], &val_arrays[0], flags_array);
387 for (uint32_t i = 0; i < num_dbs; i++) {
388 invariant(key_arrays[i].size == 1);
389 invariant(key_arrays[i].capacity == 1);
390 invariant(val_arrays[i].size == 1);
391 invariant(val_arrays[i].capacity == 1);
392 keys[i] = key_arrays[i].dbts[0];
393 vals[i] = val_arrays[i].dbts[0];
394 toku_dbt_array_destroy_shallow(&key_arrays[i]);
395 toku_dbt_array_destroy_shallow(&val_arrays[i]);
396 }
397 return r;
398 }
399
UU()400 UU()
401 static int env_del_multiple_test_no_array(
402 DB_ENV *env,
403 DB *src_db,
404 DB_TXN *txn,
405 const DBT *src_key,
406 const DBT *src_val,
407 uint32_t num_dbs,
408 DB **db_array,
409 DBT *keys,
410 uint32_t *flags_array)
411 {
412 int r;
413 DBT_ARRAY key_arrays[num_dbs];
414 for (uint32_t i = 0; i < num_dbs; i++) {
415 toku_dbt_array_init(&key_arrays[i], 1);
416 key_arrays[i].dbts[0] = keys[i];
417 }
418 r = env->del_multiple(env, src_db, txn, src_key, src_val, num_dbs, db_array, &key_arrays[0], flags_array);
419 for (uint32_t i = 0; i < num_dbs; i++) {
420 invariant(key_arrays[i].size == 1);
421 invariant(key_arrays[i].capacity == 1);
422 keys[i] = key_arrays[i].dbts[0];
423 toku_dbt_array_destroy_shallow(&key_arrays[i]);
424 }
425 return r;
426 }
427
428 /* Some macros for evaluating blocks or functions within the scope of a
429 * transaction. */
430 #define IN_TXN_COMMIT(env, parent, txn, flags, expr) ({ \
431 DB_TXN *txn; \
432 { int chk_r = (env)->txn_begin((env), (parent), &(txn), (flags)); CKERR(chk_r); } \
433 (expr); \
434 { int chk_r = (txn)->commit((txn), 0); CKERR(chk_r); } \
435 })
436
437 #define IN_TXN_ABORT(env, parent, txn, flags, expr) ({ \
438 DB_TXN *txn; \
439 { int chk_r = (env)->txn_begin((env), (parent), &(txn), (flags)); CKERR(chk_r); } \
440 (expr); \
441 { int chk_r = (txn)->abort(txn); CKERR(chk_r); } \
442 })
443
444 int test_main(int argc, char *const argv[]);
main(int argc,char * const argv[])445 int main(int argc, char *const argv[]) {
446 int r;
447 toku_os_initialize_settings(1);
448 r = test_main(argc, argv);
449 return r;
450 }
451
452 #ifndef DB_GID_SIZE
453 #define DB_GID_SIZE DB_XIDDATASIZE
454 #endif
455