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