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