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, &current_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