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 #include "cachetable/cachetable-internal.h"
41 #include "cachetable-test.h"
42
43 //
44 // Wrapper for the checkpointer and necessary
45 // data to run the tests.
46 //
47 struct checkpointer_test {
48 checkpointer m_cp;
49 pair_list m_pl;
50
51 // Tests
52 void test_begin_checkpoint();
53 void test_pending_bits();
54 void test_end_checkpoint();
55
56 // Test Helper
57 void add_pairs(struct cachefile *cf,
58 ctpair pairs[],
59 uint32_t count,
60 uint32_t k);
61 };
62
init_cachefile(CACHEFILE cf,int which_cf,bool for_checkpoint)63 static void init_cachefile(CACHEFILE cf, int which_cf, bool for_checkpoint) {
64 memset(cf, 0, sizeof(*cf));
65 create_dummy_functions(cf);
66 cf->fileid = { 0, (unsigned) which_cf };
67 cf->filenum = { (unsigned) which_cf };
68 cf->for_checkpoint = for_checkpoint;
69 }
70
71 //------------------------------------------------------------------------------
72 // test_begin_checkpoint() -
73 //
74 // Description:
75 //
test_begin_checkpoint()76 void checkpointer_test::test_begin_checkpoint() {
77 cachefile_list cfl;
78 ZERO_STRUCT(cfl);
79 cfl.init();
80
81 cachetable ctbl;
82 ZERO_STRUCT(ctbl);
83 ctbl.list.init();
84
85 ZERO_STRUCT(m_cp);
86 m_cp.init(&ctbl.list, NULL, &ctbl.ev, &cfl);
87
88 // 1. Call checkpoint with NO cachefiles.
89 m_cp.begin_checkpoint();
90
91 // 2. Call checkpoint with ONE cachefile.
92 //cachefile cf;
93 struct cachefile cf;
94 init_cachefile(&cf, 0, false);
95 m_cp.m_cf_list->add_cf_unlocked(&cf);
96
97 m_cp.begin_checkpoint();
98 assert(m_cp.m_checkpoint_num_files == 1);
99 assert(cf.for_checkpoint == true);
100 m_cp.m_cf_list->remove_cf(&cf);
101
102 // 3. Call checkpoint with MANY cachefiles.
103 const uint32_t count = 3;
104 struct cachefile cfs[count];
105 for (uint32_t i = 0; i < count; ++i) {
106 init_cachefile(&cfs[i], i, false);
107 create_dummy_functions(&cfs[i]);
108 m_cp.m_cf_list->add_cf_unlocked(&cfs[i]);
109 }
110
111 m_cp.begin_checkpoint();
112 assert(m_cp.m_checkpoint_num_files == count);
113 for (uint32_t i = 0; i < count; ++i) {
114 assert(cfs[i].for_checkpoint == true);
115 cfl.remove_cf(&cfs[i]);
116 }
117 ctbl.list.destroy();
118 m_cp.destroy();
119 cfl.destroy();
120 }
121
122 //------------------------------------------------------------------------------
123 // test_pending_bits() -
124 //
125 // Description:
126 //
test_pending_bits()127 void checkpointer_test::test_pending_bits() {
128 cachefile_list cfl;
129 ZERO_STRUCT(cfl);
130 cfl.init();
131
132 cachetable ctbl;
133 ZERO_STRUCT(ctbl);
134 ctbl.list.init();
135
136 ZERO_STRUCT(m_cp);
137 m_cp.init(&ctbl.list, NULL, &ctbl.ev, &cfl);
138
139 //
140 // 1. Empty hash chain.
141 //
142 m_cp.turn_on_pending_bits();
143
144 //
145 // 2. One entry in pair chain
146 //
147 struct cachefile cf;
148 cf.cachetable = &ctbl;
149 init_cachefile(&cf, 0, true);
150 m_cp.m_cf_list->add_cf_unlocked(&cf);
151 create_dummy_functions(&cf);
152
153 CACHEKEY k;
154 k.b = 0;
155 uint32_t hash = toku_cachetable_hash(&cf, k);
156
157 ctpair p;
158 CACHETABLE_WRITE_CALLBACK cb;
159
160 pair_attr_s attr;
161 attr.size = 0;
162 attr.nonleaf_size = 0;
163 attr.leaf_size = 0;
164 attr.rollback_size = 0;
165 attr.cache_pressure_size = 0;
166 attr.is_valid = true;
167
168 ZERO_STRUCT(p);
169 pair_init(&p,
170 &cf,
171 k,
172 NULL,
173 attr,
174 CACHETABLE_CLEAN,
175 hash,
176 cb,
177 NULL,
178 &ctbl.list);
179
180 m_cp.m_list->put(&p);
181
182 m_cp.turn_on_pending_bits();
183 assert(p.checkpoint_pending);
184 m_cp.m_list->evict_completely(&p);
185
186 //
187 // 3. Many hash chain entries.
188 //
189 const uint32_t count = 3;
190 ctpair pairs[count];
191 ZERO_ARRAY(pairs);
192 add_pairs(&cf, pairs, count, 0);
193
194 m_cp.turn_on_pending_bits();
195
196 for (uint32_t i = 0; i < count; ++i) {
197 assert(pairs[i].checkpoint_pending);
198 }
199 for (uint32_t i = 0; i < count; ++i) {
200 CACHEKEY key;
201 key.b = i;
202 uint32_t full_hash = toku_cachetable_hash(&cf, key);
203 PAIR pp = m_cp.m_list->find_pair(&cf, key, full_hash);
204 assert(pp);
205 m_cp.m_list->evict_completely(pp);
206 }
207
208 ctbl.list.destroy();
209 m_cp.destroy();
210 cfl.remove_cf(&cf);
211 cfl.destroy();
212 }
213
214 //------------------------------------------------------------------------------
215 // add_pairs() -
216 //
217 // Description: Adds data (pairs) to the list referenced in the checkpoitner.
218 //
add_pairs(struct cachefile * cf,ctpair pairs[],uint32_t count,uint32_t k)219 void checkpointer_test::add_pairs(struct cachefile *cf,
220 ctpair pairs[],
221 uint32_t count,
222 uint32_t k)
223 {
224 pair_attr_s attr;
225 attr.size = 0;
226 attr.nonleaf_size = 0;
227 attr.leaf_size = 0;
228 attr.rollback_size = 0;
229 attr.cache_pressure_size = 0;
230 attr.is_valid = true;
231 CACHETABLE_WRITE_CALLBACK cb;
232 ZERO_STRUCT(cb); // All nullptr
233
234 for (uint32_t i = k; i < count + k; ++i) {
235 CACHEKEY key;
236 key.b = i;
237 uint32_t full_hash = toku_cachetable_hash(cf, key);
238 pair_init(&(pairs[i]),
239 cf,
240 key,
241 nullptr,
242 attr,
243 CACHETABLE_CLEAN,
244 full_hash,
245 cb,
246 nullptr,
247 m_cp.m_list);
248
249 m_cp.m_list->put(&pairs[i]);
250 }
251 }
252
253 //------------------------------------------------------------------------------
254 // get_number_pending_pairs() -
255 //
256 // Description: Helper function that iterates over pending list, and returns
257 // the number of pairs discovered.
258 //
get_number_pending_pairs(pair_list * list)259 static uint32_t get_number_pending_pairs(pair_list *list)
260 {
261 PAIR p;
262 uint32_t count = 0;
263 PAIR head = list->m_pending_head;
264 while((p = list->m_pending_head) != 0)
265 {
266 list->m_pending_head = list->m_pending_head->pending_next;
267 count++;
268 }
269
270 list->m_pending_head = head;
271 return count;
272 }
273
274 //------------------------------------------------------------------------------
275 // test_end_checkpoint() -
276 //
277 // Description: Adds pairs to the list, before and after a checkpoint.
278 //
test_end_checkpoint()279 void checkpointer_test::test_end_checkpoint() {
280 // 1. Init test.
281 cachetable ctbl;
282 ZERO_STRUCT(ctbl);
283 ctbl.list.init();
284
285 cachefile_list cfl;
286 ZERO_STRUCT(cfl);
287 cfl.init();
288
289 struct cachefile cf;
290 init_cachefile(&cf, 0, true);
291
292 ZERO_STRUCT(m_cp);
293 m_cp.init(&ctbl.list, NULL, &ctbl.ev, &cfl);
294 m_cp.m_cf_list->add_cf_unlocked(&cf);
295
296 // 2. Add data before running checkpoint.
297 const uint32_t count = 6;
298 ctpair pairs[count];
299 ZERO_ARRAY(pairs);
300 add_pairs(&cf, pairs, count / 2, 0);
301 assert(m_cp.m_list->m_n_in_table == count / 2);
302
303 // 3. Call begin checkpoint.
304 m_cp.begin_checkpoint();
305 assert(m_cp.m_checkpoint_num_files == 1);
306 for (uint32_t i = 0; i < count / 2; ++i)
307 {
308 assert(pairs[i].checkpoint_pending);
309 }
310
311 // 4. Add new data between starting and stopping checkpoint.
312 add_pairs(&cf, pairs, count / 2, count / 2);
313 assert(m_cp.m_list->m_n_in_table == count);
314 for (uint32_t i = count / 2; i < count / 2; ++i)
315 {
316 assert(!pairs[i].checkpoint_pending);
317 }
318
319 uint32_t pending_pairs = 0;
320 pending_pairs = get_number_pending_pairs(m_cp.m_list);
321 assert(pending_pairs == count / 2);
322
323 // 5. Call end checkpoint
324 m_cp.end_checkpoint(NULL, NULL);
325
326 pending_pairs = get_number_pending_pairs(m_cp.m_list);
327 assert(pending_pairs == 0);
328
329 // Verify that none of the pairs are pending a checkpoint.
330 for (uint32_t i = 0; i < count; ++i)
331 {
332 assert(!pairs[i].checkpoint_pending);
333 }
334
335 // 6. Cleanup
336 for (uint32_t i = 0; i < count; ++i) {
337 CACHEKEY key;
338 key.b = i;
339 uint32_t full_hash = toku_cachetable_hash(&cf, key);
340 PAIR pp = m_cp.m_list->find_pair(&cf, key, full_hash);
341 assert(pp);
342 m_cp.m_list->evict_completely(pp);
343 }
344 cfl.remove_cf(&cf);
345 m_cp.destroy();
346 ctbl.list.destroy();
347 cfl.destroy();
348 }
349
350
351 //------------------------------------------------------------------------------
352 // test_main() -
353 //
354 // Description:
355 //
356 int
test_main(int argc,const char * argv[])357 test_main(int argc, const char *argv[]) {
358 int r = 0;
359 default_parse_args(argc, argv);
360 checkpointer_test cp_test;
361
362 // Run the tests.
363 cp_test.test_begin_checkpoint();
364 cp_test.test_pending_bits();
365 cp_test.test_end_checkpoint();
366
367 return r;
368 }
369