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