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 /* The goal of this test. Make sure that inserts stay behind deletes. */
40
41
42 #include "test.h"
43
44 #include <ft-cachetable-wrappers.h>
45 #include "ft-flusher.h"
46 #include "cachetable/checkpoint.h"
47
48 static TOKUTXN const null_txn = 0;
49
50 enum { NODESIZE = 1024, KSIZE=NODESIZE-100, TOKU_PSIZE=20 };
51
52 CACHETABLE ct;
53 FT_HANDLE ft;
54 const char *fname = TOKU_TEST_FILENAME;
55
update_func(DB * UU (db),const DBT * key,const DBT * old_val,const DBT * UU (extra),void (* set_val)(const DBT * new_val,void * set_extra),void * set_extra)56 static int update_func(
57 DB* UU(db),
58 const DBT* key,
59 const DBT* old_val,
60 const DBT* UU(extra),
61 void (*set_val)(const DBT *new_val, void *set_extra),
62 void *set_extra)
63 {
64 DBT new_val;
65 assert(old_val->size > 0);
66 if (verbose) {
67 printf("applying update to %s\n", (char *)key->data);
68 }
69 toku_init_dbt(&new_val);
70 set_val(&new_val, set_extra);
71 return 0;
72 }
73
74
75 static void
doit(void)76 doit (void) {
77 BLOCKNUM node_leaf[2];
78 BLOCKNUM node_internal, node_root;
79
80 int r;
81
82 toku_cachetable_create(&ct, 500*1024*1024, ZERO_LSN, nullptr);
83 unlink(fname);
84 r = toku_open_ft_handle(fname, 1, &ft, NODESIZE, NODESIZE/2, TOKU_DEFAULT_COMPRESSION_METHOD, ct, null_txn, toku_builtin_compare_fun);
85 assert(r==0);
86
87 ft->options.update_fun = update_func;
88 ft->ft->update_fun = update_func;
89
90 toku_testsetup_initialize(); // must precede any other toku_testsetup calls
91
92 r = toku_testsetup_leaf(ft, &node_leaf[0], 1, NULL, NULL);
93 assert(r==0);
94 r = toku_testsetup_leaf(ft, &node_leaf[1], 1, NULL, NULL);
95 assert(r==0);
96
97 char* pivots[1];
98 pivots[0] = toku_strdup("kkkkk");
99 int pivot_len = 6;
100
101 r = toku_testsetup_nonleaf(ft, 1, &node_internal, 2, node_leaf, pivots, &pivot_len);
102 assert(r==0);
103
104 r = toku_testsetup_nonleaf(ft, 2, &node_root, 1, &node_internal, 0, 0);
105 assert(r==0);
106
107 r = toku_testsetup_root(ft, node_root);
108 assert(r==0);
109
110 //
111 // at this point we have created a tree with a root, an internal node,
112 // and two leaf nodes, the pivot being "kkkkk"
113 //
114
115 // now we insert a row into each leaf node
116 r = toku_testsetup_insert_to_leaf (
117 ft,
118 node_leaf[0],
119 "a", // key
120 2, // keylen
121 "aa",
122 3
123 );
124 assert(r==0);
125 r = toku_testsetup_insert_to_leaf (
126 ft,
127 node_leaf[1],
128 "z", // key
129 2, // keylen
130 "zz",
131 3
132 );
133 assert(r==0);
134
135 //
136 // now insert a bunch of dummy delete messages
137 // into the internal node, to get its cachepressure size up
138 //
139 for (int i = 0; i < 100000; i++) {
140 r = toku_testsetup_insert_to_nonleaf (
141 ft,
142 node_internal,
143 FT_DELETE_ANY,
144 "jj", // this key does not exist, so its message application should be a no-op
145 3,
146 NULL,
147 0
148 );
149 assert(r==0);
150 }
151
152 //
153 // now insert a broadcast message into the root
154 //
155 r = toku_testsetup_insert_to_nonleaf (
156 ft,
157 node_root,
158 FT_UPDATE_BROADCAST_ALL,
159 NULL,
160 0,
161 NULL,
162 0
163 );
164 assert(r==0);
165
166 //
167 // now let us induce a clean on the internal node
168 //
169 FTNODE node;
170 toku_pin_node_with_min_bfe(&node, node_leaf[1], ft);
171 // hack to get merge going
172 BLB_SEQINSERT(node, node->n_children-1) = false;
173 toku_unpin_ftnode(ft->ft, node);
174
175 // now do a lookup on one of the keys, this should bring a leaf node up to date
176 DBT k;
177 struct check_pair pair = {2, "a", 0, NULL, 0};
178 r = toku_ft_lookup(ft, toku_fill_dbt(&k, "a", 2), lookup_checkf, &pair);
179 assert(r==0);
180
181 ftnode_fetch_extra bfe;
182 bfe.create_for_min_read(ft->ft);
183 toku_pin_ftnode(
184 ft->ft,
185 node_internal,
186 toku_cachetable_hash(ft->ft->cf, node_internal),
187 &bfe,
188 PL_WRITE_EXPENSIVE,
189 &node,
190 true
191 );
192 assert(node->n_children == 2);
193 // we expect that this flushes its buffer, that
194 // a merge is not done, and that the lookup
195 // of values "a" and "z" still works
196 r = toku_ftnode_cleaner_callback(
197 node,
198 node_internal,
199 toku_cachetable_hash(ft->ft->cf, node_internal),
200 ft->ft
201 );
202
203 // verify that node_internal's buffer is empty
204 bfe.create_for_min_read(ft->ft);
205 toku_pin_ftnode(
206 ft->ft,
207 node_internal,
208 toku_cachetable_hash(ft->ft->cf, node_internal),
209 &bfe,
210 PL_WRITE_EXPENSIVE,
211 &node,
212 true
213 );
214 // check that merge happened
215 assert(node->n_children == 1);
216 // check that buffers are empty
217 assert(toku_bnc_nbytesinbuf(BNC(node, 0)) == 0);
218 toku_unpin_ftnode(ft->ft, node);
219
220 //
221 // now run a checkpoint to get everything clean,
222 // and to get the rebalancing to happen
223 //
224 CHECKPOINTER cp = toku_cachetable_get_checkpointer(ct);
225 r = toku_checkpoint(cp, NULL, NULL, NULL, NULL, NULL, CLIENT_CHECKPOINT);
226 assert_zero(r);
227
228 // check that lookups on the two keys is still good
229 struct check_pair pair1 = {2, "a", 0, NULL, 0};
230 r = toku_ft_lookup(ft, toku_fill_dbt(&k, "a", 2), lookup_checkf, &pair1);
231 assert(r==0);
232 struct check_pair pair2 = {2, "z", 0, NULL, 0};
233 r = toku_ft_lookup(ft, toku_fill_dbt(&k, "z", 2), lookup_checkf, &pair2);
234 assert(r==0);
235
236
237 r = toku_close_ft_handle_nolsn(ft, 0); assert(r==0);
238 toku_cachetable_close(&ct);
239
240 toku_free(pivots[0]);
241 }
242
243 int
test_main(int argc,const char * argv[])244 test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) {
245 default_parse_args(argc, argv);
246 doit();
247 return 0;
248 }
249