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 #include "toku_os.h"
42 #include "cachetable/checkpoint.h"
43
44 #define ENVDIR TOKU_TEST_FILENAME
45 #include "test-ft-txns.h"
46
do_txn(TOKULOGGER logger,bool readonly)47 static void do_txn(TOKULOGGER logger, bool readonly) {
48 int r;
49 TOKUTXN txn;
50 r = toku_txn_begin_txn((DB_TXN*)NULL, (TOKUTXN)0, &txn, logger, TXN_SNAPSHOT_NONE, false);
51 CKERR(r);
52
53 if (!readonly) {
54 toku_maybe_log_begin_txn_for_write_operation(txn);
55 }
56 r = toku_txn_commit_txn(txn, false, NULL, NULL);
57 CKERR(r);
58
59 toku_txn_close_txn(txn);
60 }
61
test_xid_lsn_independent(int N)62 static void test_xid_lsn_independent(int N) {
63 TOKULOGGER logger;
64 CACHETABLE ct;
65 int r;
66
67 test_setup(TOKU_TEST_FILENAME, &logger, &ct);
68
69 FT_HANDLE ft;
70
71 TOKUTXN txn;
72 r = toku_txn_begin_txn((DB_TXN*)NULL, (TOKUTXN)0, &txn, logger, TXN_SNAPSHOT_NONE, false);
73 CKERR(r);
74
75 r = toku_open_ft_handle("ftfile", 1, &ft, 1024, 256, TOKU_DEFAULT_COMPRESSION_METHOD, ct, txn, toku_builtin_compare_fun);
76 CKERR(r);
77
78 r = toku_txn_commit_txn(txn, false, NULL, NULL);
79 CKERR(r);
80 toku_txn_close_txn(txn);
81
82 r = toku_txn_begin_txn((DB_TXN*)NULL, (TOKUTXN)0, &txn, logger, TXN_SNAPSHOT_NONE, false);
83 CKERR(r);
84 TXNID xid_first = txn->txnid.parent_id64;
85 unsigned int rands[N];
86 for (int i=0; i<N; i++) {
87 char key[100],val[300];
88 DBT k, v;
89 rands[i] = random();
90 snprintf(key, sizeof(key), "key%x.%x", rands[i], i);
91 memset(val, 'v', sizeof(val));
92 val[sizeof(val)-1]=0;
93 toku_ft_insert(ft, toku_fill_dbt(&k, key, 1+strlen(key)), toku_fill_dbt(&v, val, 1+strlen(val)), txn);
94 }
95 {
96 TOKUTXN txn2;
97 r = toku_txn_begin_txn((DB_TXN*)NULL, (TOKUTXN)0, &txn2, logger, TXN_SNAPSHOT_NONE, false);
98 CKERR(r);
99 // Verify the txnid has gone up only by one (even though many log entries were done)
100 invariant(txn2->txnid.parent_id64 == xid_first + 1);
101 r = toku_txn_commit_txn(txn2, false, NULL, NULL);
102 CKERR(r);
103 toku_txn_close_txn(txn2);
104 }
105 r = toku_txn_commit_txn(txn, false, NULL, NULL);
106 CKERR(r);
107 toku_txn_close_txn(txn);
108 {
109 //TODO(yoni) #5067 will break this portion of the test. (End ids are also assigned, so it would increase by 4 instead of 2.)
110 // Verify the txnid has gone up only by two (even though many log entries were done)
111 TOKUTXN txn3;
112 r = toku_txn_begin_txn((DB_TXN*)NULL, (TOKUTXN)0, &txn3, logger, TXN_SNAPSHOT_NONE, false);
113 CKERR(r);
114 invariant(txn3->txnid.parent_id64 == xid_first + 2);
115 r = toku_txn_commit_txn(txn3, false, NULL, NULL);
116 CKERR(r);
117 toku_txn_close_txn(txn3);
118 }
119 CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
120 r = toku_checkpoint(cp, logger, NULL, NULL, NULL, NULL, CLIENT_CHECKPOINT);
121 CKERR(r);
122 r = toku_close_ft_handle_nolsn(ft, NULL);
123 CKERR(r);
124
125 clean_shutdown(&logger, &ct);
126 }
127
128 static TXNID
logger_get_last_xid(TOKULOGGER logger)129 logger_get_last_xid(TOKULOGGER logger) {
130 TXN_MANAGER mgr = toku_logger_get_txn_manager(logger);
131 return toku_txn_manager_get_last_xid(mgr);
132 }
133
test_xid_lsn_independent_crash_recovery(int N)134 static void test_xid_lsn_independent_crash_recovery(int N) {
135 TOKULOGGER logger;
136 CACHETABLE ct;
137 int r;
138
139 test_setup(TOKU_TEST_FILENAME, &logger, &ct);
140
141 for (int i=0; i < N - 1; i++) {
142 do_txn(logger, true);
143 }
144 do_txn(logger, false);
145
146 TXNID last_xid_before = logger_get_last_xid(logger);
147
148 toku_logger_close_rollback(logger);
149
150 toku_cachetable_close(&ct);
151 // "Crash"
152 r = toku_logger_close(&logger);
153 CKERR(r);
154 ct = NULL;
155 logger = NULL;
156
157 // "Recover"
158 test_setup_and_recover(TOKU_TEST_FILENAME, &logger, &ct);
159
160 TXNID last_xid_after = logger_get_last_xid(logger);
161
162 invariant(last_xid_after == last_xid_before);
163
164 shutdown_after_recovery(&logger, &ct);
165 }
166
test_xid_lsn_independent_shutdown_recovery(int N)167 static void test_xid_lsn_independent_shutdown_recovery(int N) {
168 TOKULOGGER logger;
169 CACHETABLE ct;
170 test_setup(TOKU_TEST_FILENAME, &logger, &ct);
171
172 for (int i=0; i < N - 1; i++) {
173 do_txn(logger, true);
174 }
175 do_txn(logger, false);
176
177 TXNID last_xid_before = logger_get_last_xid(logger);
178
179 clean_shutdown(&logger, &ct);
180
181 // Did a clean shutdown.
182
183 // "Recover"
184 test_setup_and_recover(TOKU_TEST_FILENAME, &logger, &ct);
185
186 TXNID last_xid_after = logger_get_last_xid(logger);
187
188 invariant(last_xid_after == last_xid_before);
189
190 shutdown_after_recovery(&logger, &ct);
191 }
192
test_xid_lsn_independent_parents(int N)193 static void test_xid_lsn_independent_parents(int N) {
194 TOKULOGGER logger;
195 CACHETABLE ct;
196 int r;
197
198 // Lets txns[-1] be NULL
199 TOKUTXN txns_hack[N+1];
200 TOKUTXN *txns=&txns_hack[1];
201
202 int num_non_cascade = N;
203 do {
204 test_setup(TOKU_TEST_FILENAME, &logger, &ct);
205 ZERO_ARRAY(txns_hack);
206
207 for (int i = 0; i < N; i++) {
208 r = toku_txn_begin_txn((DB_TXN*)NULL, txns[i-1], &txns[i], logger, TXN_SNAPSHOT_NONE, false);
209 CKERR(r);
210
211 if (i < num_non_cascade) {
212 toku_maybe_log_begin_txn_for_write_operation(txns[i]);
213 invariant(txns[i]->begin_was_logged);
214 }
215 else {
216 invariant(!txns[i]->begin_was_logged);
217 }
218 }
219 for (int i = 0; i < N; i++) {
220 if (i < num_non_cascade) {
221 toku_maybe_log_begin_txn_for_write_operation(txns[i]);
222 invariant(txns[i]->begin_was_logged);
223 }
224 else {
225 invariant(!txns[i]->begin_was_logged);
226 }
227 }
228 toku_maybe_log_begin_txn_for_write_operation(txns[N-1]);
229 for (int i = 0; i < N; i++) {
230 invariant(txns[i]->begin_was_logged);
231 }
232 for (int i = N-1; i >= 0; i--) {
233 r = toku_txn_commit_txn(txns[i], false, NULL, NULL);
234 CKERR(r);
235
236 toku_txn_close_txn(txns[i]);
237 }
238 clean_shutdown(&logger, &ct);
239
240 num_non_cascade /= 2;
241 } while (num_non_cascade > 0);
242 }
243
test_main(int argc,const char * argv[])244 int test_main (int argc, const char *argv[]) {
245 default_parse_args(argc, argv);
246 for (int i=1; i<=128; i *= 2) {
247 test_xid_lsn_independent(i);
248 test_xid_lsn_independent_crash_recovery(i);
249 test_xid_lsn_independent_shutdown_recovery(i);
250 test_xid_lsn_independent_parents(i);
251 }
252 return 0;
253 }
254