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 "bndata.h"
41 
42 #ifndef MIN
43 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
44 #endif
45 
le_add_to_bn(bn_data * bn,uint32_t idx,const char * key,int keysize,const char * val,int valsize)46 static size_t le_add_to_bn(bn_data *bn,
47                            uint32_t idx,
48                            const char *key,
49                            int keysize,
50                            const char *val,
51                            int valsize) {
52     LEAFENTRY r = NULL;
53     uint32_t size_needed = LE_CLEAN_MEMSIZE(valsize);
54     void *maybe_free = nullptr;
55     bn->get_space_for_insert(idx, key, keysize, size_needed, &r, &maybe_free);
56     if (maybe_free) {
57         toku_free(maybe_free);
58     }
59     resource_assert(r);
60     r->type = LE_CLEAN;
61     r->u.clean.vallen = valsize;
62     memcpy(r->u.clean.val, val, valsize);
63     return size_needed + keysize + sizeof(uint32_t);
64 }
65 
66 class test_key_le_pair {
67    public:
68     uint32_t keylen;
69     char *keyp;
70     LEAFENTRY le;
71 
test_key_le_pair()72     test_key_le_pair() : keylen(), keyp(), le() {}
init(const char * _keyp,const char * _val)73     void init(const char *_keyp, const char *_val) {
74         init(_keyp, strlen(_keyp) + 1, _val, strlen(_val) + 1);
75     }
init(const char * _keyp,uint32_t _keylen,const char * _val,uint32_t _vallen)76     void init(const char *_keyp,
77               uint32_t _keylen,
78               const char *_val,
79               uint32_t _vallen) {
80         keylen = _keylen;
81 
82         CAST_FROM_VOIDP(le, toku_malloc(LE_CLEAN_MEMSIZE(_vallen)));
83         le->type = LE_CLEAN;
84         le->u.clean.vallen = _vallen;
85         memcpy(le->u.clean.val, _val, _vallen);
86 
87         CAST_FROM_VOIDP(keyp, toku_xmemdup(_keyp, keylen));
88     }
~test_key_le_pair()89     ~test_key_le_pair() {
90         toku_free(le);
91         toku_free(keyp);
92     }
93 };
94 
95 enum ftnode_verify_type { read_all = 1, read_compressed, read_none };
96 
string_key_cmp(DB * UU (e),const DBT * a,const DBT * b)97 static int string_key_cmp(DB *UU(e), const DBT *a, const DBT *b) {
98     char *CAST_FROM_VOIDP(s, a->data);
99     char *CAST_FROM_VOIDP(t, b->data);
100     return strcmp(s, t);
101 }
102 
setup_dn(enum ftnode_verify_type bft,int fd,FT ft_h,FTNODE * dn,FTNODE_DISK_DATA * ndd)103 static void setup_dn(enum ftnode_verify_type bft,
104                      int fd,
105                      FT ft_h,
106                      FTNODE *dn,
107                      FTNODE_DISK_DATA *ndd) {
108     int r;
109     if (bft == read_all) {
110         ftnode_fetch_extra bfe;
111         bfe.create_for_full_read(ft_h);
112         r = toku_deserialize_ftnode_from(
113             fd, make_blocknum(20), 0 /*pass zero for hash*/, dn, ndd, &bfe);
114         invariant(r == 0);
115     } else if (bft == read_compressed || bft == read_none) {
116         ftnode_fetch_extra bfe;
117         bfe.create_for_min_read(ft_h);
118         r = toku_deserialize_ftnode_from(
119             fd, make_blocknum(20), 0 /*pass zero for hash*/, dn, ndd, &bfe);
120         invariant(r == 0);
121         // invariant all bp's are compressed or on disk.
122         for (int i = 0; i < (*dn)->n_children; i++) {
123             invariant(BP_STATE(*dn, i) == PT_COMPRESSED ||
124                    BP_STATE(*dn, i) == PT_ON_DISK);
125         }
126         // if read_none, get rid of the compressed bp's
127         if (bft == read_none) {
128             if ((*dn)->height == 0) {
129                 toku_ftnode_pe_callback(*dn,
130                                         make_pair_attr(0xffffffff),
131                                         ft_h,
132                                         def_pe_finalize_impl,
133                                         nullptr);
134                 // invariant all bp's are on disk
135                 for (int i = 0; i < (*dn)->n_children; i++) {
136                     if ((*dn)->height == 0) {
137                         invariant(BP_STATE(*dn, i) == PT_ON_DISK);
138                         invariant(is_BNULL(*dn, i));
139                     } else {
140                         invariant(BP_STATE(*dn, i) == PT_COMPRESSED);
141                     }
142                 }
143             } else {
144                 // first decompress everything, and make sure
145                 // that it is available
146                 // then run partial eviction to get it compressed
147                 PAIR_ATTR attr;
148                 bfe.create_for_full_read(ft_h);
149                 invariant(toku_ftnode_pf_req_callback(*dn, &bfe));
150                 r = toku_ftnode_pf_callback(*dn, *ndd, &bfe, fd, &attr);
151                 invariant(r == 0);
152                 // invariant all bp's are available
153                 for (int i = 0; i < (*dn)->n_children; i++) {
154                     invariant(BP_STATE(*dn, i) == PT_AVAIL);
155                 }
156                 toku_ftnode_pe_callback(*dn,
157                                         make_pair_attr(0xffffffff),
158                                         ft_h,
159                                         def_pe_finalize_impl,
160                                         nullptr);
161                 for (int i = 0; i < (*dn)->n_children; i++) {
162                     // invariant all bp's are still available, because we touched
163                     // the clock
164                     invariant(BP_STATE(*dn, i) == PT_AVAIL);
165                     // now invariant all should be evicted
166                     invariant(BP_SHOULD_EVICT(*dn, i));
167                 }
168                 toku_ftnode_pe_callback(*dn,
169                                         make_pair_attr(0xffffffff),
170                                         ft_h,
171                                         def_pe_finalize_impl,
172                                         nullptr);
173                 for (int i = 0; i < (*dn)->n_children; i++) {
174                     invariant(BP_STATE(*dn, i) == PT_COMPRESSED);
175                 }
176             }
177         }
178         // now decompress them
179         bfe.create_for_full_read(ft_h);
180         invariant(toku_ftnode_pf_req_callback(*dn, &bfe));
181         PAIR_ATTR attr;
182         r = toku_ftnode_pf_callback(*dn, *ndd, &bfe, fd, &attr);
183         invariant(r == 0);
184         // invariant all bp's are available
185         for (int i = 0; i < (*dn)->n_children; i++) {
186             invariant(BP_STATE(*dn, i) == PT_AVAIL);
187         }
188         // continue on with test
189     } else {
190         // if we get here, this is a test bug, NOT a bug in development code
191         invariant(false);
192     }
193 }
194 
write_sn_to_disk(int fd,FT_HANDLE ft,FTNODE sn,FTNODE_DISK_DATA * src_ndd,bool do_clone)195 static void write_sn_to_disk(int fd,
196                              FT_HANDLE ft,
197                              FTNODE sn,
198                              FTNODE_DISK_DATA *src_ndd,
199                              bool do_clone) {
200     int r;
201     if (do_clone) {
202         void *cloned_node_v = NULL;
203         PAIR_ATTR attr;
204         long clone_size;
205         toku_ftnode_clone_callback(
206             sn, &cloned_node_v, &clone_size, &attr, false, ft->ft);
207         FTNODE CAST_FROM_VOIDP(cloned_node, cloned_node_v);
208         r = toku_serialize_ftnode_to(
209             fd, make_blocknum(20), cloned_node, src_ndd, false, ft->ft, false);
210         invariant(r == 0);
211         toku_ftnode_free(&cloned_node);
212     } else {
213         r = toku_serialize_ftnode_to(
214             fd, make_blocknum(20), sn, src_ndd, true, ft->ft, false);
215         invariant(r == 0);
216     }
217 }
218 
test_serialize_leaf_check_msn(enum ftnode_verify_type bft,bool do_clone)219 static void test_serialize_leaf_check_msn(enum ftnode_verify_type bft,
220                                           bool do_clone) {
221     //    struct ft_handle source_ft;
222     struct ftnode sn, *dn;
223 
224     int fd = open(TOKU_TEST_FILENAME,
225                   O_RDWR | O_CREAT | O_BINARY,
226                   S_IRWXU | S_IRWXG | S_IRWXO);
227     invariant(fd >= 0);
228 
229     int r;
230 
231 #define PRESERIALIZE_MSN_ON_DISK ((MSN){MIN_MSN.msn + 42})
232 #define POSTSERIALIZE_MSN_ON_DISK ((MSN){MIN_MSN.msn + 84})
233 
234     sn.max_msn_applied_to_node_on_disk = PRESERIALIZE_MSN_ON_DISK;
235     sn.flags = 0x11223344;
236     sn.blocknum.b = 20;
237     sn.layout_version = FT_LAYOUT_VERSION;
238     sn.layout_version_original = FT_LAYOUT_VERSION;
239     sn.height = 0;
240     sn.n_children = 2;
241     sn.set_dirty();
242     sn.oldest_referenced_xid_known = TXNID_NONE;
243     MALLOC_N(sn.n_children, sn.bp);
244     DBT pivotkey;
245     sn.pivotkeys.create_from_dbts(toku_fill_dbt(&pivotkey, "b", 2), 1);
246     BP_STATE(&sn, 0) = PT_AVAIL;
247     BP_STATE(&sn, 1) = PT_AVAIL;
248     set_BLB(&sn, 0, toku_create_empty_bn());
249     set_BLB(&sn, 1, toku_create_empty_bn());
250     le_add_to_bn(BLB_DATA(&sn, 0), 0, "a", 2, "aval", 5);
251     le_add_to_bn(BLB_DATA(&sn, 0), 1, "b", 2, "bval", 5);
252     le_add_to_bn(BLB_DATA(&sn, 1), 0, "x", 2, "xval", 5);
253     BLB_MAX_MSN_APPLIED(&sn, 0) = ((MSN){MIN_MSN.msn + 73});
254     BLB_MAX_MSN_APPLIED(&sn, 1) = POSTSERIALIZE_MSN_ON_DISK;
255 
256     FT_HANDLE XMALLOC(ft);
257     FT XCALLOC(ft_h);
258     toku_ft_init(ft_h,
259                  make_blocknum(0),
260                  ZERO_LSN,
261                  TXNID_NONE,
262                  4 * 1024 * 1024,
263                  128 * 1024,
264                  TOKU_DEFAULT_COMPRESSION_METHOD,
265                  16);
266     ft->ft = ft_h;
267     ft_h->blocktable.create();
268     {
269         int r_truncate = ftruncate(fd, 0);
270         CKERR(r_truncate);
271     }
272 
273     // Want to use block #20
274     BLOCKNUM b = make_blocknum(0);
275     while (b.b < 20) {
276         ft_h->blocktable.allocate_blocknum(&b, ft_h);
277     }
278     invariant(b.b == 20);
279 
280     {
281         DISKOFF offset;
282         DISKOFF size;
283         ft_h->blocktable.realloc_on_disk(b, 100, &offset, ft_h, fd, false);
284         invariant(offset ==
285                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
286 
287         ft_h->blocktable.translate_blocknum_to_offset_size(b, &offset, &size);
288         invariant(offset ==
289                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
290         invariant(size == 100);
291     }
292     FTNODE_DISK_DATA src_ndd = NULL;
293     FTNODE_DISK_DATA dest_ndd = NULL;
294 
295     write_sn_to_disk(fd, ft, &sn, &src_ndd, do_clone);
296 
297     setup_dn(bft, fd, ft_h, &dn, &dest_ndd);
298 
299     invariant(dn->blocknum.b == 20);
300 
301     invariant(dn->layout_version == FT_LAYOUT_VERSION);
302     invariant(dn->layout_version_original == FT_LAYOUT_VERSION);
303     invariant(dn->layout_version_read_from_disk == FT_LAYOUT_VERSION);
304     invariant(dn->height == 0);
305     invariant(dn->n_children >= 1);
306     invariant(dn->max_msn_applied_to_node_on_disk.msn ==
307            POSTSERIALIZE_MSN_ON_DISK.msn);
308     {
309         // Man, this is way too ugly.  This entire test suite needs to be
310         // refactored.
311         // Create a dummy mempool and put the leaves there.  Ugh.
312         test_key_le_pair elts[3];
313         elts[0].init("a", "aval");
314         elts[1].init("b", "bval");
315         elts[2].init("x", "xval");
316         const uint32_t npartitions = dn->n_children;
317         uint32_t last_i = 0;
318         for (uint32_t bn = 0; bn < npartitions; ++bn) {
319             invariant(BLB_MAX_MSN_APPLIED(dn, bn).msn ==
320                    POSTSERIALIZE_MSN_ON_DISK.msn);
321             invariant(dest_ndd[bn].start > 0);
322             invariant(dest_ndd[bn].size > 0);
323             if (bn > 0) {
324                 invariant(dest_ndd[bn].start >=
325                        dest_ndd[bn - 1].start + dest_ndd[bn - 1].size);
326             }
327             for (uint32_t i = 0; i < BLB_DATA(dn, bn)->num_klpairs(); i++) {
328                 LEAFENTRY curr_le;
329                 uint32_t curr_keylen;
330                 void *curr_key;
331                 BLB_DATA(dn, bn)
332                     ->fetch_klpair(i, &curr_le, &curr_keylen, &curr_key);
333                 invariant(leafentry_memsize(curr_le) ==
334                        leafentry_memsize(elts[last_i].le));
335                 invariant(memcmp(curr_le,
336                               elts[last_i].le,
337                               leafentry_memsize(curr_le)) == 0);
338                 if (bn < npartitions - 1) {
339                     invariant(strcmp((char *)dn->pivotkeys.get_pivot(bn).data,
340                                   elts[last_i].keyp) <= 0);
341                 }
342                 // TODO for later, get a key comparison here as well
343                 last_i++;
344             }
345         }
346         invariant(last_i == 3);
347     }
348 
349     toku_ftnode_free(&dn);
350     toku_destroy_ftnode_internals(&sn);
351 
352     ft_h->blocktable.block_free(
353         BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE, 100);
354     ft_h->blocktable.destroy();
355     toku_free(ft_h->h);
356     toku_free(ft_h);
357     toku_free(ft);
358     toku_free(src_ndd);
359     toku_free(dest_ndd);
360 
361     r = close(fd);
362     invariant(r != -1);
363 }
364 
test_serialize_leaf_with_large_pivots(enum ftnode_verify_type bft,bool do_clone)365 static void test_serialize_leaf_with_large_pivots(enum ftnode_verify_type bft,
366                                                   bool do_clone) {
367     int r;
368     struct ftnode sn, *dn;
369     const int keylens = 256 * 1024, vallens = 0;
370     const uint32_t nrows = 8;
371     // invariant(val_size > BN_MAX_SIZE);  // BN_MAX_SIZE isn't visible
372     int fd = open(TOKU_TEST_FILENAME,
373                   O_RDWR | O_CREAT | O_BINARY,
374                   S_IRWXU | S_IRWXG | S_IRWXO);
375     invariant(fd >= 0);
376 
377     sn.max_msn_applied_to_node_on_disk.msn = 0;
378     sn.flags = 0x11223344;
379     sn.blocknum.b = 20;
380     sn.layout_version = FT_LAYOUT_VERSION;
381     sn.layout_version_original = FT_LAYOUT_VERSION;
382     sn.height = 0;
383     sn.n_children = nrows;
384     sn.set_dirty();
385     sn.oldest_referenced_xid_known = TXNID_NONE;
386 
387     MALLOC_N(sn.n_children, sn.bp);
388     sn.pivotkeys.create_empty();
389     for (int i = 0; i < sn.n_children; ++i) {
390         BP_STATE(&sn, i) = PT_AVAIL;
391         set_BLB(&sn, i, toku_create_empty_bn());
392     }
393     for (uint32_t i = 0; i < nrows; ++i) {  // one basement per row
394         char key[keylens], val[vallens];
395         key[keylens - 1] = '\0';
396         char c = 'a' + i;
397         memset(key, c, keylens - 1);
398         le_add_to_bn(BLB_DATA(&sn, i),
399                      0,
400                      (char *)&key,
401                      sizeof(key),
402                      (char *)&val,
403                      sizeof(val));
404         if (i < nrows - 1) {
405             uint32_t keylen;
406             void *curr_key;
407             BLB_DATA(&sn, i)->fetch_key_and_len(0, &keylen, &curr_key);
408             DBT pivotkey;
409             sn.pivotkeys.insert_at(toku_fill_dbt(&pivotkey, curr_key, keylen),
410                                    i);
411         }
412     }
413 
414     FT_HANDLE XMALLOC(ft);
415     FT XCALLOC(ft_h);
416     toku_ft_init(ft_h,
417                  make_blocknum(0),
418                  ZERO_LSN,
419                  TXNID_NONE,
420                  4 * 1024 * 1024,
421                  128 * 1024,
422                  TOKU_DEFAULT_COMPRESSION_METHOD,
423                  16);
424     ft->ft = ft_h;
425     ft_h->blocktable.create();
426     {
427         int r_truncate = ftruncate(fd, 0);
428         CKERR(r_truncate);
429     }
430     // Want to use block #20
431     BLOCKNUM b = make_blocknum(0);
432     while (b.b < 20) {
433         ft_h->blocktable.allocate_blocknum(&b, ft_h);
434     }
435     invariant(b.b == 20);
436 
437     {
438         DISKOFF offset;
439         DISKOFF size;
440         ft_h->blocktable.realloc_on_disk(b, 100, &offset, ft_h, fd, false);
441         invariant(offset ==
442                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
443 
444         ft_h->blocktable.translate_blocknum_to_offset_size(b, &offset, &size);
445         invariant(offset ==
446                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
447         invariant(size == 100);
448     }
449     FTNODE_DISK_DATA src_ndd = NULL;
450     FTNODE_DISK_DATA dest_ndd = NULL;
451 
452     write_sn_to_disk(fd, ft, &sn, &src_ndd, do_clone);
453 
454     setup_dn(bft, fd, ft_h, &dn, &dest_ndd);
455 
456     invariant(dn->blocknum.b == 20);
457 
458     invariant(dn->layout_version == FT_LAYOUT_VERSION);
459     invariant(dn->layout_version_original == FT_LAYOUT_VERSION);
460     {
461         // Man, this is way too ugly.  This entire test suite needs to be
462         // refactored.
463         // Create a dummy mempool and put the leaves there.  Ugh.
464         test_key_le_pair *les = new test_key_le_pair[nrows];
465         {
466             char key[keylens], val[vallens];
467             key[keylens - 1] = '\0';
468             for (uint32_t i = 0; i < nrows; ++i) {
469                 char c = 'a' + i;
470                 memset(key, c, keylens - 1);
471                 les[i].init(
472                     (char *)&key, sizeof(key), (char *)&val, sizeof(val));
473             }
474         }
475         const uint32_t npartitions = dn->n_children;
476         uint32_t last_i = 0;
477         for (uint32_t bn = 0; bn < npartitions; ++bn) {
478             invariant(dest_ndd[bn].start > 0);
479             invariant(dest_ndd[bn].size > 0);
480             if (bn > 0) {
481                 invariant(dest_ndd[bn].start >=
482                        dest_ndd[bn - 1].start + dest_ndd[bn - 1].size);
483             }
484             invariant(BLB_DATA(dn, bn)->num_klpairs() > 0);
485             for (uint32_t i = 0; i < BLB_DATA(dn, bn)->num_klpairs(); i++) {
486                 LEAFENTRY curr_le;
487                 uint32_t curr_keylen;
488                 void *curr_key;
489                 BLB_DATA(dn, bn)
490                     ->fetch_klpair(i, &curr_le, &curr_keylen, &curr_key);
491                 invariant(leafentry_memsize(curr_le) ==
492                        leafentry_memsize(les[last_i].le));
493                 invariant(memcmp(curr_le,
494                               les[last_i].le,
495                               leafentry_memsize(curr_le)) == 0);
496                 if (bn < npartitions - 1) {
497                     invariant(strcmp((char *)dn->pivotkeys.get_pivot(bn).data,
498                                   les[last_i].keyp) <= 0);
499                 }
500                 // TODO for later, get a key comparison here as well
501                 last_i++;
502             }
503         }
504         invariant(last_i == nrows);
505         delete[] les;
506     }
507 
508     toku_ftnode_free(&dn);
509     toku_destroy_ftnode_internals(&sn);
510 
511     ft_h->blocktable.block_free(
512         BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE, 100);
513     ft_h->blocktable.destroy();
514     toku_free(ft_h->h);
515     toku_free(ft_h);
516     toku_free(ft);
517     toku_free(src_ndd);
518     toku_free(dest_ndd);
519 
520     r = close(fd);
521     invariant(r != -1);
522 }
523 
test_serialize_leaf_with_many_rows(enum ftnode_verify_type bft,bool do_clone)524 static void test_serialize_leaf_with_many_rows(enum ftnode_verify_type bft,
525                                                bool do_clone) {
526     int r;
527     struct ftnode sn, *dn;
528     const uint32_t nrows = 196 * 1024;
529     int fd = open(TOKU_TEST_FILENAME,
530                   O_RDWR | O_CREAT | O_BINARY,
531                   S_IRWXU | S_IRWXG | S_IRWXO);
532     invariant(fd >= 0);
533 
534     sn.max_msn_applied_to_node_on_disk.msn = 0;
535     sn.flags = 0x11223344;
536     sn.blocknum.b = 20;
537     sn.layout_version = FT_LAYOUT_VERSION;
538     sn.layout_version_original = FT_LAYOUT_VERSION;
539     sn.height = 0;
540     sn.n_children = 1;
541     sn.set_dirty();
542     sn.oldest_referenced_xid_known = TXNID_NONE;
543 
544     XMALLOC_N(sn.n_children, sn.bp);
545     sn.pivotkeys.create_empty();
546     for (int i = 0; i < sn.n_children; ++i) {
547         BP_STATE(&sn, i) = PT_AVAIL;
548         set_BLB(&sn, i, toku_create_empty_bn());
549     }
550     size_t total_size = 0;
551     for (uint32_t i = 0; i < nrows; ++i) {
552         uint32_t key = i;
553         uint32_t val = i;
554         total_size += le_add_to_bn(BLB_DATA(&sn, 0),
555                                    i,
556                                    (char *)&key,
557                                    sizeof(key),
558                                    (char *)&val,
559                                    sizeof(val));
560     }
561 
562     FT_HANDLE XMALLOC(ft);
563     FT XCALLOC(ft_h);
564     toku_ft_init(ft_h,
565                  make_blocknum(0),
566                  ZERO_LSN,
567                  TXNID_NONE,
568                  4 * 1024 * 1024,
569                  128 * 1024,
570                  TOKU_DEFAULT_COMPRESSION_METHOD,
571                  16);
572     ft->ft = ft_h;
573 
574     ft_h->blocktable.create();
575     {
576         int r_truncate = ftruncate(fd, 0);
577         CKERR(r_truncate);
578     }
579     // Want to use block #20
580     BLOCKNUM b = make_blocknum(0);
581     while (b.b < 20) {
582         ft_h->blocktable.allocate_blocknum(&b, ft_h);
583     }
584     invariant(b.b == 20);
585 
586     {
587         DISKOFF offset;
588         DISKOFF size;
589         ft_h->blocktable.realloc_on_disk(b, 100, &offset, ft_h, fd, false);
590         invariant(offset ==
591                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
592 
593         ft_h->blocktable.translate_blocknum_to_offset_size(b, &offset, &size);
594         invariant(offset ==
595                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
596         invariant(size == 100);
597     }
598 
599     FTNODE_DISK_DATA src_ndd = NULL;
600     FTNODE_DISK_DATA dest_ndd = NULL;
601     write_sn_to_disk(fd, ft, &sn, &src_ndd, do_clone);
602 
603     setup_dn(bft, fd, ft_h, &dn, &dest_ndd);
604 
605     invariant(dn->blocknum.b == 20);
606 
607     invariant(dn->layout_version == FT_LAYOUT_VERSION);
608     invariant(dn->layout_version_original == FT_LAYOUT_VERSION);
609     {
610         // Man, this is way too ugly.  This entire test suite needs to be
611         // refactored.
612         // Create a dummy mempool and put the leaves there.  Ugh.
613         test_key_le_pair *les = new test_key_le_pair[nrows];
614         {
615             int key = 0, val = 0;
616             for (uint32_t i = 0; i < nrows; ++i, key++, val++) {
617                 les[i].init(
618                     (char *)&key, sizeof(key), (char *)&val, sizeof(val));
619             }
620         }
621         const uint32_t npartitions = dn->n_children;
622         uint32_t last_i = 0;
623         for (uint32_t bn = 0; bn < npartitions; ++bn) {
624             invariant(dest_ndd[bn].start > 0);
625             invariant(dest_ndd[bn].size > 0);
626             if (bn > 0) {
627                 invariant(dest_ndd[bn].start >=
628                        dest_ndd[bn - 1].start + dest_ndd[bn - 1].size);
629             }
630             invariant(BLB_DATA(dn, bn)->num_klpairs() > 0);
631             for (uint32_t i = 0; i < BLB_DATA(dn, bn)->num_klpairs(); i++) {
632                 LEAFENTRY curr_le;
633                 uint32_t curr_keylen;
634                 void *curr_key;
635                 BLB_DATA(dn, bn)
636                     ->fetch_klpair(i, &curr_le, &curr_keylen, &curr_key);
637                 invariant(leafentry_memsize(curr_le) ==
638                        leafentry_memsize(les[last_i].le));
639                 invariant(memcmp(curr_le,
640                               les[last_i].le,
641                               leafentry_memsize(curr_le)) == 0);
642                 if (bn < npartitions - 1) {
643                     uint32_t *CAST_FROM_VOIDP(pivot,
644                                               dn->pivotkeys.get_pivot(bn).data);
645                     void *tmp = les[last_i].keyp;
646                     uint32_t *CAST_FROM_VOIDP(item, tmp);
647                     invariant(*pivot >= *item);
648                 }
649                 // TODO for later, get a key comparison here as well
650                 last_i++;
651             }
652             // don't check soft_copy_is_up_to_date or seqinsert
653             invariant(BLB_DATA(dn, bn)->get_disk_size() <
654                    128 * 1024);  // BN_MAX_SIZE, apt to change
655         }
656         invariant(last_i == nrows);
657         delete[] les;
658     }
659 
660     toku_ftnode_free(&dn);
661     toku_destroy_ftnode_internals(&sn);
662 
663     ft_h->blocktable.block_free(
664         BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE, 100);
665     ft_h->blocktable.destroy();
666     toku_free(ft_h->h);
667     toku_free(ft_h);
668     toku_free(ft);
669     toku_free(src_ndd);
670     toku_free(dest_ndd);
671 
672     r = close(fd);
673     invariant(r != -1);
674 }
675 
test_serialize_leaf_with_large_rows(enum ftnode_verify_type bft,bool do_clone)676 static void test_serialize_leaf_with_large_rows(enum ftnode_verify_type bft,
677                                                 bool do_clone) {
678     int r;
679     struct ftnode sn, *dn;
680     const uint32_t nrows = 7;
681     const size_t key_size = 8;
682     const size_t val_size = 512 * 1024;
683     // invariant(val_size > BN_MAX_SIZE);  // BN_MAX_SIZE isn't visible
684     int fd = open(TOKU_TEST_FILENAME,
685                   O_RDWR | O_CREAT | O_BINARY,
686                   S_IRWXU | S_IRWXG | S_IRWXO);
687     invariant(fd >= 0);
688 
689     sn.max_msn_applied_to_node_on_disk.msn = 0;
690     sn.flags = 0x11223344;
691     sn.blocknum.b = 20;
692     sn.layout_version = FT_LAYOUT_VERSION;
693     sn.layout_version_original = FT_LAYOUT_VERSION;
694     sn.height = 0;
695     sn.n_children = 1;
696     sn.set_dirty();
697     sn.oldest_referenced_xid_known = TXNID_NONE;
698 
699     MALLOC_N(sn.n_children, sn.bp);
700     sn.pivotkeys.create_empty();
701     for (int i = 0; i < sn.n_children; ++i) {
702         BP_STATE(&sn, i) = PT_AVAIL;
703         set_BLB(&sn, i, toku_create_empty_bn());
704     }
705     for (uint32_t i = 0; i < nrows; ++i) {
706         char key[key_size], val[val_size];
707         key[key_size - 1] = '\0';
708         val[val_size - 1] = '\0';
709         char c = 'a' + i;
710         memset(key, c, key_size - 1);
711         memset(val, c, val_size - 1);
712         le_add_to_bn(BLB_DATA(&sn, 0), i, key, 8, val, val_size);
713     }
714 
715     FT_HANDLE XMALLOC(ft);
716     FT XCALLOC(ft_h);
717     toku_ft_init(ft_h,
718                  make_blocknum(0),
719                  ZERO_LSN,
720                  TXNID_NONE,
721                  4 * 1024 * 1024,
722                  128 * 1024,
723                  TOKU_DEFAULT_COMPRESSION_METHOD,
724                  16);
725     ft->ft = ft_h;
726 
727     ft_h->blocktable.create();
728     {
729         int r_truncate = ftruncate(fd, 0);
730         CKERR(r_truncate);
731     }
732     // Want to use block #20
733     BLOCKNUM b = make_blocknum(0);
734     while (b.b < 20) {
735         ft_h->blocktable.allocate_blocknum(&b, ft_h);
736     }
737     invariant(b.b == 20);
738 
739     {
740         DISKOFF offset;
741         DISKOFF size;
742         ft_h->blocktable.realloc_on_disk(b, 100, &offset, ft_h, fd, false);
743         invariant(offset ==
744                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
745 
746         ft_h->blocktable.translate_blocknum_to_offset_size(b, &offset, &size);
747         invariant(offset ==
748                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
749         invariant(size == 100);
750     }
751 
752     FTNODE_DISK_DATA src_ndd = NULL;
753     FTNODE_DISK_DATA dest_ndd = NULL;
754     write_sn_to_disk(fd, ft, &sn, &src_ndd, do_clone);
755 
756     setup_dn(bft, fd, ft_h, &dn, &dest_ndd);
757 
758     invariant(dn->blocknum.b == 20);
759 
760     invariant(dn->layout_version == FT_LAYOUT_VERSION);
761     invariant(dn->layout_version_original == FT_LAYOUT_VERSION);
762     {
763         // Man, this is way too ugly.  This entire test suite needs to be
764         // refactored.
765         // Create a dummy mempool and put the leaves there.  Ugh.
766         test_key_le_pair *les = new test_key_le_pair[nrows];
767         {
768             char key[key_size], val[val_size];
769             key[key_size - 1] = '\0';
770             val[val_size - 1] = '\0';
771             for (uint32_t i = 0; i < nrows; ++i) {
772                 char c = 'a' + i;
773                 memset(key, c, key_size - 1);
774                 memset(val, c, val_size - 1);
775                 les[i].init(key, key_size, val, val_size);
776             }
777         }
778         const uint32_t npartitions = dn->n_children;
779         invariant(npartitions == nrows);
780         uint32_t last_i = 0;
781         for (uint32_t bn = 0; bn < npartitions; ++bn) {
782             invariant(dest_ndd[bn].start > 0);
783             invariant(dest_ndd[bn].size > 0);
784             if (bn > 0) {
785                 invariant(dest_ndd[bn].start >=
786                        dest_ndd[bn - 1].start + dest_ndd[bn - 1].size);
787             }
788             invariant(BLB_DATA(dn, bn)->num_klpairs() > 0);
789             for (uint32_t i = 0; i < BLB_DATA(dn, bn)->num_klpairs(); i++) {
790                 LEAFENTRY curr_le;
791                 uint32_t curr_keylen;
792                 void *curr_key;
793                 BLB_DATA(dn, bn)
794                     ->fetch_klpair(i, &curr_le, &curr_keylen, &curr_key);
795                 invariant(leafentry_memsize(curr_le) ==
796                        leafentry_memsize(les[last_i].le));
797                 invariant(memcmp(curr_le,
798                               les[last_i].le,
799                               leafentry_memsize(curr_le)) == 0);
800                 if (bn < npartitions - 1) {
801                     invariant(strcmp((char *)dn->pivotkeys.get_pivot(bn).data,
802                                   (char *)(les[last_i].keyp)) <= 0);
803                 }
804                 // TODO for later, get a key comparison here as well
805                 last_i++;
806             }
807             // don't check soft_copy_is_up_to_date or seqinsert
808         }
809         invariant(last_i == 7);
810         delete[] les;
811     }
812 
813     toku_ftnode_free(&dn);
814     toku_destroy_ftnode_internals(&sn);
815 
816     ft_h->blocktable.block_free(
817         BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE, 100);
818     ft_h->blocktable.destroy();
819     toku_free(ft_h->h);
820     toku_free(ft_h);
821     toku_free(ft);
822     toku_free(src_ndd);
823     toku_free(dest_ndd);
824 
825     r = close(fd);
826     invariant(r != -1);
827 }
828 
test_serialize_leaf_with_empty_basement_nodes(enum ftnode_verify_type bft,bool do_clone)829 static void test_serialize_leaf_with_empty_basement_nodes(
830     enum ftnode_verify_type bft,
831     bool do_clone) {
832     struct ftnode sn, *dn;
833 
834     int fd = open(TOKU_TEST_FILENAME,
835                   O_RDWR | O_CREAT | O_BINARY,
836                   S_IRWXU | S_IRWXG | S_IRWXO);
837     invariant(fd >= 0);
838 
839     int r;
840 
841     sn.max_msn_applied_to_node_on_disk.msn = 0;
842     sn.flags = 0x11223344;
843     sn.blocknum.b = 20;
844     sn.layout_version = FT_LAYOUT_VERSION;
845     sn.layout_version_original = FT_LAYOUT_VERSION;
846     sn.height = 0;
847     sn.n_children = 7;
848     sn.set_dirty();
849     sn.oldest_referenced_xid_known = TXNID_NONE;
850     MALLOC_N(sn.n_children, sn.bp);
851     DBT pivotkeys[6];
852     toku_fill_dbt(&pivotkeys[0], "A", 2);
853     toku_fill_dbt(&pivotkeys[1], "a", 2);
854     toku_fill_dbt(&pivotkeys[2], "a", 2);
855     toku_fill_dbt(&pivotkeys[3], "b", 2);
856     toku_fill_dbt(&pivotkeys[4], "b", 2);
857     toku_fill_dbt(&pivotkeys[5], "x", 2);
858     sn.pivotkeys.create_from_dbts(pivotkeys, 6);
859     for (int i = 0; i < sn.n_children; ++i) {
860         BP_STATE(&sn, i) = PT_AVAIL;
861         set_BLB(&sn, i, toku_create_empty_bn());
862         BLB_SEQINSERT(&sn, i) = 0;
863     }
864     le_add_to_bn(BLB_DATA(&sn, 1), 0, "a", 2, "aval", 5);
865     le_add_to_bn(BLB_DATA(&sn, 3), 0, "b", 2, "bval", 5);
866     le_add_to_bn(BLB_DATA(&sn, 5), 0, "x", 2, "xval", 5);
867 
868     FT_HANDLE XMALLOC(ft);
869     FT XCALLOC(ft_h);
870     toku_ft_init(ft_h,
871                  make_blocknum(0),
872                  ZERO_LSN,
873                  TXNID_NONE,
874                  4 * 1024 * 1024,
875                  128 * 1024,
876                  TOKU_DEFAULT_COMPRESSION_METHOD,
877                  16);
878     ft->ft = ft_h;
879 
880     ft_h->blocktable.create();
881     {
882         int r_truncate = ftruncate(fd, 0);
883         CKERR(r_truncate);
884     }
885     // Want to use block #20
886     BLOCKNUM b = make_blocknum(0);
887     while (b.b < 20) {
888         ft_h->blocktable.allocate_blocknum(&b, ft_h);
889     }
890     invariant(b.b == 20);
891 
892     {
893         DISKOFF offset;
894         DISKOFF size;
895         ft_h->blocktable.realloc_on_disk(b, 100, &offset, ft_h, fd, false);
896         invariant(offset ==
897                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
898 
899         ft_h->blocktable.translate_blocknum_to_offset_size(b, &offset, &size);
900         invariant(offset ==
901                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
902         invariant(size == 100);
903     }
904     FTNODE_DISK_DATA src_ndd = NULL;
905     FTNODE_DISK_DATA dest_ndd = NULL;
906     write_sn_to_disk(fd, ft, &sn, &src_ndd, do_clone);
907 
908     setup_dn(bft, fd, ft_h, &dn, &dest_ndd);
909 
910     invariant(dn->blocknum.b == 20);
911 
912     invariant(dn->layout_version == FT_LAYOUT_VERSION);
913     invariant(dn->layout_version_original == FT_LAYOUT_VERSION);
914     invariant(dn->layout_version_read_from_disk == FT_LAYOUT_VERSION);
915     invariant(dn->height == 0);
916     invariant(dn->n_children > 0);
917     {
918         test_key_le_pair elts[3];
919 
920         // Man, this is way too ugly.  This entire test suite needs to be
921         // refactored.
922         // Create a dummy mempool and put the leaves there.  Ugh.
923         elts[0].init("a", "aval");
924         elts[1].init("b", "bval");
925         elts[2].init("x", "xval");
926         const uint32_t npartitions = dn->n_children;
927         uint32_t last_i = 0;
928         for (uint32_t bn = 0; bn < npartitions; ++bn) {
929             invariant(dest_ndd[bn].start > 0);
930             invariant(dest_ndd[bn].size > 0);
931             if (bn > 0) {
932                 invariant(dest_ndd[bn].start >=
933                        dest_ndd[bn - 1].start + dest_ndd[bn - 1].size);
934             }
935             for (uint32_t i = 0; i < BLB_DATA(dn, bn)->num_klpairs(); i++) {
936                 LEAFENTRY curr_le;
937                 uint32_t curr_keylen;
938                 void *curr_key;
939                 BLB_DATA(dn, bn)
940                     ->fetch_klpair(i, &curr_le, &curr_keylen, &curr_key);
941                 invariant(leafentry_memsize(curr_le) ==
942                        leafentry_memsize(elts[last_i].le));
943                 invariant(memcmp(curr_le,
944                               elts[last_i].le,
945                               leafentry_memsize(curr_le)) == 0);
946                 if (bn < npartitions - 1) {
947                     invariant(strcmp((char *)dn->pivotkeys.get_pivot(bn).data,
948                                   (char *)(elts[last_i].keyp)) <= 0);
949                 }
950                 // TODO for later, get a key comparison here as well
951                 last_i++;
952             }
953         }
954         invariant(last_i == 3);
955     }
956 
957     toku_ftnode_free(&dn);
958     toku_destroy_ftnode_internals(&sn);
959 
960     ft_h->blocktable.block_free(
961         BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE, 100);
962     ft_h->blocktable.destroy();
963     toku_free(ft_h->h);
964     toku_free(ft_h);
965     toku_free(ft);
966     toku_free(src_ndd);
967     toku_free(dest_ndd);
968 
969     r = close(fd);
970     invariant(r != -1);
971 }
972 
test_serialize_leaf_with_multiple_empty_basement_nodes(enum ftnode_verify_type bft,bool do_clone)973 static void test_serialize_leaf_with_multiple_empty_basement_nodes(
974     enum ftnode_verify_type bft,
975     bool do_clone) {
976     struct ftnode sn, *dn;
977 
978     int fd = open(TOKU_TEST_FILENAME,
979                   O_RDWR | O_CREAT | O_BINARY,
980                   S_IRWXU | S_IRWXG | S_IRWXO);
981     invariant(fd >= 0);
982 
983     int r;
984 
985     sn.max_msn_applied_to_node_on_disk.msn = 0;
986     sn.flags = 0x11223344;
987     sn.blocknum.b = 20;
988     sn.layout_version = FT_LAYOUT_VERSION;
989     sn.layout_version_original = FT_LAYOUT_VERSION;
990     sn.height = 0;
991     sn.n_children = 4;
992     sn.set_dirty();
993     sn.oldest_referenced_xid_known = TXNID_NONE;
994     MALLOC_N(sn.n_children, sn.bp);
995     DBT pivotkeys[3];
996     toku_fill_dbt(&pivotkeys[0], "A", 2);
997     toku_fill_dbt(&pivotkeys[1], "A", 2);
998     toku_fill_dbt(&pivotkeys[2], "A", 2);
999     sn.pivotkeys.create_from_dbts(pivotkeys, 3);
1000     for (int i = 0; i < sn.n_children; ++i) {
1001         BP_STATE(&sn, i) = PT_AVAIL;
1002         set_BLB(&sn, i, toku_create_empty_bn());
1003     }
1004 
1005     FT_HANDLE XMALLOC(ft);
1006     FT XCALLOC(ft_h);
1007     toku_ft_init(ft_h,
1008                  make_blocknum(0),
1009                  ZERO_LSN,
1010                  TXNID_NONE,
1011                  4 * 1024 * 1024,
1012                  128 * 1024,
1013                  TOKU_DEFAULT_COMPRESSION_METHOD,
1014                  16);
1015     ft->ft = ft_h;
1016 
1017     ft_h->blocktable.create();
1018     {
1019         int r_truncate = ftruncate(fd, 0);
1020         CKERR(r_truncate);
1021     }
1022     // Want to use block #20
1023     BLOCKNUM b = make_blocknum(0);
1024     while (b.b < 20) {
1025         ft_h->blocktable.allocate_blocknum(&b, ft_h);
1026     }
1027     invariant(b.b == 20);
1028 
1029     {
1030         DISKOFF offset;
1031         DISKOFF size;
1032         ft_h->blocktable.realloc_on_disk(b, 100, &offset, ft_h, fd, false);
1033         invariant(offset ==
1034                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
1035 
1036         ft_h->blocktable.translate_blocknum_to_offset_size(b, &offset, &size);
1037         invariant(offset ==
1038                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
1039         invariant(size == 100);
1040     }
1041 
1042     FTNODE_DISK_DATA src_ndd = NULL;
1043     FTNODE_DISK_DATA dest_ndd = NULL;
1044     write_sn_to_disk(fd, ft, &sn, &src_ndd, do_clone);
1045 
1046     setup_dn(bft, fd, ft_h, &dn, &dest_ndd);
1047 
1048     invariant(dn->blocknum.b == 20);
1049 
1050     invariant(dn->layout_version == FT_LAYOUT_VERSION);
1051     invariant(dn->layout_version_original == FT_LAYOUT_VERSION);
1052     invariant(dn->layout_version_read_from_disk == FT_LAYOUT_VERSION);
1053     invariant(dn->height == 0);
1054     invariant(dn->n_children == 1);
1055     {
1056         const uint32_t npartitions = dn->n_children;
1057         for (uint32_t i = 0; i < npartitions; ++i) {
1058             invariant(dest_ndd[i].start > 0);
1059             invariant(dest_ndd[i].size > 0);
1060             if (i > 0) {
1061                 invariant(dest_ndd[i].start >=
1062                        dest_ndd[i - 1].start + dest_ndd[i - 1].size);
1063             }
1064             invariant(BLB_DATA(dn, i)->num_klpairs() == 0);
1065         }
1066     }
1067 
1068     toku_ftnode_free(&dn);
1069     toku_destroy_ftnode_internals(&sn);
1070 
1071     ft_h->blocktable.block_free(
1072         BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE, 100);
1073     ft_h->blocktable.destroy();
1074     toku_free(ft_h->h);
1075     toku_free(ft_h);
1076     toku_free(ft);
1077     toku_free(src_ndd);
1078     toku_free(dest_ndd);
1079 
1080     r = close(fd);
1081     invariant(r != -1);
1082 }
1083 
test_serialize_nonleaf(enum ftnode_verify_type bft,bool do_clone)1084 static void test_serialize_nonleaf(enum ftnode_verify_type bft, bool do_clone) {
1085     //    struct ft_handle source_ft;
1086     struct ftnode sn, *dn;
1087 
1088     int fd = open(TOKU_TEST_FILENAME,
1089                   O_RDWR | O_CREAT | O_BINARY,
1090                   S_IRWXU | S_IRWXG | S_IRWXO);
1091     invariant(fd >= 0);
1092 
1093     int r;
1094 
1095     //    source_ft.fd=fd;
1096     sn.max_msn_applied_to_node_on_disk.msn = 0;
1097     sn.flags = 0x11223344;
1098     sn.blocknum.b = 20;
1099     sn.layout_version = FT_LAYOUT_VERSION;
1100     sn.layout_version_original = FT_LAYOUT_VERSION;
1101     sn.height = 1;
1102     sn.n_children = 2;
1103     sn.set_dirty();
1104     sn.oldest_referenced_xid_known = TXNID_NONE;
1105     MALLOC_N(2, sn.bp);
1106     DBT pivotkey;
1107     sn.pivotkeys.create_from_dbts(toku_fill_dbt(&pivotkey, "hello", 6), 1);
1108     BP_BLOCKNUM(&sn, 0).b = 30;
1109     BP_BLOCKNUM(&sn, 1).b = 35;
1110     BP_STATE(&sn, 0) = PT_AVAIL;
1111     BP_STATE(&sn, 1) = PT_AVAIL;
1112     set_BNC(&sn, 0, toku_create_empty_nl());
1113     set_BNC(&sn, 1, toku_create_empty_nl());
1114     // Create XIDS
1115     XIDS xids_0 = toku_xids_get_root_xids();
1116     XIDS xids_123;
1117     XIDS xids_234;
1118     r = toku_xids_create_child(xids_0, &xids_123, (TXNID)123);
1119     CKERR(r);
1120     r = toku_xids_create_child(xids_123, &xids_234, (TXNID)234);
1121     CKERR(r);
1122 
1123     toku::comparator cmp;
1124     cmp.create(string_key_cmp, nullptr);
1125 
1126     toku_bnc_insert_msg(BNC(&sn, 0),
1127                         "a",
1128                         2,
1129                         "aval",
1130                         5,
1131                         FT_NONE,
1132                         next_dummymsn(),
1133                         xids_0,
1134                         true,
1135                         cmp);
1136     toku_bnc_insert_msg(BNC(&sn, 0),
1137                         "b",
1138                         2,
1139                         "bval",
1140                         5,
1141                         FT_NONE,
1142                         next_dummymsn(),
1143                         xids_123,
1144                         false,
1145                         cmp);
1146     toku_bnc_insert_msg(BNC(&sn, 1),
1147                         "x",
1148                         2,
1149                         "xval",
1150                         5,
1151                         FT_NONE,
1152                         next_dummymsn(),
1153                         xids_234,
1154                         true,
1155                         cmp);
1156 
1157     // Cleanup:
1158     toku_xids_destroy(&xids_0);
1159     toku_xids_destroy(&xids_123);
1160     toku_xids_destroy(&xids_234);
1161     cmp.destroy();
1162 
1163     FT_HANDLE XMALLOC(ft);
1164     FT XCALLOC(ft_h);
1165     toku_ft_init(ft_h,
1166                  make_blocknum(0),
1167                  ZERO_LSN,
1168                  TXNID_NONE,
1169                  4 * 1024 * 1024,
1170                  128 * 1024,
1171                  TOKU_DEFAULT_COMPRESSION_METHOD,
1172                  16);
1173     ft_h->cmp.create(string_key_cmp, nullptr);
1174     ft->ft = ft_h;
1175 
1176     ft_h->blocktable.create();
1177     {
1178         int r_truncate = ftruncate(fd, 0);
1179         CKERR(r_truncate);
1180     }
1181     // Want to use block #20
1182     BLOCKNUM b = make_blocknum(0);
1183     while (b.b < 20) {
1184         ft_h->blocktable.allocate_blocknum(&b, ft_h);
1185     }
1186     invariant(b.b == 20);
1187 
1188     {
1189         DISKOFF offset;
1190         DISKOFF size;
1191         ft_h->blocktable.realloc_on_disk(b, 100, &offset, ft_h, fd, false);
1192         invariant(offset ==
1193                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
1194 
1195         ft_h->blocktable.translate_blocknum_to_offset_size(b, &offset, &size);
1196         invariant(offset ==
1197                (DISKOFF)BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE);
1198         invariant(size == 100);
1199     }
1200     FTNODE_DISK_DATA src_ndd = NULL;
1201     FTNODE_DISK_DATA dest_ndd = NULL;
1202     write_sn_to_disk(fd, ft, &sn, &src_ndd, do_clone);
1203 
1204     setup_dn(bft, fd, ft_h, &dn, &dest_ndd);
1205 
1206     invariant(dn->blocknum.b == 20);
1207 
1208     invariant(dn->layout_version == FT_LAYOUT_VERSION);
1209     invariant(dn->layout_version_original == FT_LAYOUT_VERSION);
1210     invariant(dn->layout_version_read_from_disk == FT_LAYOUT_VERSION);
1211     invariant(dn->height == 1);
1212     invariant(dn->n_children == 2);
1213     invariant(strcmp((char *)dn->pivotkeys.get_pivot(0).data, "hello") == 0);
1214     invariant(dn->pivotkeys.get_pivot(0).size == 6);
1215     invariant(BP_BLOCKNUM(dn, 0).b == 30);
1216     invariant(BP_BLOCKNUM(dn, 1).b == 35);
1217 
1218     message_buffer *src_msg_buffer1 = &BNC(&sn, 0)->msg_buffer;
1219     message_buffer *src_msg_buffer2 = &BNC(&sn, 1)->msg_buffer;
1220     message_buffer *dest_msg_buffer1 = &BNC(dn, 0)->msg_buffer;
1221     message_buffer *dest_msg_buffer2 = &BNC(dn, 1)->msg_buffer;
1222 
1223     invariant(src_msg_buffer1->equals(dest_msg_buffer1));
1224     invariant(src_msg_buffer2->equals(dest_msg_buffer2));
1225 
1226     toku_ftnode_free(&dn);
1227     toku_destroy_ftnode_internals(&sn);
1228 
1229     ft_h->blocktable.block_free(
1230         BlockAllocator::BLOCK_ALLOCATOR_TOTAL_HEADER_RESERVE, 100);
1231     ft_h->blocktable.destroy();
1232     ft_h->cmp.destroy();
1233     toku_free(ft_h->h);
1234     toku_free(ft_h);
1235     toku_free(ft);
1236     toku_free(src_ndd);
1237     toku_free(dest_ndd);
1238 
1239     r = close(fd);
1240     invariant(r != -1);
1241 }
1242 
test_main(int argc,const char * argv[])1243 int test_main(int argc __attribute__((__unused__)),
1244               const char *argv[] __attribute__((__unused__))) {
1245     initialize_dummymsn();
1246 
1247     test_serialize_nonleaf(read_none, false);
1248     test_serialize_nonleaf(read_all, false);
1249     test_serialize_nonleaf(read_compressed, false);
1250     test_serialize_nonleaf(read_none, true);
1251     test_serialize_nonleaf(read_all, true);
1252     test_serialize_nonleaf(read_compressed, true);
1253 
1254     test_serialize_leaf_check_msn(read_none, false);
1255     test_serialize_leaf_check_msn(read_all, false);
1256     test_serialize_leaf_check_msn(read_compressed, false);
1257     test_serialize_leaf_check_msn(read_none, true);
1258     test_serialize_leaf_check_msn(read_all, true);
1259     test_serialize_leaf_check_msn(read_compressed, true);
1260 
1261     test_serialize_leaf_with_multiple_empty_basement_nodes(read_none, false);
1262     test_serialize_leaf_with_multiple_empty_basement_nodes(read_all, false);
1263     test_serialize_leaf_with_multiple_empty_basement_nodes(read_compressed,
1264                                                            false);
1265     test_serialize_leaf_with_multiple_empty_basement_nodes(read_none, true);
1266     test_serialize_leaf_with_multiple_empty_basement_nodes(read_all, true);
1267     test_serialize_leaf_with_multiple_empty_basement_nodes(read_compressed,
1268                                                            true);
1269 
1270     test_serialize_leaf_with_empty_basement_nodes(read_none, false);
1271     test_serialize_leaf_with_empty_basement_nodes(read_all, false);
1272     test_serialize_leaf_with_empty_basement_nodes(read_compressed, false);
1273     test_serialize_leaf_with_empty_basement_nodes(read_none, true);
1274     test_serialize_leaf_with_empty_basement_nodes(read_all, true);
1275     test_serialize_leaf_with_empty_basement_nodes(read_compressed, true);
1276 
1277     test_serialize_leaf_with_large_rows(read_none, false);
1278     test_serialize_leaf_with_large_rows(read_all, false);
1279     test_serialize_leaf_with_large_rows(read_compressed, false);
1280     test_serialize_leaf_with_large_rows(read_none, true);
1281     test_serialize_leaf_with_large_rows(read_all, true);
1282     test_serialize_leaf_with_large_rows(read_compressed, true);
1283 
1284     test_serialize_leaf_with_large_pivots(read_none, false);
1285     test_serialize_leaf_with_large_pivots(read_all, false);
1286     test_serialize_leaf_with_large_pivots(read_compressed, false);
1287     test_serialize_leaf_with_large_pivots(read_none, true);
1288     test_serialize_leaf_with_large_pivots(read_all, true);
1289     test_serialize_leaf_with_large_pivots(read_compressed, true);
1290 
1291     test_serialize_leaf_with_many_rows(read_none, false);
1292     test_serialize_leaf_with_many_rows(read_all, false);
1293     test_serialize_leaf_with_many_rows(read_compressed, false);
1294     test_serialize_leaf_with_many_rows(read_none, true);
1295     test_serialize_leaf_with_many_rows(read_all, true);
1296     test_serialize_leaf_with_many_rows(read_compressed, true);
1297 
1298     return 0;
1299 }
1300