1
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
5
COPYING CONDITIONS NOTICE:
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of version 2 of the GNU General Public License as
9
published by the Free Software Foundation, and provided that the
10
following conditions are met:
12
* Redistributions of source code must retain this COPYING
13
CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
14
DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
15
PATENT MARKING NOTICE (below), and the PATENT RIGHTS
18
* Redistributions in binary form must reproduce this COPYING
19
CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
20
DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
21
PATENT MARKING NOTICE (below), and the PATENT RIGHTS
22
GRANT (below) in the documentation and/or other materials
23
provided with the distribution.
25
You should have received a copy of the GNU General Public License
26
along with this program; if not, write to the Free Software
27
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32
TokuDB, Tokutek Fractal Tree Indexing Library.
33
Copyright (C) 2007-2013 Tokutek, Inc.
37
This program is distributed in the hope that it will be useful, but
38
WITHOUT ANY WARRANTY; without even the implied warranty of
39
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40
General Public License for more details.
42
UNIVERSITY PATENT NOTICE:
44
The technology is licensed by the Massachusetts Institute of
45
Technology, Rutgers State University of New Jersey, and the Research
46
Foundation of State University of New York at Stony Brook under
47
United States of America Serial No. 11/760379 and to the patents
48
and/or patent applications resulting from it.
50
PATENT MARKING NOTICE:
52
This software is covered by US Patent No. 8,185,551.
53
This software is covered by US Patent No. 8,489,638.
57
"THIS IMPLEMENTATION" means the copyrightable works distributed by
58
Tokutek as part of the Fractal Tree project.
60
"PATENT CLAIMS" means the claims of patents that are owned or
61
licensable by Tokutek, both currently or in the future; and that in
62
the absence of this license would be infringed by THIS
63
IMPLEMENTATION or by using or running THIS IMPLEMENTATION.
65
"PATENT CHALLENGE" shall mean a challenge to the validity,
66
patentability, enforceability and/or non-infringement of any of the
67
PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.
69
Tokutek hereby grants to you, for the term and geographical scope of
70
the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
71
irrevocable (except as stated in this section) patent license to
72
make, have made, use, offer to sell, sell, import, transfer, and
73
otherwise run, modify, and propagate the contents of THIS
74
IMPLEMENTATION, where such license applies only to the PATENT
75
CLAIMS. This grant does not include claims that would be infringed
76
only as a consequence of further modifications of THIS
77
IMPLEMENTATION. If you or your agent or licensee institute or order
78
or agree to the institution of patent litigation against any entity
79
(including a cross-claim or counterclaim in a lawsuit) alleging that
80
THIS IMPLEMENTATION constitutes direct or contributory patent
81
infringement, or inducement of patent infringement, then any rights
82
granted to you under this License shall terminate as of the date
83
such litigation is filed. If you or your agent or exclusive
84
licensee institute or order or agree to the institution of a PATENT
85
CHALLENGE, then Tokutek may terminate any rights granted to you
89
#ident "Copyright (c) 2007-2013 Tokutek Inc. All rights reserved."
90
#include <toku_portability.h>
97
#include "ule-internal.h"
99
enum {MAX_SIZE = 256};
100
static XIDS nested_xids[MAX_TRANSACTION_RECORDS];
103
verify_ule_equal(ULE a, ULE b) {
104
assert(a->num_cuxrs > 0);
105
assert(a->num_puxrs < MAX_TRANSACTION_RECORDS);
106
assert(a->num_cuxrs == b->num_cuxrs);
107
assert(a->num_puxrs == b->num_puxrs);
109
for (i = 0; i < (a->num_cuxrs + a->num_puxrs); i++) {
110
assert(a->uxrs[i].type == b->uxrs[i].type);
111
assert(a->uxrs[i].xid == b->uxrs[i].xid);
112
if (a->uxrs[i].type == XR_INSERT) {
113
assert(a->uxrs[i].vallen == b->uxrs[i].vallen);
114
assert(memcmp(a->uxrs[i].valp, b->uxrs[i].valp, a->uxrs[i].vallen) == 0);
120
verify_le_equal(LEAFENTRY a, LEAFENTRY b) {
121
if (a==NULL) assert(b==NULL);
125
size_t size = leafentry_memsize(a);
126
assert(size==leafentry_memsize(b));
128
assert(memcmp(a, b, size) == 0);
133
le_unpack(&ule_a, a);
134
le_unpack(&ule_b, b);
135
verify_ule_equal(&ule_a, &ule_b);
142
fillrandom(uint8_t buf[MAX_SIZE], uint32_t length) {
143
assert(length < MAX_SIZE);
145
for (i = 0; i < length; i++) {
146
buf[i] = random() & 0xFF;
151
test_le_offset_is(LEAFENTRY le, void *field, size_t expected_offset) {
152
size_t le_address = (size_t) le;
153
size_t field_address = (size_t) field;
154
assert(field_address >= le_address);
155
size_t actual_offset = field_address - le_address;
156
assert(actual_offset == expected_offset);
159
//Fixed offsets in a packed leafentry.
162
LE_OFFSET_VARIABLE = 1+LE_OFFSET_NUM
166
test_le_fixed_offsets (void) {
167
LEAFENTRY XMALLOC(le);
168
test_le_offset_is(le, &le->type, LE_OFFSET_NUM);
172
//Fixed offsets in a leafentry with no uncommitted transaction records.
173
//(Note, there is no type required.)
175
LE_COMMITTED_OFFSET_VALLEN = LE_OFFSET_VARIABLE,
176
LE_COMMITTED_OFFSET_VAL = 4 + LE_COMMITTED_OFFSET_VALLEN
180
test_le_committed_offsets (void) {
181
LEAFENTRY XMALLOC(le);
182
test_le_offset_is(le, &le->u.clean.vallen, LE_COMMITTED_OFFSET_VALLEN);
183
test_le_offset_is(le, &le->u.clean.val, LE_COMMITTED_OFFSET_VAL);
187
//Fixed offsets in a leafentry with uncommitted transaction records.
189
LE_MVCC_OFFSET_NUM_CUXRS = LE_OFFSET_VARIABLE, //Type of innermost record
190
LE_MVCC_OFFSET_NUM_PUXRS = 4+LE_MVCC_OFFSET_NUM_CUXRS, //XID of outermost noncommitted record
191
LE_MVCC_OFFSET_XRS = 1+LE_MVCC_OFFSET_NUM_PUXRS
195
test_le_provisional_offsets (void) {
196
LEAFENTRY XMALLOC(le);
197
test_le_offset_is(le, &le->u.mvcc.num_cxrs, LE_MVCC_OFFSET_NUM_CUXRS);
198
test_le_offset_is(le, &le->u.mvcc.num_pxrs, LE_MVCC_OFFSET_NUM_PUXRS);
199
test_le_offset_is(le, &le->u.mvcc.xrs, LE_MVCC_OFFSET_XRS);
203
//We use a packed struct to represent a leafentry.
204
//We want to make sure the compiler correctly represents the offsets.
205
//This test verifies all offsets in a packed leafentry correspond to the required memory format.
207
test_le_offsets (void) {
208
test_le_fixed_offsets();
209
test_le_committed_offsets();
210
test_le_provisional_offsets();
214
test_ule_packs_to_nothing (ULE ule) {
216
int r = le_pack(ule, NULL, 0, NULL, 0, 0, &le);
221
//A leafentry must contain at least one 'insert' (all deletes means the leafentry
223
//Verify that 'le_pack' of any set of all deletes ends up not creating a leafentry.
225
test_le_empty_packs_to_nothing (void) {
227
ule.uxrs = ule.uxrs_static;
231
for (committed = 1; committed < MAX_TRANSACTION_RECORDS; committed++) {
234
for (num_xrs = committed; num_xrs < MAX_TRANSACTION_RECORDS; num_xrs++) {
235
ule.num_cuxrs = committed;
236
ule.num_puxrs = num_xrs - committed;
238
ule.uxrs[num_xrs-1].xid = TXNID_NONE;
241
ule.uxrs[num_xrs-1].xid = ule.uxrs[num_xrs-2].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing
243
ule.uxrs[num_xrs-1].type = XR_DELETE;
244
test_ule_packs_to_nothing(&ule);
245
if (num_xrs > 2 && num_xrs > committed && num_xrs % 4) {
246
//Set some of them to placeholders instead of deletes
247
ule.uxrs[num_xrs-2].type = XR_PLACEHOLDER;
249
test_ule_packs_to_nothing(&ule);
256
le_verify_accessors(LEAFENTRY le, ULE ule, size_t pre_calculated_memsize) {
258
assert(ule->num_cuxrs > 0);
259
assert(ule->num_puxrs <= MAX_TRANSACTION_RECORDS);
260
assert(ule->uxrs[ule->num_cuxrs + ule->num_puxrs-1].type != XR_PLACEHOLDER);
261
//Extract expected values from ULE
262
size_t memsize = le_memsize_from_ule(ule);
263
size_t num_uxrs = ule->num_cuxrs + ule->num_puxrs;
265
void *latest_val = ule->uxrs[num_uxrs -1].type == XR_DELETE ? NULL : ule->uxrs[num_uxrs -1].valp;
266
uint32_t latest_vallen = ule->uxrs[num_uxrs -1].type == XR_DELETE ? 0 : ule->uxrs[num_uxrs -1].vallen;
269
for (i = num_uxrs - 1; i >= 0; i--) {
270
if (ule->uxrs[i].type == XR_INSERT) {
277
TXNID outermost_uncommitted_xid = ule->num_puxrs == 0 ? TXNID_NONE : ule->uxrs[ule->num_cuxrs].xid;
278
int is_provdel = ule->uxrs[num_uxrs-1].type == XR_DELETE;
281
//Verify all accessors
282
assert(memsize == pre_calculated_memsize);
283
assert(memsize == leafentry_memsize(le));
285
uint32_t test_vallen;
286
void* test_valp = le_latest_val_and_len(le, &test_vallen);
287
if (latest_val != NULL) assert(test_valp != latest_val);
288
assert(test_vallen == latest_vallen);
289
assert(memcmp(test_valp, latest_val, test_vallen) == 0);
290
assert(le_latest_val(le) == test_valp);
291
assert(le_latest_vallen(le) == test_vallen);
294
assert(le_outermost_uncommitted_xid(le) == outermost_uncommitted_xid);
297
assert((le_latest_is_del(le)==0) == (is_provdel==0));
304
test_le_pack_committed (void) {
306
ule.uxrs = ule.uxrs_static;
308
uint8_t val[MAX_SIZE];
310
for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) {
311
fillrandom(val, valsize);
315
ule.uxrs[0].type = XR_INSERT;
317
ule.uxrs[0].valp = val;
318
ule.uxrs[0].vallen = valsize;
322
int r = le_pack(&ule, nullptr, 0, nullptr, 0, 0, &le);
325
memsize = le_memsize_from_ule(&ule);
326
le_verify_accessors(le, &ule, memsize);
328
le_unpack(&tmp_ule, le);
329
verify_ule_equal(&ule, &tmp_ule);
332
r = le_pack(&tmp_ule, nullptr, 0, nullptr, 0, 0, &tmp_le);
333
tmp_memsize = le_memsize_from_ule(&tmp_ule);
335
assert(tmp_memsize == memsize);
336
assert(memcmp(le, tmp_le, memsize) == 0);
337
le_verify_accessors(tmp_le, &tmp_ule, tmp_memsize);
341
ule_cleanup(&tmp_ule);
346
test_le_pack_uncommitted (uint8_t committed_type, uint8_t prov_type, int num_placeholders) {
348
ule.uxrs = ule.uxrs_static;
349
assert(num_placeholders >= 0);
351
uint8_t cval[MAX_SIZE];
352
uint8_t pval[MAX_SIZE];
355
for (cvalsize = 0; cvalsize < MAX_SIZE; cvalsize += (random() % MAX_SIZE) + 1) {
356
pvalsize = (cvalsize + random()) % MAX_SIZE;
357
if (committed_type == XR_INSERT)
358
fillrandom(cval, cvalsize);
359
if (prov_type == XR_INSERT)
360
fillrandom(pval, pvalsize);
361
ule.uxrs[0].type = committed_type;
362
ule.uxrs[0].xid = TXNID_NONE;
363
ule.uxrs[0].vallen = cvalsize;
364
ule.uxrs[0].valp = cval;
366
ule.num_puxrs = 1 + num_placeholders;
369
for (idx = 1; idx <= (uint32_t)num_placeholders; idx++) {
370
ule.uxrs[idx].type = XR_PLACEHOLDER;
371
ule.uxrs[idx].xid = ule.uxrs[idx-1].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing
373
ule.uxrs[idx].xid = ule.uxrs[idx-1].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing
374
ule.uxrs[idx].type = prov_type;
375
ule.uxrs[idx].vallen = pvalsize;
376
ule.uxrs[idx].valp = pval;
380
int r = le_pack(&ule, nullptr, 0, nullptr, 0, 0, &le);
383
memsize = le_memsize_from_ule(&ule);
384
le_verify_accessors(le, &ule, memsize);
386
le_unpack(&tmp_ule, le);
387
verify_ule_equal(&ule, &tmp_ule);
390
r = le_pack(&tmp_ule, nullptr, 0, nullptr, 0, 0, &tmp_le);
391
tmp_memsize = le_memsize_from_ule(&tmp_ule);
393
assert(tmp_memsize == memsize);
394
assert(memcmp(le, tmp_le, memsize) == 0);
395
le_verify_accessors(tmp_le, &tmp_ule, tmp_memsize);
399
ule_cleanup(&tmp_ule);
404
test_le_pack_provpair (int num_placeholders) {
405
test_le_pack_uncommitted(XR_DELETE, XR_INSERT, num_placeholders);
409
test_le_pack_provdel (int num_placeholders) {
410
test_le_pack_uncommitted(XR_INSERT, XR_DELETE, num_placeholders);
414
test_le_pack_both (int num_placeholders) {
415
test_le_pack_uncommitted(XR_INSERT, XR_INSERT, num_placeholders);
419
// Committed leafentry
420
// delete -> nothing (le_empty_packs_to_nothing)
422
// make key/val have diff lengths/content
425
// followed by placeholder*, delete (le_empty_packs_to_nothing)
426
// followed by placeholder*, insert
428
// followed by placeholder*, delete
429
// followed by placeholder*, insert
431
// placeholder* is 0,1, or 2 placeholders
433
test_le_pack (void) {
434
test_le_empty_packs_to_nothing();
435
test_le_pack_committed();
437
for (i = 0; i < 3; i++) {
438
test_le_pack_provpair(i);
439
test_le_pack_provdel(i);
440
test_le_pack_both(i);
445
test_le_apply(ULE ule_initial, FT_MSG msg, ULE ule_expected) {
447
LEAFENTRY le_initial;
448
LEAFENTRY le_expected;
451
r = le_pack(ule_initial, nullptr, 0, nullptr, 0, 0, &le_initial);
454
size_t result_memsize = 0;
456
toku_le_apply_msg(msg,
465
result_memsize = leafentry_memsize(le_result);
466
le_verify_accessors(le_result, ule_expected, result_memsize);
469
size_t expected_memsize = 0;
470
r = le_pack(ule_expected, nullptr, 0, nullptr, 0, 0, &le_expected);
473
expected_memsize = leafentry_memsize(le_expected);
477
verify_le_equal(le_result, le_expected);
478
if (le_result && le_expected) {
479
assert(result_memsize == expected_memsize);
481
if (le_initial) toku_free(le_initial);
482
if (le_result) toku_free(le_result);
483
if (le_expected) toku_free(le_expected);
486
static const ULE_S ule_committed_delete = {
495
.uxrs = (UXR_S *)ule_committed_delete.uxrs_static
499
msg_init(enum ft_msg_type type, XIDS xids,
500
DBT *key, DBT *val) {
510
next_nesting_level(uint32_t current) {
511
uint32_t rval = current + 1;
513
if (current > 3 && current < MAX_TRANSACTION_RECORDS - 1) {
514
rval = current + random() % 100;
515
if (rval >= MAX_TRANSACTION_RECORDS)
516
rval = MAX_TRANSACTION_RECORDS - 1;
522
generate_committed_for(ULE ule, DBT *val) {
525
ule->uxrs = ule->uxrs_static;
526
ule->uxrs[0].type = XR_INSERT;
527
ule->uxrs[0].vallen = val->size;
528
ule->uxrs[0].valp = val->data;
529
ule->uxrs[0].xid = 0;
533
generate_provpair_for(ULE ule, FT_MSG msg) {
535
XIDS xids = msg->xids;
536
ule->uxrs = ule->uxrs_static;
539
ule->num_puxrs = xids_get_num_xids(xids);
540
uint32_t num_uxrs = ule->num_cuxrs + ule->num_puxrs;
541
ule->uxrs[0].type = XR_DELETE;
542
ule->uxrs[0].vallen = 0;
543
ule->uxrs[0].valp = NULL;
544
ule->uxrs[0].xid = TXNID_NONE;
545
for (level = 1; level < num_uxrs - 1; level++) {
546
ule->uxrs[level].type = XR_PLACEHOLDER;
547
ule->uxrs[level].vallen = 0;
548
ule->uxrs[level].valp = NULL;
549
ule->uxrs[level].xid = xids_get_xid(xids, level-1);
551
ule->uxrs[num_uxrs - 1].type = XR_INSERT;
552
ule->uxrs[num_uxrs - 1].vallen = msg->u.id.val->size;
553
ule->uxrs[num_uxrs - 1].valp = msg->u.id.val->data;
554
ule->uxrs[num_uxrs - 1].xid = xids_get_innermost_xid(xids);
557
//Test all the different things that can happen to a
558
//non-existent leafentry (logical equivalent of a committed delete).
560
test_le_empty_apply(void) {
561
ULE_S ule_initial = ule_committed_delete;
566
uint8_t keybuf[MAX_SIZE];
567
uint8_t valbuf[MAX_SIZE];
570
uint32_t nesting_level;
571
for (keysize = 0; keysize < MAX_SIZE; keysize += (random() % MAX_SIZE) + 1) {
572
for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) {
573
for (nesting_level = 0;
574
nesting_level < MAX_TRANSACTION_RECORDS;
575
nesting_level = next_nesting_level(nesting_level)) {
576
XIDS msg_xids = nested_xids[nesting_level];
577
fillrandom(keybuf, keysize);
578
fillrandom(valbuf, valsize);
579
toku_fill_dbt(&key, keybuf, keysize);
580
toku_fill_dbt(&val, valbuf, valsize);
582
//COMMIT/ABORT is illegal with TXNID 0
583
if (nesting_level > 0) {
584
//Abort/commit of an empty le is an empty le
585
ULE_S ule_expected = ule_committed_delete;
587
msg = msg_init(FT_COMMIT_ANY, msg_xids, &key, &val);
588
test_le_apply(&ule_initial, &msg, &ule_expected);
589
msg = msg_init(FT_COMMIT_BROADCAST_TXN, msg_xids, &key, &val);
590
test_le_apply(&ule_initial, &msg, &ule_expected);
592
msg = msg_init(FT_ABORT_ANY, msg_xids, &key, &val);
593
test_le_apply(&ule_initial, &msg, &ule_expected);
594
msg = msg_init(FT_ABORT_BROADCAST_TXN, msg_xids, &key, &val);
595
test_le_apply(&ule_initial, &msg, &ule_expected);
598
//delete of an empty le is an empty le
599
ULE_S ule_expected = ule_committed_delete;
601
msg = msg_init(FT_DELETE_ANY, msg_xids, &key, &val);
602
test_le_apply(&ule_initial, &msg, &ule_expected);
605
msg = msg_init(FT_INSERT, msg_xids, &key, &val);
607
generate_provpair_for(&ule_expected, &msg);
608
test_le_apply(&ule_initial, &msg, &ule_expected);
611
msg = msg_init(FT_INSERT_NO_OVERWRITE, msg_xids, &key, &val);
613
generate_provpair_for(&ule_expected, &msg);
614
test_le_apply(&ule_initial, &msg, &ule_expected);
622
generate_provdel_for(ULE ule, FT_MSG msg) {
624
XIDS xids = msg->xids;
627
ule->num_puxrs = xids_get_num_xids(xids);
628
uint32_t num_uxrs = ule->num_cuxrs + ule->num_puxrs;
629
ule->uxrs[0].type = XR_INSERT;
630
ule->uxrs[0].vallen = msg->u.id.val->size;
631
ule->uxrs[0].valp = msg->u.id.val->data;
632
ule->uxrs[0].xid = TXNID_NONE;
633
for (level = ule->num_cuxrs; level < ule->num_cuxrs + ule->num_puxrs - 1; level++) {
634
ule->uxrs[level].type = XR_PLACEHOLDER;
635
ule->uxrs[level].vallen = 0;
636
ule->uxrs[level].valp = NULL;
637
ule->uxrs[level].xid = xids_get_xid(xids, level-1);
639
ule->uxrs[num_uxrs - 1].type = XR_DELETE;
640
ule->uxrs[num_uxrs - 1].vallen = 0;
641
ule->uxrs[num_uxrs - 1].valp = NULL;
642
ule->uxrs[num_uxrs - 1].xid = xids_get_innermost_xid(xids);
646
generate_both_for(ULE ule, DBT *oldval, FT_MSG msg) {
648
XIDS xids = msg->xids;
651
ule->num_puxrs = xids_get_num_xids(xids);
652
uint32_t num_uxrs = ule->num_cuxrs + ule->num_puxrs;
653
ule->uxrs[0].type = XR_INSERT;
654
ule->uxrs[0].vallen = oldval->size;
655
ule->uxrs[0].valp = oldval->data;
656
ule->uxrs[0].xid = TXNID_NONE;
657
for (level = ule->num_cuxrs; level < ule->num_cuxrs + ule->num_puxrs - 1; level++) {
658
ule->uxrs[level].type = XR_PLACEHOLDER;
659
ule->uxrs[level].vallen = 0;
660
ule->uxrs[level].valp = NULL;
661
ule->uxrs[level].xid = xids_get_xid(xids, level-1);
663
ule->uxrs[num_uxrs - 1].type = XR_INSERT;
664
ule->uxrs[num_uxrs - 1].vallen = msg->u.id.val->size;
665
ule->uxrs[num_uxrs - 1].valp = msg->u.id.val->data;
666
ule->uxrs[num_uxrs - 1].xid = xids_get_innermost_xid(xids);
669
//Test all the different things that can happen to a
670
//committed leafentry (logical equivalent of a committed insert).
672
test_le_committed_apply(void) {
674
ule_initial.uxrs = ule_initial.uxrs_static;
679
uint8_t valbuf[MAX_SIZE];
681
uint32_t nesting_level;
682
for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) {
683
for (nesting_level = 0;
684
nesting_level < MAX_TRANSACTION_RECORDS;
685
nesting_level = next_nesting_level(nesting_level)) {
686
XIDS msg_xids = nested_xids[nesting_level];
687
fillrandom(valbuf, valsize);
688
toku_fill_dbt(&val, valbuf, valsize);
690
//Generate initial ule
691
generate_committed_for(&ule_initial, &val);
694
//COMMIT/ABORT is illegal with TXNID 0
695
if (nesting_level > 0) {
696
//Commit/abort will not change a committed le
697
ULE_S ule_expected = ule_initial;
698
msg = msg_init(FT_COMMIT_ANY, msg_xids, &key, &val);
699
test_le_apply(&ule_initial, &msg, &ule_expected);
700
msg = msg_init(FT_COMMIT_BROADCAST_TXN, msg_xids, &key, &val);
701
test_le_apply(&ule_initial, &msg, &ule_expected);
703
msg = msg_init(FT_ABORT_ANY, msg_xids, &key, &val);
704
test_le_apply(&ule_initial, &msg, &ule_expected);
705
msg = msg_init(FT_ABORT_BROADCAST_TXN, msg_xids, &key, &val);
706
test_le_apply(&ule_initial, &msg, &ule_expected);
710
msg = msg_init(FT_DELETE_ANY, msg_xids, &key, &val);
712
ule_expected.uxrs = ule_expected.uxrs_static;
713
generate_provdel_for(&ule_expected, &msg);
714
test_le_apply(&ule_initial, &msg, &ule_expected);
718
uint8_t valbuf2[MAX_SIZE];
719
uint32_t valsize2 = random() % MAX_SIZE;
720
fillrandom(valbuf2, valsize2);
722
toku_fill_dbt(&val2, valbuf2, valsize2);
723
msg = msg_init(FT_INSERT, msg_xids, &key, &val2);
725
ule_expected.uxrs = ule_expected.uxrs_static;
726
generate_both_for(&ule_expected, &val, &msg);
727
test_le_apply(&ule_initial, &msg, &ule_expected);
730
//INSERT_NO_OVERWRITE will not change a committed insert
731
ULE_S ule_expected = ule_initial;
732
uint8_t valbuf2[MAX_SIZE];
733
uint32_t valsize2 = random() % MAX_SIZE;
734
fillrandom(valbuf2, valsize2);
736
toku_fill_dbt(&val2, valbuf2, valsize2);
737
msg = msg_init(FT_INSERT_NO_OVERWRITE, msg_xids, &key, &val2);
738
test_le_apply(&ule_initial, &msg, &ule_expected);
745
test_le_apply_messages(void) {
746
test_le_empty_apply();
747
test_le_committed_apply();
750
static bool ule_worth_running_garbage_collection(ULE ule, TXNID oldest_referenced_xid_known) {
752
int r = le_pack(ule, nullptr, 0, nullptr, 0, 0, &le); CKERR(r);
753
invariant_notnull(le);
754
bool worth_running = toku_le_worth_running_garbage_collection(le, oldest_referenced_xid_known);
756
return worth_running;
759
static void test_le_garbage_collection_birdie(void) {
763
uint8_t keybuf[MAX_SIZE];
765
uint8_t valbuf[MAX_SIZE];
767
bool do_garbage_collect;
769
memset(&key, 0, sizeof(key));
770
memset(&val, 0, sizeof(val));
771
fillrandom(keybuf, keysize);
772
fillrandom(valbuf, valsize);
773
memset(&ule, 0, sizeof(ule));
774
ule.uxrs = ule.uxrs_static;
777
// Test garbage collection "worth-doing" heurstic
780
// Garbage collection should not be worth doing on a clean leafentry.
783
ule.uxrs[0].xid = TXNID_NONE;
784
ule.uxrs[0].type = XR_INSERT;
785
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
786
invariant(!do_garbage_collect);
788
// It is worth doing when there is more than one committed entry
791
ule.uxrs[1].xid = 500;
792
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
793
invariant(do_garbage_collect);
795
// It is not worth doing when there is one of each, when the
796
// provisional entry is newer than the oldest known referenced xid
799
ule.uxrs[1].xid = 1500;
800
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
801
invariant(!do_garbage_collect);
802
ule.uxrs[1].xid = 200;
803
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
804
invariant(!do_garbage_collect);
806
// It is not worth doing when there is only one committed entry,
807
// multiple provisional entries, but the outermost entry is newer.
810
ule.uxrs[1].xid = 201;
811
ule.uxrs[2].xid = 206;
812
ule.uxrs[3].xid = 215;
813
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
814
invariant(!do_garbage_collect);
816
// It is worth doing when the above scenario has an outermost entry
817
// older than the oldest known, even if its children seem newer.
818
// this children must have commit because the parent is not live.
821
ule.uxrs[1].xid = 190;
822
ule.uxrs[2].xid = 206;
823
ule.uxrs[3].xid = 215;
824
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
825
invariant(do_garbage_collect);
827
// It is worth doing when there is more than one committed entry,
828
// even if a provisional entry exists that is newer than the
829
// oldest known refrenced xid
832
ule.uxrs[1].xid = 499;
833
ule.uxrs[2].xid = 500;
834
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
835
invariant(do_garbage_collect);
837
// It is worth doing when there is one of each, and the provisional
838
// entry is older than the oldest known referenced xid
841
ule.uxrs[1].xid = 199;
842
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
843
invariant(do_garbage_collect);
845
// It is definately worth doing when the above case is true
846
// and there is more than one provisional entry.
849
ule.uxrs[1].xid = 150;
850
ule.uxrs[2].xid = 175;
851
do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
852
invariant(do_garbage_collect);
855
static void test_le_optimize(void) {
861
uint8_t keybuf[MAX_SIZE];
863
uint8_t valbuf[MAX_SIZE];
865
ule_initial.uxrs = ule_initial.uxrs_static;
866
ule_expected.uxrs = ule_expected.uxrs_static;
867
TXNID optimize_txnid = 1000;
868
memset(&key, 0, sizeof(key));
869
memset(&val, 0, sizeof(val));
870
XIDS root_xids = xids_get_root_xids();
872
int r = xids_create_child(root_xids, &msg_xids, optimize_txnid);
874
msg = msg_init(FT_OPTIMIZE, msg_xids, &key, &val);
879
fillrandom(keybuf, keysize);
880
fillrandom(valbuf, valsize);
883
// test a clean leafentry has no effect
885
ule_initial.num_cuxrs = 1;
886
ule_initial.num_puxrs = 0;
887
ule_initial.uxrs[0].type = XR_INSERT;
888
ule_initial.uxrs[0].xid = TXNID_NONE;
889
ule_initial.uxrs[0].vallen = valsize;
890
ule_initial.uxrs[0].valp = valbuf;
892
ule_expected.num_cuxrs = 1;
893
ule_expected.num_puxrs = 0;
894
ule_expected.uxrs[0].type = XR_INSERT;
895
ule_expected.uxrs[0].xid = TXNID_NONE;
896
ule_expected.uxrs[0].vallen = valsize;
897
ule_expected.uxrs[0].valp = valbuf;
899
test_msg_modify_ule(&ule_initial,&msg);
900
verify_ule_equal(&ule_initial,&ule_expected);
903
// add another committed entry and ensure no effect
905
ule_initial.num_cuxrs = 2;
906
ule_initial.uxrs[1].type = XR_DELETE;
907
ule_initial.uxrs[1].xid = 500;
908
ule_initial.uxrs[1].vallen = 0;
909
ule_initial.uxrs[1].valp = NULL;
911
ule_expected.num_cuxrs = 2;
912
ule_expected.uxrs[1].type = XR_DELETE;
913
ule_expected.uxrs[1].xid = 500;
914
ule_expected.uxrs[1].vallen = 0;
915
ule_expected.uxrs[1].valp = NULL;
917
test_msg_modify_ule(&ule_initial,&msg);
918
verify_ule_equal(&ule_initial,&ule_expected);
921
// now test when there is one provisional, three cases, after, equal, and before FT_OPTIMIZE's transaction
923
ule_initial.num_cuxrs = 1;
924
ule_initial.num_puxrs = 1;
925
ule_initial.uxrs[1].xid = 1500;
927
ule_expected.num_cuxrs = 1;
928
ule_expected.num_puxrs = 1;
929
ule_expected.uxrs[1].xid = 1500;
930
test_msg_modify_ule(&ule_initial,&msg);
931
verify_ule_equal(&ule_initial,&ule_expected);
933
ule_initial.uxrs[1].xid = 1000;
934
ule_expected.uxrs[1].xid = 1000;
935
test_msg_modify_ule(&ule_initial,&msg);
936
verify_ule_equal(&ule_initial,&ule_expected);
938
ule_initial.uxrs[1].xid = 500;
939
ule_expected.uxrs[1].xid = 500;
940
ule_expected.num_cuxrs = 2;
941
ule_expected.num_puxrs = 0;
942
test_msg_modify_ule(&ule_initial,&msg);
943
verify_ule_equal(&ule_initial,&ule_expected);
946
// now test cases with two provisional
948
ule_initial.num_cuxrs = 1;
949
ule_initial.num_puxrs = 2;
950
ule_expected.num_cuxrs = 1;
951
ule_expected.num_puxrs = 2;
953
ule_initial.uxrs[2].type = XR_INSERT;
954
ule_initial.uxrs[2].xid = 1500;
955
ule_initial.uxrs[2].vallen = valsize;
956
ule_initial.uxrs[2].valp = valbuf;
957
ule_initial.uxrs[1].xid = 1200;
959
ule_expected.uxrs[2].type = XR_INSERT;
960
ule_expected.uxrs[2].xid = 1500;
961
ule_expected.uxrs[2].vallen = valsize;
962
ule_expected.uxrs[2].valp = valbuf;
963
ule_expected.uxrs[1].xid = 1200;
964
test_msg_modify_ule(&ule_initial,&msg);
965
verify_ule_equal(&ule_initial,&ule_expected);
967
ule_initial.uxrs[1].xid = 1000;
968
ule_expected.uxrs[1].xid = 1000;
969
test_msg_modify_ule(&ule_initial,&msg);
970
verify_ule_equal(&ule_initial,&ule_expected);
972
ule_initial.uxrs[1].xid = 800;
973
ule_expected.uxrs[1].xid = 800;
974
ule_expected.num_cuxrs = 2;
975
ule_expected.num_puxrs = 0;
976
ule_expected.uxrs[1].type = ule_initial.uxrs[2].type;
977
ule_expected.uxrs[1].valp = ule_initial.uxrs[2].valp;
978
ule_expected.uxrs[1].vallen = ule_initial.uxrs[2].vallen;
979
test_msg_modify_ule(&ule_initial,&msg);
980
verify_ule_equal(&ule_initial,&ule_expected);
983
xids_destroy(&msg_xids);
984
xids_destroy(&root_xids);
988
// Will probably have to expose ULE_S definition
989
// - Check memsize function is correct
990
// - Assert == disksize (almost useless, but go ahead)
991
// - Check standard accessors
992
// - le_latest_val_and_len
994
// - le_latest_vallen
996
// - le_innermost_inserted_val_and_len
997
// - le_innermost_inserted_val
998
// - le_innermost_inserted_vallen
999
// - Check le_outermost_uncommitted_xid
1000
// - Check le_latest_is_del
1001
// - Check unpack+pack memcmps equal
1002
// - Check exact memory expected (including size) for various leafentry types.
1003
// - Check apply_msg logic
1004
// - Known start, known expected.. various types.
1005
// - Go through test-leafentry10.c
1006
// - Verify we have tests for all analogous stuff.
1010
// verify pack+unpack is no-op
1011
// verify unpack+pack is no-op
1013
// Test apply_msg logic
1014
// i.e. start with LE, apply message
1015
// in parallel, construct the expected ULE manually, and pack that
1016
// Compare the two results
1017
// Test full_promote
1022
nested_xids[0] = xids_get_root_xids();
1023
for (i = 1; i < MAX_TRANSACTION_RECORDS; i++) {
1024
int r = xids_create_child(nested_xids[i-1], &nested_xids[i], i * 37 + random() % 36);
1030
destroy_xids(void) {
1032
for (i = 0; i < MAX_TRANSACTION_RECORDS; i++) {
1033
xids_destroy(&nested_xids[i]);
1038
test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) {
1039
srandom(7); //Arbitrary seed.
1043
test_le_apply_messages();
1045
test_le_garbage_collection_birdie();