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 #include "toku_pthread.h"
41 #include <db.h>
42 #include <sys/stat.h>
43 #include "ydb-internal.h"
44
45 #include "test_kv_gen.h"
46
47 /****************************************************************************************
48 *
49 * Test sequence is run four times, two in outer loop, two in inner loop
50 * Outer loop is for default or small node and cachetable sizes,
51 * inner loop is for insert and delete.
52 *
53 * open dbs
54 * read and verify first n rows of primary, a few interspersed rows of secondaries (n is very small so only a few nodes of secondaries are upgraded, even with prefetch)
55 * close dbs (dictionaries now partially upgraded)
56 * open dbs
57 * read and verify a few more rows of primary, a few more interspersed rows of secondaries
58 * close dbs (some more nodes now upgraded)
59 * open dbs
60 * if (insert test)
61 * insert at end of primary and interspersed in secondary dictionaries
62 * else (delete test)
63 * delete from beginning of primary and interspersed in secondary dictionaries
64 * close dbs
65 * open dbs
66 * verify all rows (including newly inserted ones)
67 * close dbs
68 *
69 */
70
71 DB_ENV *env;
72 enum {MAX_NAME=128};
73 int NUM_DBS=5;
74 int NUM_ROWS=100000;
75 int CHECK_RESULTS=0;
76 int SRC_VERSION = 4;
77 int littlenode = 0;
78
79 #define OLDDATADIR "../../../../tokudb.data/"
80
81 char *env_dir = TOKU_TEST_FILENAME; // the default env_dir.
82 char *db_v5_dir = "dir.preload-db.c.tdb";
83 char *db_v4_dir = OLDDATADIR "env_preload.4.2.0.cleanshutdown";
84 char *db_v4_dir_node4k = OLDDATADIR "env_preload.4.2.0.node4k.cleanshutdown";
85
86
87 enum {ROWS_PER_TRANSACTION=10000};
88
89 static int idx[MAX_DBS];
90
91 typedef enum {insert, delete} test_type;
92
93 static void
open_dbs(DB ** dbs)94 open_dbs(DB **dbs) {
95 int r;
96 DBT desc;
97 dbt_init(&desc, "foo", sizeof("foo"));
98 char name[MAX_NAME*2];
99
100 for(int i=0;i<NUM_DBS;i++) {
101 idx[i] = i;
102 r = db_create(&dbs[i], env, 0); CKERR(r);
103 dbs[i]->app_private = &idx[i];
104 snprintf(name, sizeof(name), "db_%04x", i);
105 r = dbs[i]->open(dbs[i], NULL, name, NULL, DB_BTREE, DB_CREATE, 0666); CKERR(r);
106 IN_TXN_COMMIT(env, NULL, txn_desc, 0, {
107 { int chk_r = dbs[i]->change_descriptor(dbs[i], txn_desc, &desc, 0); CKERR(chk_r); }
108 });
109 }
110 }
111
112
113 static void
close_dbs(DB ** dbs)114 close_dbs(DB **dbs) {
115 for(int i=0;i<NUM_DBS;i++) {
116 int r = dbs[i]->close(dbs[i], 0); CKERR(r);
117 dbs[i] = NULL;
118 }
119 }
120
121
upgrade_test_4(DB ** dbs,test_type test_to_do)122 static void upgrade_test_4(DB **dbs, test_type test_to_do) {
123 int r;
124 int n = 4; // number of rows to check to partially upgrade dictionary
125 char * msg;
126 if (test_to_do == insert)
127 msg = "insert";
128 else if (test_to_do == delete)
129 msg = "delete";
130 else assert(0);
131
132
133 // open the DBS
134 open_dbs(dbs);
135
136 // check first few rows of primary, some (pseudo)random rows of secondaries
137 {
138 check_results(env, dbs, NUM_DBS, n);
139 if (verbose)
140 printf("First %d rows checked, now close and reopen\n", n);
141 }
142
143 // close and reopen
144 close_dbs(dbs);
145 open_dbs(dbs);
146
147 // check first few rows of primary, some (pseudo)random rows of secondaries
148 {
149 n *= 2;
150 check_results(env, dbs, NUM_DBS, n);
151 if (verbose)
152 printf("\nFirst %d rows checked, now %s some rows\n", n, msg);
153 }
154
155 // close and reopen
156 close_dbs(dbs);
157 open_dbs(dbs);
158
159 // insert or delete some rows
160 DB_TXN *txn;
161 DBT skey, sval;
162 DBT key, val;
163 dbt_init_realloc(&key);
164 dbt_init_realloc(&val);
165
166 unsigned int k, v;
167 if ( verbose ) {
168 printf("%s some rows\n", msg);
169 fflush(stdout);
170 }
171 int num_rows_to_modify, base;
172 if (test_to_do == insert) {
173 num_rows_to_modify = NUM_ROWS;
174 base = NUM_ROWS; // insert after existing rows in primary
175 }
176 else if (test_to_do == delete) {
177 num_rows_to_modify = 2*n;
178 base = 0; // delete some rows from primary
179 }
180 else assert(0);
181 int outer_loop_num = ( num_rows_to_modify <= ROWS_PER_TRANSACTION ) ? 1 : (num_rows_to_modify / ROWS_PER_TRANSACTION);
182 for(int x=0;x<outer_loop_num;x++) {
183 r = env->txn_begin(env, NULL, &txn, 0); CKERR(r);
184 for(int i=1; (i<=ROWS_PER_TRANSACTION && i<=num_rows_to_modify); i++) {
185 k = i + (x*ROWS_PER_TRANSACTION) + base;
186 v = generate_val(k, 0);
187 dbt_init(&skey, &k, sizeof(unsigned int));
188 dbt_init(&sval, &v, sizeof(unsigned int));
189
190 for(int db = 0;db < NUM_DBS;db++) {
191 put_multiple_generate(dbs[db], // dest_db
192 NULL, // src_db, ignored
193 &key, &val, //
194 &skey, &sval, // src_key, src_val
195 NULL); // extra, ignored
196 if (test_to_do == insert) {
197 r = dbs[db]->put(dbs[db], txn, &key, &val, 0);
198 CKERR(r);
199 }
200 else if (test_to_do == delete) {
201 r = dbs[db]->del(dbs[db], txn, &key, 0);
202 CKERR(r);
203 }
204 else assert(0);
205
206 if (key.flags == 0) { dbt_init_realloc(&key); }
207 if (val.flags == 0) { dbt_init_realloc(&val); }
208 }
209 }
210 r = txn->commit(txn, 0); CKERR(r);
211 if ( verbose ) {printf(".");fflush(stdout);}
212 }
213 if ( key.flags ) { toku_free(key.data); key.data = NULL; }
214 if ( val.flags ) { toku_free(val.data); key.data = NULL; }
215
216 // close
217 close_dbs(dbs);
218
219 // open
220 open_dbs(dbs);
221
222 // read and verify all rows
223 {
224 if ( verbose ) {printf("\nchecking");fflush(stdout);}
225 if (test_to_do == insert)
226 check_results(env, dbs, NUM_DBS, NUM_ROWS * 2);
227 else if (test_to_do == delete)
228 check_results_after_row_n(env, dbs, NUM_DBS, NUM_ROWS, num_rows_to_modify);
229 else assert(0);
230 if ( verbose) {printf("\ndone\n");fflush(stdout);}
231 }
232 // close
233 {
234 for(int i=0;i<NUM_DBS;i++) {
235 r = dbs[i]->close(dbs[i], 0); CKERR(r);
236 dbs[i] = NULL;
237 }
238 }
239 }
240
setup(void)241 static void setup(void) {
242 int r;
243 int len = 256;
244 char syscmd[len];
245 char * src_db_dir;
246
247 if ( SRC_VERSION == 4 ) {
248 if (littlenode)
249 src_db_dir = db_v4_dir_node4k;
250 else
251 src_db_dir = db_v4_dir;
252 }
253 else if ( SRC_VERSION == 5 ) {
254 src_db_dir = db_v5_dir;
255 }
256 else {
257 fprintf(stderr, "unsupported PerconaFT version %d to upgrade\n", SRC_VERSION);
258 assert(0);
259 }
260
261 r = snprintf(syscmd, len, "rm -rf %s", env_dir);
262 assert(r<len);
263 r = system(syscmd);
264 CKERR(r);
265
266 r = snprintf(syscmd, len, "cp -r %s %s", src_db_dir, env_dir);
267 assert(r<len);
268 r = system(syscmd);
269 CKERR(r);
270 generate_permute_tables();
271
272 }
273
run_test(test_type test_to_do)274 static void run_test(test_type test_to_do)
275 {
276 int r;
277
278 r = db_env_create(&env, 0); CKERR(r);
279 if (littlenode) {
280 r = env->set_cachesize(env, 0, 512*1024, 1); CKERR(r);
281 }
282 r = env->set_redzone(env, 0); CKERR(r);
283 int envflags = DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_CREATE | DB_PRIVATE;
284 r = env->open(env, env_dir, envflags, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
285 env->set_errfile(env, stderr);
286 r = env->checkpointing_set_period(env, 5); CKERR(r);
287
288 DB **dbs = (DB**)toku_malloc(sizeof(DB*) * NUM_DBS);
289 assert(dbs != NULL);
290
291 // --------------------------
292 upgrade_test_4(dbs, test_to_do);
293 // --------------------------
294
295 if (verbose >= 2)
296 print_engine_status(env);
297 r = env->close(env, 0); CKERR(r);
298 toku_free(dbs);
299
300 }
301
302 // ------------ infrastructure ----------
303 static void do_args(int argc, char * const argv[]);
304
test_main(int argc,char * const * argv)305 int test_main(int argc, char * const *argv) {
306 do_args(argc, argv);
307 littlenode = 0;
308 setup();
309 run_test(insert);
310 setup();
311 run_test(delete);
312 if (SRC_VERSION == 4) {
313 if (verbose)
314 printf("Now repeat test with small nodes and small cache.\n");
315 littlenode = 1; // 4k nodes, small cache
316 setup();
317 run_test(insert);
318 setup();
319 run_test(delete);
320 }
321 return 0;
322 }
323
do_args(int argc,char * const argv[])324 static void do_args(int argc, char * const argv[]) {
325 int resultcode;
326 char *cmd = argv[0];
327 argc--; argv++;
328
329 while (argc>0) {
330 if (strcmp(argv[0], "-v")==0) {
331 verbose++;
332 } else if (strcmp(argv[0],"-q")==0) {
333 verbose--;
334 if (verbose<0) verbose=0;
335 } else if (strcmp(argv[0], "-h")==0) {
336 resultcode=0;
337 do_usage:
338 fprintf(stderr, "Usage: -h -c -d <num_dbs> -r <num_rows> %s\n", cmd);
339 exit(resultcode);
340 } else if (strcmp(argv[0], "-d")==0) {
341 argc--; argv++;
342 NUM_DBS = atoi(argv[0]);
343 if ( NUM_DBS > MAX_DBS ) {
344 fprintf(stderr, "max value for -d field is %d\n", MAX_DBS);
345 resultcode=1;
346 goto do_usage;
347 }
348 } else if (strcmp(argv[0], "-r")==0) {
349 argc--; argv++;
350 NUM_ROWS = atoi(argv[0]);
351 } else if (strcmp(argv[0], "-c")==0) {
352 CHECK_RESULTS = 1;
353 } else if (strcmp(argv[0], "-V")==0) {
354 argc--; argv++;
355 SRC_VERSION = atoi(argv[0]);
356 } else {
357 fprintf(stderr, "Unknown arg: %s\n", argv[0]);
358 resultcode=1;
359 goto do_usage;
360 }
361 argc--;
362 argv++;
363 }
364 }
365