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 // insert enough rows with a child txn and then force an eviction to verify the rollback
42 // log node is in valid state.
43 // the test fails without the fix (and of course passes with it).
44 // The test basically simulates the test script of George's.
45
46
47 static void
populate_table(int start,int end,DB_TXN * parent,DB_ENV * env,DB * db)48 populate_table(int start, int end, DB_TXN * parent, DB_ENV * env, DB * db) {
49 DB_TXN *txn = NULL;
50 int r = env->txn_begin(env, parent, &txn, 0); assert_zero(r);
51 for (int i = start; i < end; i++) {
52 int k = htonl(i);
53 char kk[4];
54 char str[220];
55 memset(kk, 0, sizeof kk);
56 memcpy(kk, &k, sizeof k);
57 memset(str,'a', sizeof str);
58 DBT key = { .data = kk, .size = sizeof kk };
59 DBT val = { .data = str, .size = sizeof str };
60 r = db->put(db, txn, &key, &val, 0);
61 assert_zero(r);
62 }
63 r = txn->commit(txn, 0);
64 assert_zero(r);
65 }
66
67 static void
populate_and_test(DB_ENV * env,DB * db)68 populate_and_test(DB_ENV *env, DB *db) {
69 int r;
70 DB_TXN *parent = NULL;
71 r = env->txn_begin(env, NULL, &parent, 0); assert_zero(r);
72
73 populate_table(0, 128, parent, env, db);
74
75 //we know the eviction is going to happen here and the log node of parent txn is going to be evicted
76 //due to the extremely low cachesize.
77 populate_table(128, 256, parent, env, db);
78
79 //again eviction due to the memory pressure. 256 rows is the point when that rollback log spills out. The spilled node
80 //will be written back but will not be dirtied by including rollback nodes from child txn(in which case the bug is bypassed).
81 populate_table(256, 512, parent, env, db);
82
83 r = parent->abort(parent); assert_zero(r);
84
85 //try to search anything in the lost range
86 int k = htonl(200);
87 char kk[4];
88 memset(kk, 0, sizeof kk);
89 memcpy(kk, &k, sizeof k);
90 DBT key = { .data = kk, .size = sizeof kk };
91 DBT val;
92 r = db->get(db, NULL, &key, &val, 0);
93 assert(r==DB_NOTFOUND);
94
95 }
96
97 static void
run_test(void)98 run_test(void) {
99 int r;
100 DB_ENV *env = NULL;
101 r = db_env_create(&env, 0);
102 assert_zero(r);
103 env->set_errfile(env, stderr);
104
105 //setting up the cachetable size 64k
106 uint32_t cachesize = 64*1024;
107 r = env->set_cachesize(env, 0, cachesize, 1);
108 assert_zero(r);
109
110 //setting up the log write block size to 4k so the rollback log nodes spill in accordance with the node size
111 r = env->set_lg_bsize(env, 4096);
112 assert_zero(r);
113
114 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);
115 assert_zero(r);
116
117 DB *db = NULL;
118 r = db_create(&db, env, 0);
119 assert_zero(r);
120
121 r = db->set_pagesize(db, 4096);
122 assert_zero(r);
123
124 r = db->set_readpagesize(db, 1024);
125 assert_zero(r);
126
127 r = db->open(db, NULL, "test.tdb", NULL, DB_BTREE, DB_AUTO_COMMIT+DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO);
128 assert_zero(r);
129
130 populate_and_test(env, db);
131
132 r = db->close(db, 0); assert_zero(r);
133
134 r = env->close(env, 0); assert_zero(r);
135 }
136
137 int
test_main(int argc,char * const argv[])138 test_main(int argc, char * const argv[]) {
139 int r;
140
141 // parse_args(argc, argv);
142 for (int i = 1; i < argc; i++) {
143 char * const arg = argv[i];
144 if (strcmp(arg, "-v") == 0) {
145 verbose++;
146 continue;
147 }
148 if (strcmp(arg, "-q") == 0) {
149 verbose = 0;
150 continue;
151 }
152 }
153
154 toku_os_recursive_delete(TOKU_TEST_FILENAME);
155 r = toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); assert_zero(r);
156
157 run_test();
158
159 return 0;
160 }
161
162