1
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
4
COPYING CONDITIONS NOTICE:
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of version 2 of the GNU General Public License as
8
published by the Free Software Foundation, and provided that the
9
following conditions are met:
11
* Redistributions of source code must retain this COPYING
12
CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
13
DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
14
PATENT MARKING NOTICE (below), and the PATENT RIGHTS
17
* Redistributions in binary form must reproduce this COPYING
18
CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
19
DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
20
PATENT MARKING NOTICE (below), and the PATENT RIGHTS
21
GRANT (below) in the documentation and/or other materials
22
provided with the distribution.
24
You should have received a copy of the GNU General Public License
25
along with this program; if not, write to the Free Software
26
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31
TokuDB, Tokutek Fractal Tree Indexing Library.
32
Copyright (C) 2007-2013 Tokutek, Inc.
36
This program is distributed in the hope that it will be useful, but
37
WITHOUT ANY WARRANTY; without even the implied warranty of
38
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39
General Public License for more details.
41
UNIVERSITY PATENT NOTICE:
43
The technology is licensed by the Massachusetts Institute of
44
Technology, Rutgers State University of New Jersey, and the Research
45
Foundation of State University of New York at Stony Brook under
46
United States of America Serial No. 11/760379 and to the patents
47
and/or patent applications resulting from it.
49
PATENT MARKING NOTICE:
51
This software is covered by US Patent No. 8,185,551.
52
This software is covered by US Patent No. 8,489,638.
56
"THIS IMPLEMENTATION" means the copyrightable works distributed by
57
Tokutek as part of the Fractal Tree project.
59
"PATENT CLAIMS" means the claims of patents that are owned or
60
licensable by Tokutek, both currently or in the future; and that in
61
the absence of this license would be infringed by THIS
62
IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
64
"PATENT CHALLENGE" shall mean a challenge to the validity,
65
patentability, enforceability and/or non-infringement of any of the
66
PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
68
Tokutek hereby grants to you, for the term and geographical scope of
69
the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
70
irrevocable (except as stated in this section) patent license to
71
make, have made, use, offer to sell, sell, import, transfer, and
72
otherwise run, modify, and propagate the contents of THIS
73
IMPLEMENTATION, where such license applies only to the PATENT
74
CLAIMS. This grant does not include claims that would be infringed
75
only as a consequence of further modifications of THIS
76
IMPLEMENTATION. If you or your agent or licensee institute or order
77
or agree to the institution of patent litigation against any entity
78
(including a cross-claim or counterclaim in a lawsuit) alleging that
79
THIS IMPLEMENTATION constitutes direct or contributory patent
80
infringement, or inducement of patent infringement, then any rights
81
granted to you under this License shall terminate as of the date
82
such litigation is filed. If you or your agent or exclusive
83
licensee institute or order or agree to the institution of a PATENT
84
CHALLENGE, then Tokutek may terminate any rights granted to you
88
#ident "Copyright (c) 2010-2013 Tokutek Inc. All rights reserved."
89
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
92
// test the hotindexer undo do function
93
// read a description of the live transactions and a leafentry from a test file, run the undo do function,
94
// and print out the actions taken by the undo do function while processing the leafentry
98
#include <ft/tokuconst.h>
99
#include <ft/fttypes.h>
101
#include <ft/leafentry.h>
103
#include <ft/ule-internal.h>
104
#include <ft/le-cursor.h>
105
#include "indexer-internal.h"
106
#include <ft/xids-internal.h>
120
live_init(struct live *live) {
121
live->n = live->o = 0;
126
live_destroy(struct live *live) {
127
toku_free(live->txns);
131
live_add(struct live *live, TXNID xid, TOKUTXN_STATE state) {
132
if (live->o >= live->n) {
133
int newn = live->n == 0 ? 1 : live->n * 2;
134
live->txns = (struct txn *) toku_realloc(live->txns, newn * sizeof (struct txn));
135
resource_assert(live->txns);
138
live->txns[live->o++] = (struct txn ) { xid, state };
142
lookup_txn_state(struct live *live, TXNID xid) {
143
TOKUTXN_STATE r = TOKUTXN_RETIRED;
144
for (int i = 0; i < live->o; i++) {
145
if (live->txns[i].xid == xid) {
146
r = live->txns[i].state;
153
// live transaction ID set
154
struct live live_xids;
157
uxr_init(UXR uxr, uint8_t type, void *val, uint32_t vallen, TXNID xid) {
159
uxr->valp = toku_malloc(vallen); resource_assert(uxr->valp);
160
memcpy(uxr->valp, val, vallen);
161
uxr->vallen = vallen;
166
uxr_destroy(UXR uxr) {
167
toku_free(uxr->valp);
175
ule->uxrs = ule->uxrs_static;
180
ule_destroy(ULE ule) {
181
for (unsigned int i = 0; i < ule->num_cuxrs + ule->num_puxrs; i++) {
182
uxr_destroy(&ule->uxrs[i]);
187
ule_add_provisional(ULE ule, UXR uxr) {
188
invariant(ule->num_cuxrs + ule->num_puxrs + 1 <= MAX_TRANSACTION_RECORDS*2);
189
ule->uxrs[ule->num_cuxrs + ule->num_puxrs] = *uxr;
194
ule_add_committed(ULE ule, UXR uxr) {
195
lazy_assert(ule->num_puxrs == 0);
196
invariant(ule->num_cuxrs + 1 <= MAX_TRANSACTION_RECORDS*2);
197
ule->uxrs[ule->num_cuxrs] = *uxr;
203
ULE ule = (ULE) toku_calloc(1, sizeof (ULE_S)); resource_assert(ule);
216
print_xids(XIDS xids) {
218
if (xids->num_xids == 0)
221
for (int i = 0; i < xids->num_xids; i++) {
222
printf("%" PRIu64, xids->ids[i]);
223
if (i+1 < xids->num_xids)
231
print_dbt(DBT *dbt) {
232
printf("%.*s ", dbt->size, (char *) dbt->data);
236
put_callback(DB *dest_db, DB *src_db, DBT_ARRAY *dest_keys, DBT_ARRAY *dest_vals, const DBT *src_key, const DBT *src_val) {
237
toku_dbt_array_resize(dest_keys, 1);
238
toku_dbt_array_resize(dest_vals, 1);
239
DBT *dest_key = &dest_keys->dbts[0];
240
DBT *dest_val = &dest_vals->dbts[0];
241
(void) dest_db; (void) src_db; (void) dest_key; (void) dest_val; (void) src_key; (void) src_val;
243
lazy_assert(src_db != NULL && dest_db != NULL);
245
switch (dest_key->flags) {
247
dest_key->data = src_val->data;
248
dest_key->size = src_val->size;
251
dest_key->data = toku_realloc(dest_key->data, src_val->size);
252
memcpy(dest_key->data, src_val->data, src_val->size);
253
dest_key->size = src_val->size;
260
switch (dest_val->flags) {
265
dest_val->data = toku_realloc(dest_val->data, src_key->size);
266
memcpy(dest_val->data, src_key->data, src_key->size);
267
dest_val->size = src_key->size;
277
del_callback(DB *dest_db, DB *src_db, DBT_ARRAY *dest_keys, const DBT *src_key, const DBT *src_data) {
278
toku_dbt_array_resize(dest_keys, 1);
279
DBT *dest_key = &dest_keys->dbts[0];
280
(void) dest_db; (void) src_db; (void) dest_key; (void) src_key; (void) src_data;
282
lazy_assert(src_db != NULL && dest_db != NULL);
284
switch (dest_key->flags) {
286
dest_key->data = src_data->data;
287
dest_key->size = src_data->size;
290
dest_key->data = toku_realloc(dest_key->data, src_data->size);
291
memcpy(dest_key->data, src_data->data, src_data->size);
292
dest_key->size = src_data->size;
301
static DB_INDEXER *test_indexer = NULL;
302
static DB *test_hotdb = NULL;
305
test_xid_state(DB_INDEXER *indexer, TXNID xid) {
306
invariant(indexer == test_indexer);
307
TOKUTXN_STATE r = lookup_txn_state(&live_xids, xid);
312
test_lock_key(DB_INDEXER *indexer, TXNID xid, DB *hotdb, DBT *key) {
313
invariant(indexer == test_indexer);
314
invariant(hotdb == test_hotdb);
315
TOKUTXN_STATE txn_state = test_xid_state(indexer, xid);
316
invariant(txn_state == TOKUTXN_LIVE || txn_state == TOKUTXN_PREPARING);
317
printf("lock [%" PRIu64 "] ", xid);
323
test_delete_provisional(DB_INDEXER *indexer, DB *hotdb, DBT *hotkey, XIDS xids) {
324
invariant(indexer == test_indexer);
325
invariant(hotdb == test_hotdb);
326
printf("delete_provisional ");
334
test_delete_committed(DB_INDEXER *indexer, DB *hotdb, DBT *hotkey, XIDS xids) {
335
invariant(indexer == test_indexer);
336
invariant(hotdb == test_hotdb);
337
printf("delete_committed ");
345
test_insert_provisional(DB_INDEXER *indexer, DB *hotdb, DBT *hotkey, DBT *hotval, XIDS xids) {
346
invariant(indexer == test_indexer);
347
invariant(hotdb == test_hotdb);
348
printf("insert_provisional ");
357
test_insert_committed(DB_INDEXER *indexer, DB *hotdb, DBT *hotkey, DBT *hotval, XIDS xids) {
358
invariant(indexer == test_indexer);
359
invariant(hotdb == test_hotdb);
360
printf("insert_committed ");
369
test_commit_any(DB_INDEXER *indexer, DB *hotdb, DBT *hotkey, XIDS xids) {
370
invariant(indexer == test_indexer);
371
invariant(hotdb == test_hotdb);
372
printf("commit_any ");
380
split_fields(char *line, char *fields[], int maxfields) {
382
for (i = 0; i < maxfields; i++, line = NULL) {
383
fields[i] = strtok(line, " ");
384
if (fields[i] == NULL)
391
read_line(char **line_ptr, size_t *len_ptr, FILE *f) {
392
char *line = *line_ptr;
394
bool in_comment = false;
399
else if (c == '\n') {
407
XREALLOC_N(len+1, line);
413
XREALLOC_N(len+1, line);
418
return len == 0 ? -1 : 0;
421
struct saved_lines_t {
428
save_line(char** line, saved_lines_t* saved) {
429
if (saved->capacity == saved->used) {
430
if (saved->capacity == 0) {
433
saved->capacity *= 2;
434
XREALLOC_N(saved->capacity, saved->savedlines);
436
saved->savedlines[saved->used++] = *line;
441
read_test(char *testname, ULE ule, DBT* key, saved_lines_t* saved) {
443
FILE *f = fopen(testname, "r");
447
while (read_line(&line, &len, f) != -1) {
448
// printf("%s", line);
450
const int maxfields = 8;
451
char *fields[maxfields];
452
int nfields = split_fields(line, fields, maxfields);
453
// for (int i = 0; i < nfields; i++); printf("%s ", fields[i]); printf("\n");
458
if (strcmp(fields[0], "live") == 0) {
459
for (int i = 1; i < nfields; i++)
460
live_add(&live_xids, atoll(fields[i]), TOKUTXN_LIVE);
463
// xid <XID> [live|committing|aborting]
464
if (strcmp(fields[0], "xid") == 0 && nfields == 3) {
465
TXNID xid = atoll(fields[1]);
466
TOKUTXN_STATE state = TOKUTXN_RETIRED;
467
if (strcmp(fields[2], "live") == 0)
468
state = TOKUTXN_LIVE;
469
else if (strcmp(fields[2], "preparing") == 0)
470
state = TOKUTXN_PREPARING;
471
else if (strcmp(fields[2], "committing") == 0)
472
state = TOKUTXN_COMMITTING;
473
else if (strcmp(fields[2], "aborting") == 0)
474
state = TOKUTXN_ABORTING;
477
live_add(&live_xids, xid, state);
481
if (strcmp(fields[0], "key") == 0 && nfields == 2) {
482
save_line(&line, saved);
483
dbt_init(key, fields[1], strlen(fields[1]));
486
// insert committed|provisional XID DATA
487
if (strcmp(fields[0], "insert") == 0 && nfields == 4) {
488
save_line(&line, saved);
490
uxr_init(&uxr_s, XR_INSERT, fields[3], strlen(fields[3]), atoll(fields[2]));
491
if (fields[1][0] == 'p')
492
ule_add_provisional(ule, &uxr_s);
493
if (fields[1][0] == 'c')
494
ule_add_committed(ule, &uxr_s);
497
// delete committed|provisional XID
498
if (strcmp(fields[0], "delete") == 0 && nfields == 3) {
500
uxr_init(&uxr_s, XR_DELETE, NULL, 0, atoll(fields[2]));
501
if (fields[1][0] == 'p')
502
ule_add_provisional(ule, &uxr_s);
503
if (fields[1][0] == 'c')
504
ule_add_committed(ule, &uxr_s);
508
if (strcmp(fields[0], "placeholder") == 0 && nfields == 2) {
510
uxr_init(&uxr_s, XR_PLACEHOLDER, NULL, 0, atoll(fields[1]));
511
ule_add_provisional(ule, &uxr_s);
514
// placeholder provisional XID
515
if (strcmp(fields[0], "placeholder") == 0 && nfields == 3 && fields[1][0] == 'p') {
517
uxr_init(&uxr_s, XR_PLACEHOLDER, NULL, 0, atoll(fields[2]));
518
ule_add_provisional(ule, &uxr_s);
521
fprintf(stderr, "%s???\n", line);
528
fprintf(stderr, "fopen %s errno=%d\n", testname, errno);
534
run_test(char *envdir, char *testname) {
536
printf("%s\n", testname);
538
live_init(&live_xids);
542
r = db_env_create(&env, 0); assert_zero(r);
543
r = env->set_redzone(env, 0); assert_zero(r);
545
r = env->set_generate_row_callback_for_put(env, put_callback); assert_zero(r);
546
r = env->set_generate_row_callback_for_del(env, del_callback); assert_zero(r);
548
r = env->open(env, envdir, 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);
551
r = db_create(&src_db, env, 0); assert_zero(r);
552
r = src_db->open(src_db, NULL, "0.tdb", NULL, DB_BTREE, DB_AUTO_COMMIT+DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r);
555
r = db_create(&dest_db, env, 0); assert_zero(r);
556
r = dest_db->open(dest_db, NULL, "1.tdb", NULL, DB_BTREE, DB_AUTO_COMMIT+DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r);
559
r = env->txn_begin(env, NULL, &txn, 0); assert_zero(r);
561
DB_INDEXER *indexer = NULL;
562
r = env->create_indexer(env, txn, &indexer, src_db, 1, &dest_db, NULL, 0); assert_zero(r);
564
// set test callbacks
565
indexer->i->test_xid_state = test_xid_state;
566
indexer->i->test_lock_key = test_lock_key;
567
indexer->i->test_delete_provisional = test_delete_provisional;
568
indexer->i->test_delete_committed = test_delete_committed;
569
indexer->i->test_insert_provisional = test_insert_provisional;
570
indexer->i->test_insert_committed = test_insert_committed;
571
indexer->i->test_commit_any = test_commit_any;
573
// verify indexer and hotdb in the callbacks
574
test_indexer = indexer;
575
test_hotdb = dest_db;
578
ULE ule = ule_create();
586
r = read_test(testname, ule, &key, &saved);
590
r = indexer->i->undo_do(indexer, dest_db, &key, ule); assert_zero(r);
595
for (uint32_t i = 0; i < saved.used; i++) {
596
toku_free(saved.savedlines[i]);
598
toku_free(saved.savedlines);
600
r = indexer->close(indexer); assert_zero(r);
602
r = txn->abort(txn); assert_zero(r);
604
r = src_db->close(src_db, 0); assert_zero(r);
605
r = dest_db->close(dest_db, 0); assert_zero(r);
607
r = env->close(env, 0); assert_zero(r);
609
live_destroy(&live_xids);
615
test_main(int argc, char * const argv[]) {
618
// parse_args(argc, argv);
620
for (i = 1; i < argc; i++) {
621
char * const arg = argv[i];
622
if (strcmp(arg, "-v") == 0) {
626
if (strcmp(arg, "-q") == 0) {
634
toku_os_recursive_delete(TOKU_TEST_FILENAME);
635
r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);
637
for (r = 0 ; r == 0 && i < argc; i++) {
638
char *testname = argv[i];
640
sprintf(pid, "%d", toku_os_getpid());
641
char envdir[TOKU_PATH_MAX+1];
642
toku_path_join(envdir, 2, TOKU_TEST_FILENAME, pid);
644
toku_os_recursive_delete(envdir);
645
r = toku_os_mkdir(envdir, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r);
647
r = run_test(envdir, testname);