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 #include "test-ft-txns.h"
45 
txn_child_manager_test_cb(TOKUTXN txn,void * extra)46 static int txn_child_manager_test_cb(TOKUTXN txn, void* extra) {
47     TOKUTXN* ptxn = (TOKUTXN *)extra;
48     assert(txn == *ptxn);
49     *ptxn = txn->child;
50     return 0;
51 }
52 
txn_child_manager_test_cb2(TOKUTXN txn,void * extra)53 static int txn_child_manager_test_cb2(TOKUTXN txn, void* extra) {
54     TOKUTXN extra_txn = (TOKUTXN)extra;
55     if (txn == extra_txn) {
56         return -1;
57     }
58     return 0;
59 }
60 
61 
62 class txn_child_manager_unit_test {
63 public:
64     void run_test();
65     void run_child_txn_test();
66 };
67 
68 // simple test that verifies that creating a TXN_CHILD_SNAPSHOT tokutxn
69 // creates its own snapshot
run_child_txn_test()70 void txn_child_manager_unit_test::run_child_txn_test() {
71     TOKULOGGER logger;
72     CACHETABLE ct;
73     int r = 0;
74     test_setup(TOKU_TEST_FILENAME, &logger, &ct);
75     // create the root transaction
76     TOKUTXN root_txn = NULL;
77     r = toku_txn_begin_txn(
78         (DB_TXN *)NULL,
79         NULL,
80         &root_txn,
81         logger,
82         TXN_SNAPSHOT_CHILD,
83         false
84         );
85     CKERR(r);
86     // test starting a child txn
87     TOKUTXN child_txn = NULL;
88     r = toku_txn_begin_txn(
89         NULL,
90         root_txn,
91         &child_txn,
92         logger,
93         TXN_SNAPSHOT_CHILD,
94         false
95         );
96     CKERR(r);
97 
98     // assert that the child has a later snapshot
99     assert(child_txn->snapshot_txnid64 > root_txn->snapshot_txnid64);
100 
101     r = toku_txn_commit_txn(child_txn, true, NULL, NULL);
102     CKERR(r);
103     toku_txn_close_txn(child_txn);
104     assert(root_txn->child == NULL);
105 
106     r = toku_txn_commit_txn(root_txn, true, NULL, NULL);
107     CKERR(r);
108     toku_txn_close_txn(root_txn);
109 
110 
111     clean_shutdown(&logger, &ct);
112 }
113 
run_test()114 void txn_child_manager_unit_test::run_test() {
115     TOKULOGGER logger;
116     CACHETABLE ct;
117     int r = 0;
118     test_setup(TOKU_TEST_FILENAME, &logger, &ct);
119     // create the root transaction
120     TOKUTXN root_txn = NULL;
121     r = toku_txn_begin_txn(
122         (DB_TXN *)NULL,
123         NULL,
124         &root_txn,
125         logger,
126         TXN_SNAPSHOT_ROOT,
127         false
128         );
129     CKERR(r);
130     txn_child_manager* cm = root_txn->child_manager;
131     assert(cm == &root_txn->child_manager_s);
132     assert(cm->m_root == root_txn);
133     assert(cm->m_last_xid == TXNID_NONE);
134     assert(root_txn->child == NULL);
135     // this assumption implies our assumptions of child_id values below,
136     // because the parent id cannot be the child id
137     assert(root_txn->txnid.parent_id64 == 1);
138 
139     // test starting a child txn
140     TOKUTXN child_txn = NULL;
141     r = toku_txn_begin_txn(
142         NULL,
143         root_txn,
144         &child_txn,
145         logger,
146         TXN_SNAPSHOT_ROOT,
147         false
148         );
149     CKERR(r);
150     assert(child_txn->child_manager == cm);
151     assert(child_txn->parent == root_txn);
152     assert(root_txn->child == child_txn);
153     assert(child_txn->txnid.parent_id64 == root_txn->txnid.parent_id64);
154     assert(child_txn->txnid.child_id64 == 2);
155     assert(child_txn->live_root_txn_list == root_txn->live_root_txn_list);
156     assert(child_txn->snapshot_txnid64 == root_txn->snapshot_txnid64);
157 
158     assert(cm->m_root == root_txn);
159     assert(cm->m_last_xid == child_txn->txnid.child_id64);
160 
161     TOKUTXN grandchild_txn = NULL;
162     r = toku_txn_begin_txn(
163         NULL,
164         child_txn,
165         &grandchild_txn,
166         logger,
167         TXN_SNAPSHOT_ROOT,
168         false
169         );
170     CKERR(r);
171     assert(grandchild_txn->child_manager == cm);
172     assert(grandchild_txn->parent == child_txn);
173     assert(child_txn->child == grandchild_txn);
174     assert(grandchild_txn->txnid.parent_id64 == root_txn->txnid.parent_id64);
175     assert(grandchild_txn->txnid.child_id64 == 3);
176     assert(grandchild_txn->live_root_txn_list == root_txn->live_root_txn_list);
177     assert(grandchild_txn->snapshot_txnid64 == root_txn->snapshot_txnid64);
178 
179     assert(cm->m_root == root_txn);
180     assert(cm->m_last_xid == grandchild_txn->txnid.child_id64);
181 
182     r = toku_txn_commit_txn(grandchild_txn, true, NULL, NULL);
183     CKERR(r);
184     toku_txn_close_txn(grandchild_txn);
185 
186 
187     // now after closing one grandchild txn, open another one
188     r = toku_txn_begin_txn(
189         NULL,
190         child_txn,
191         &grandchild_txn,
192         logger,
193         TXN_SNAPSHOT_ROOT,
194         false
195         );
196     CKERR(r);
197     assert(grandchild_txn->child_manager == cm);
198     assert(grandchild_txn->parent == child_txn);
199     assert(child_txn->child == grandchild_txn);
200     assert(grandchild_txn->txnid.parent_id64 == root_txn->txnid.parent_id64);
201     assert(grandchild_txn->txnid.child_id64 == 4);
202     assert(grandchild_txn->live_root_txn_list == root_txn->live_root_txn_list);
203     assert(grandchild_txn->snapshot_txnid64 == root_txn->snapshot_txnid64);
204 
205     assert(cm->m_root == root_txn);
206     assert(cm->m_last_xid == grandchild_txn->txnid.child_id64);
207 
208 
209     TXNID_PAIR xid = {.parent_id64 = root_txn->txnid.parent_id64, .child_id64 = 100};
210     TOKUTXN recovery_txn = NULL;
211     r = toku_txn_begin_with_xid(
212         grandchild_txn,
213         &recovery_txn,
214         logger,
215         xid,
216         TXN_SNAPSHOT_NONE,
217         NULL,
218         true, // for recovery
219         false // read_only
220         );
221 
222     assert(recovery_txn->child_manager == cm);
223     assert(recovery_txn->parent == grandchild_txn);
224     assert(grandchild_txn->child == recovery_txn);
225     assert(recovery_txn->txnid.parent_id64 == root_txn->txnid.parent_id64);
226     assert(recovery_txn->txnid.child_id64 == 100);
227     // ensure that no snapshot is made
228     assert(recovery_txn->live_root_txn_list == NULL);
229     assert(recovery_txn->snapshot_txnid64 == TXNID_NONE);
230 
231     assert(cm->m_root == root_txn);
232     assert(cm->m_last_xid == recovery_txn->txnid.child_id64);
233 
234 
235     // now ensure that txn_child_manager::find_tokutxn_by_xid_unlocked works
236     TOKUTXN found_txn = NULL;
237     // first ensure that a dummy TXNID_PAIR cannot be found
238     TXNID_PAIR dummy_pair = { .parent_id64 = root_txn->txnid.parent_id64, .child_id64 = 1000};
239     cm->find_tokutxn_by_xid_unlocked(dummy_pair, &found_txn);
240     assert(found_txn == NULL);
241     cm->find_tokutxn_by_xid_unlocked(root_txn->txnid, &found_txn);
242     assert(found_txn == root_txn);
243     cm->find_tokutxn_by_xid_unlocked(child_txn->txnid, &found_txn);
244     assert(found_txn == child_txn);
245     cm->find_tokutxn_by_xid_unlocked(grandchild_txn->txnid, &found_txn);
246     assert(found_txn == grandchild_txn);
247     cm->find_tokutxn_by_xid_unlocked(recovery_txn->txnid, &found_txn);
248     assert(found_txn == recovery_txn);
249 
250 
251     // now ensure that the iterator works
252     found_txn = root_txn;
253     r = cm->iterate(txn_child_manager_test_cb, &found_txn);
254     CKERR(r);
255     assert(found_txn == NULL);
256 
257     // now test that iterator properly stops
258     found_txn = child_txn;
259     r = cm->iterate(txn_child_manager_test_cb2, found_txn);
260     assert(r == -1);
261 
262     r = toku_txn_commit_txn(recovery_txn, true, NULL, NULL);
263     CKERR(r);
264     toku_txn_close_txn(recovery_txn);
265     assert(grandchild_txn->child == NULL);
266 
267     r = toku_txn_commit_txn(grandchild_txn, true, NULL, NULL);
268     CKERR(r);
269     toku_txn_close_txn(grandchild_txn);
270     assert(child_txn->child == NULL);
271 
272     r = toku_txn_commit_txn(child_txn, true, NULL, NULL);
273     CKERR(r);
274     toku_txn_close_txn(child_txn);
275     assert(root_txn->child == NULL);
276 
277     r = toku_txn_commit_txn(root_txn, true, NULL, NULL);
278     CKERR(r);
279     toku_txn_close_txn(root_txn);
280 
281 
282     clean_shutdown(&logger, &ct);
283 }
284 
test_main(int argc,const char * argv[])285 int test_main (int argc, const char *argv[]) {
286     default_parse_args(argc, argv);
287     txn_child_manager_unit_test foo;
288     foo.run_test();
289     return 0;
290 }
291