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