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 "ft-cachetable-wrappers.h"
42 #include "ft-flusher.h"
43 #include "ft-flusher-internal.h"
44 
45 static bool
dont_destroy_bn(void * UU (extra))46 dont_destroy_bn(void* UU(extra)) {
47     return false;
48 }
49 
merge_should_not_happen(struct flusher_advice * UU (fa),FT UU (h),FTNODE UU (parent),int UU (childnum),FTNODE UU (child),void * UU (extra))50 static void merge_should_not_happen(struct flusher_advice* UU(fa),
51                               FT UU(h),
52                               FTNODE UU(parent),
53                               int UU(childnum),
54                               FTNODE UU(child),
55                               void* UU(extra))
56 {
57     assert(false);
58 }
59 
dont_recursively_flush(FTNODE UU (child),void * UU (extra))60 static bool dont_recursively_flush(FTNODE UU(child), void* UU(extra)) {
61     return false;
62 }
63 
child_to_flush(FT UU (h),FTNODE parent,void * UU (extra))64 static int child_to_flush(FT UU(h), FTNODE parent, void* UU(extra)) {
65     assert(parent->height == 2);
66     assert(parent->n_children == 1);
67     return 0;
68 }
69 
dummy_update_status(FTNODE UU (child),int UU (dirtied),void * UU (extra))70 static void dummy_update_status(FTNODE UU(child), int UU(dirtied), void* UU(extra)) {
71 }
72 
73 enum { NODESIZE = 1024, KSIZE=NODESIZE-100, TOKU_PSIZE=20 };
74 
test_oldest_referenced_xid_gets_propagated(void)75 static void test_oldest_referenced_xid_gets_propagated(void) {
76     int r;
77     CACHETABLE ct;
78     FT_HANDLE t;
79     BLOCKNUM grandchild_leaf_blocknum, child_nonleaf_blocknum, root_blocknum;
80 
81     toku_cachetable_create(&ct, 500*1024*1024, ZERO_LSN, nullptr);
82     unlink("foo1.ft_handle");
83     r = toku_open_ft_handle("foo1.ft_handle", 1, &t, NODESIZE, NODESIZE/2, TOKU_DEFAULT_COMPRESSION_METHOD, ct, nullptr, toku_builtin_compare_fun);
84     assert(r==0);
85 
86     toku_testsetup_initialize();  // must precede any other toku_testsetup calls
87 
88     // This test flushes from a nonleaf root to a nonleaf child, without any leaf nodes.
89 
90     r = toku_testsetup_leaf(t, &grandchild_leaf_blocknum, 1, NULL, NULL);
91     assert(r==0);
92 
93     r = toku_testsetup_nonleaf(t, 1, &child_nonleaf_blocknum, 1, &grandchild_leaf_blocknum, NULL, NULL);
94     assert(r==0);
95 
96     r = toku_testsetup_nonleaf(t, 2, &root_blocknum, 1, &child_nonleaf_blocknum, NULL, NULL);
97     assert(r==0);
98 
99     r = toku_testsetup_root(t, root_blocknum);
100     assert(r==0);
101 
102     r = toku_testsetup_insert_to_nonleaf(
103         t,
104         root_blocknum,
105         FT_INSERT,
106         "a",
107         2,
108         NULL,
109         0
110         );
111 
112     // Verify that both the root and its child start with TXNID_NONE
113     // for the oldest referenced xid
114 
115     // first verify the child
116     FTNODE node = NULL;
117     ftnode_fetch_extra bfe;
118     bfe.create_for_min_read(t->ft);
119     toku_pin_ftnode(
120         t->ft,
121         child_nonleaf_blocknum,
122         toku_cachetable_hash(t->ft->cf, child_nonleaf_blocknum),
123         &bfe,
124         PL_WRITE_EXPENSIVE,
125         &node,
126         true
127         );
128     assert(node->height == 1);
129     assert(node->n_children == 1);
130     assert(BP_BLOCKNUM(node, 0).b == grandchild_leaf_blocknum.b);
131     assert(node->oldest_referenced_xid_known == TXNID_NONE);
132     toku_unpin_ftnode(t->ft, node);
133 
134     // now verify the root - keep it pinned so we can flush it below
135     toku_pin_ftnode(
136         t->ft,
137         root_blocknum,
138         toku_cachetable_hash(t->ft->cf, root_blocknum),
139         &bfe,
140         PL_WRITE_EXPENSIVE,
141         &node,
142         true
143         );
144     assert(node->height == 2);
145     assert(node->n_children == 1);
146     assert(BP_BLOCKNUM(node, 0).b == child_nonleaf_blocknum.b);
147     assert(toku_bnc_nbytesinbuf(BNC(node, 0)) > 0);
148     assert(node->oldest_referenced_xid_known == TXNID_NONE);
149 
150     // set the root's oldest referenced xid to something special
151     const TXNID flush_xid = 25000;
152     node->oldest_referenced_xid_known = flush_xid;
153 
154     // do the flush
155     struct flusher_advice fa;
156     flusher_advice_init(
157         &fa,
158         child_to_flush,
159         dont_destroy_bn,
160         dont_recursively_flush,
161         merge_should_not_happen,
162         dummy_update_status,
163         default_pick_child_after_split,
164         NULL
165         );
166     toku_ft_flush_some_child(t->ft, node, &fa);
167 
168     // pin the child, verify that oldest referenced xid was
169     // propagated from parent to child during the flush
170     toku_pin_ftnode(
171         t->ft,
172         child_nonleaf_blocknum,
173         toku_cachetable_hash(t->ft->cf, child_nonleaf_blocknum),
174         &bfe,
175         PL_WRITE_EXPENSIVE,
176         &node,
177         true
178         );
179     assert(node->oldest_referenced_xid_known == flush_xid);
180 
181     toku_unpin_ftnode(t->ft, node);
182     r = toku_close_ft_handle_nolsn(t, 0);    assert(r==0);
183     toku_cachetable_close(&ct);
184 }
185 
test_main(int argc,const char * argv[])186 int test_main(int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) {
187     default_parse_args(argc, argv);
188     test_oldest_referenced_xid_gets_propagated();
189     return 0;
190 }
191