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 <toku_portability.h>
40 #include <string.h>
41 
42 #include "test.h"
43 
44 #include "ft/ule.h"
45 #include "ft/ule-internal.h"
46 
47 enum {MAX_SIZE = 256};
48 static XIDS nested_xids[MAX_TRANSACTION_RECORDS];
49 
50 static void
verify_ule_equal(ULE a,ULE b)51 verify_ule_equal(ULE a, ULE b) {
52     assert(a->num_cuxrs > 0);
53     assert(a->num_puxrs < MAX_TRANSACTION_RECORDS);
54     assert(a->num_cuxrs == b->num_cuxrs);
55     assert(a->num_puxrs == b->num_puxrs);
56     uint32_t i;
57     for (i = 0; i < (a->num_cuxrs + a->num_puxrs); i++) {
58         assert(a->uxrs[i].type == b->uxrs[i].type);
59         assert(a->uxrs[i].xid  == b->uxrs[i].xid);
60         if (a->uxrs[i].type == XR_INSERT) {
61             assert(a->uxrs[i].vallen  == b->uxrs[i].vallen);
62             assert(memcmp(a->uxrs[i].valp, b->uxrs[i].valp, a->uxrs[i].vallen) == 0);
63         }
64     }
65 }
66 
67 static void
verify_le_equal(LEAFENTRY a,LEAFENTRY b)68 verify_le_equal(LEAFENTRY a, LEAFENTRY b) {
69     if (a==NULL) assert(b==NULL);
70     else {
71         assert(b!=NULL);
72 
73         size_t size = leafentry_memsize(a);
74         assert(size==leafentry_memsize(b));
75 
76         assert(memcmp(a, b, size) == 0);
77 
78         ULE_S ule_a;
79         ULE_S ule_b;
80 
81         le_unpack(&ule_a, a);
82         le_unpack(&ule_b, b);
83         verify_ule_equal(&ule_a, &ule_b);
84         ule_cleanup(&ule_a);
85         ule_cleanup(&ule_b);
86     }
87 }
88 
89 static void
fillrandom(uint8_t buf[MAX_SIZE],uint32_t length)90 fillrandom(uint8_t buf[MAX_SIZE], uint32_t length) {
91     assert(length < MAX_SIZE);
92     uint32_t i;
93     for (i = 0; i < length; i++) {
94         buf[i] = random() & 0xFF;
95     }
96 }
97 
98 static void
test_le_offset_is(LEAFENTRY le,void * field,size_t expected_offset)99 test_le_offset_is(LEAFENTRY le, void *field, size_t expected_offset) {
100     size_t le_address    = (size_t) le;
101     size_t field_address = (size_t) field;
102     assert(field_address >= le_address);
103     size_t actual_offset = field_address - le_address;
104     assert(actual_offset == expected_offset);
105 }
106 
107 //Fixed offsets in a packed leafentry.
108 enum {
109     LE_OFFSET_NUM      = 0,
110     LE_OFFSET_VARIABLE = 1+LE_OFFSET_NUM
111 };
112 
113 static void
test_le_fixed_offsets(void)114 test_le_fixed_offsets (void) {
115     LEAFENTRY XMALLOC(le);
116     test_le_offset_is(le, &le->type,                       LE_OFFSET_NUM);
117     toku_free(le);
118 }
119 
120 //Fixed offsets in a leafentry with no uncommitted transaction records.
121 //(Note, there is no type required.)
122 enum {
123     LE_COMMITTED_OFFSET_VALLEN = LE_OFFSET_VARIABLE,
124     LE_COMMITTED_OFFSET_VAL    = 4 + LE_COMMITTED_OFFSET_VALLEN
125 };
126 
127 static void
test_le_committed_offsets(void)128 test_le_committed_offsets (void) {
129     LEAFENTRY XMALLOC(le);
130     test_le_offset_is(le, &le->u.clean.vallen, LE_COMMITTED_OFFSET_VALLEN);
131     test_le_offset_is(le, &le->u.clean.val, LE_COMMITTED_OFFSET_VAL);
132     toku_free(le);
133 }
134 
135 //Fixed offsets in a leafentry with uncommitted transaction records.
136 enum {
137     LE_MVCC_OFFSET_NUM_CUXRS   =  LE_OFFSET_VARIABLE, //Type of innermost record
138     LE_MVCC_OFFSET_NUM_PUXRS    = 4+LE_MVCC_OFFSET_NUM_CUXRS, //XID of outermost noncommitted record
139     LE_MVCC_OFFSET_XRS    = 1+LE_MVCC_OFFSET_NUM_PUXRS
140 };
141 
142 static void
test_le_provisional_offsets(void)143 test_le_provisional_offsets (void) {
144     LEAFENTRY XMALLOC(le);
145     test_le_offset_is(le, &le->u.mvcc.num_cxrs,            LE_MVCC_OFFSET_NUM_CUXRS);
146     test_le_offset_is(le, &le->u.mvcc.num_pxrs, LE_MVCC_OFFSET_NUM_PUXRS);
147     test_le_offset_is(le, &le->u.mvcc.xrs,               LE_MVCC_OFFSET_XRS);
148     toku_free(le);
149 }
150 
151 //We use a packed struct to represent a leafentry.
152 //We want to make sure the compiler correctly represents the offsets.
153 //This test verifies all offsets in a packed leafentry correspond to the required memory format.
154 static void
test_le_offsets(void)155 test_le_offsets (void) {
156     test_le_fixed_offsets();
157     test_le_committed_offsets();
158     test_le_provisional_offsets();
159 }
160 
161 static void
test_ule_packs_to_nothing(ULE ule)162 test_ule_packs_to_nothing (ULE ule) {
163     LEAFENTRY le;
164     int r = le_pack(ule, NULL, 0, NULL, 0, 0, 0, &le, nullptr);
165     assert(r==0);
166     assert(le==NULL);
167 }
168 
169 //A leafentry must contain at least one 'insert' (all deletes means the leafentry
170 //should not exist).
171 //Verify that 'le_pack' of any set of all deletes ends up not creating a leafentry.
172 static void
test_le_empty_packs_to_nothing(void)173 test_le_empty_packs_to_nothing (void) {
174     ULE_S ule;
175     ule.uxrs = ule.uxrs_static;
176 
177     //Set up defaults.
178     int committed;
179     for (committed = 1; committed < MAX_TRANSACTION_RECORDS; committed++) {
180         int32_t num_xrs;
181 
182         for (num_xrs = committed; num_xrs < MAX_TRANSACTION_RECORDS; num_xrs++) {
183             ule.num_cuxrs = committed;
184             ule.num_puxrs = num_xrs - committed;
185             if (num_xrs == 1) {
186                 ule.uxrs[num_xrs-1].xid    = TXNID_NONE;
187             }
188             else {
189                 ule.uxrs[num_xrs-1].xid    = ule.uxrs[num_xrs-2].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing
190             }
191             ule.uxrs[num_xrs-1].type = XR_DELETE;
192             test_ule_packs_to_nothing(&ule);
193             if (num_xrs > 2 && num_xrs > committed && num_xrs % 4) {
194                 //Set some of them to placeholders instead of deletes
195                 ule.uxrs[num_xrs-2].type = XR_PLACEHOLDER;
196             }
197             test_ule_packs_to_nothing(&ule);
198         }
199     }
200 
201 }
202 
203 static void
le_verify_accessors(LEAFENTRY le,ULE ule,size_t pre_calculated_memsize)204 le_verify_accessors(LEAFENTRY le, ULE ule, size_t pre_calculated_memsize) {
205     assert(le);
206     assert(ule->num_cuxrs > 0);
207     assert(ule->num_puxrs <= MAX_TRANSACTION_RECORDS);
208     assert(ule->uxrs[ule->num_cuxrs + ule->num_puxrs-1].type != XR_PLACEHOLDER);
209     //Extract expected values from ULE
210     size_t memsize  = le_memsize_from_ule(ule);
211     size_t num_uxrs = ule->num_cuxrs + ule->num_puxrs;
212 
213     void *latest_val        = ule->uxrs[num_uxrs -1].type == XR_DELETE ? NULL : ule->uxrs[num_uxrs -1].valp;
214     uint32_t latest_vallen = ule->uxrs[num_uxrs -1].type == XR_DELETE ? 0    : ule->uxrs[num_uxrs -1].vallen;
215     {
216         int i;
217         for (i = num_uxrs - 1; i >= 0; i--) {
218             if (ule->uxrs[i].type == XR_INSERT) {
219                 goto found_insert;
220             }
221         }
222         assert(false);
223     }
224 found_insert:;
225     TXNID outermost_uncommitted_xid = ule->num_puxrs == 0 ? TXNID_NONE : ule->uxrs[ule->num_cuxrs].xid;
226     int   is_provdel = ule->uxrs[num_uxrs-1].type == XR_DELETE;
227 
228     assert(le!=NULL);
229     //Verify all accessors
230     assert(memsize  == pre_calculated_memsize);
231     assert(memsize  == leafentry_memsize(le));
232     {
233         uint32_t test_vallen;
234         void*     test_valp = le_latest_val_and_len(le, &test_vallen);
235         if (latest_val != NULL) assert(test_valp != latest_val);
236         assert(test_vallen == latest_vallen);
237         assert(memcmp(test_valp, latest_val, test_vallen) == 0);
238         assert(le_latest_val(le)    == test_valp);
239         assert(le_latest_vallen(le) == test_vallen);
240     }
241     {
242         assert(le_outermost_uncommitted_xid(le) == outermost_uncommitted_xid);
243     }
244     {
245         assert((le_latest_is_del(le)==0) == (is_provdel==0));
246     }
247 }
248 
249 
250 
251 static void
test_le_pack_committed(void)252 test_le_pack_committed (void) {
253     ULE_S ule;
254     ule.uxrs = ule.uxrs_static;
255 
256     uint8_t val[MAX_SIZE];
257     uint32_t valsize;
258     for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) {
259         fillrandom(val, valsize);
260 
261         ule.num_cuxrs       = 1;
262         ule.num_puxrs       = 0;
263         ule.uxrs[0].type   = XR_INSERT;
264         ule.uxrs[0].xid    = 0;
265         ule.uxrs[0].valp   = val;
266         ule.uxrs[0].vallen = valsize;
267 
268         size_t memsize;
269         LEAFENTRY le;
270         int r = le_pack(&ule, nullptr, 0, nullptr, 0, 0, 0, &le, nullptr);
271         assert(r==0);
272         assert(le!=NULL);
273         memsize = le_memsize_from_ule(&ule);
274         le_verify_accessors(le, &ule, memsize);
275         ULE_S tmp_ule;
276         le_unpack(&tmp_ule, le);
277         verify_ule_equal(&ule, &tmp_ule);
278         LEAFENTRY tmp_le;
279         size_t    tmp_memsize;
280         r = le_pack(&tmp_ule, nullptr, 0, nullptr, 0, 0, 0, &tmp_le, nullptr);
281         tmp_memsize = le_memsize_from_ule(&tmp_ule);
282         assert(r==0);
283         assert(tmp_memsize == memsize);
284         assert(memcmp(le, tmp_le, memsize) == 0);
285         le_verify_accessors(tmp_le, &tmp_ule, tmp_memsize);
286 
287         toku_free(tmp_le);
288         toku_free(le);
289         ule_cleanup(&tmp_ule);
290     }
291 }
292 
293 static void
test_le_pack_uncommitted(uint8_t committed_type,uint8_t prov_type,int num_placeholders)294 test_le_pack_uncommitted (uint8_t committed_type, uint8_t prov_type, int num_placeholders) {
295     ULE_S ule;
296     ule.uxrs = ule.uxrs_static;
297     assert(num_placeholders >= 0);
298 
299     uint8_t cval[MAX_SIZE];
300     uint8_t pval[MAX_SIZE];
301     uint32_t cvalsize;
302     uint32_t pvalsize;
303     for (cvalsize = 0; cvalsize < MAX_SIZE; cvalsize += (random() % MAX_SIZE) + 1) {
304         pvalsize = (cvalsize + random()) % MAX_SIZE;
305         if (committed_type == XR_INSERT)
306             fillrandom(cval, cvalsize);
307         if (prov_type == XR_INSERT)
308             fillrandom(pval, pvalsize);
309         ule.uxrs[0].type   = committed_type;
310         ule.uxrs[0].xid    = TXNID_NONE;
311         ule.uxrs[0].vallen = cvalsize;
312         ule.uxrs[0].valp   = cval;
313         ule.num_cuxrs       = 1;
314         ule.num_puxrs       = 1 + num_placeholders;
315 
316         uint32_t idx;
317         for (idx = 1; idx <= (uint32_t)num_placeholders; idx++) {
318             ule.uxrs[idx].type = XR_PLACEHOLDER;
319             ule.uxrs[idx].xid  = ule.uxrs[idx-1].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing
320         }
321         ule.uxrs[idx].xid  = ule.uxrs[idx-1].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing
322         ule.uxrs[idx].type   = prov_type;
323         ule.uxrs[idx].vallen = pvalsize;
324         ule.uxrs[idx].valp   = pval;
325 
326         size_t memsize;
327         LEAFENTRY le;
328         int r = le_pack(&ule, nullptr, 0, nullptr, 0, 0, 0, &le, nullptr);
329         assert(r==0);
330         assert(le!=NULL);
331         memsize = le_memsize_from_ule(&ule);
332         le_verify_accessors(le, &ule, memsize);
333         ULE_S tmp_ule;
334         le_unpack(&tmp_ule, le);
335         verify_ule_equal(&ule, &tmp_ule);
336         LEAFENTRY tmp_le;
337         size_t    tmp_memsize;
338         r = le_pack(&tmp_ule, nullptr, 0, nullptr, 0, 0, 0, &tmp_le, nullptr);
339         tmp_memsize = le_memsize_from_ule(&tmp_ule);
340         assert(r==0);
341         assert(tmp_memsize == memsize);
342         assert(memcmp(le, tmp_le, memsize) == 0);
343         le_verify_accessors(tmp_le, &tmp_ule, tmp_memsize);
344 
345         toku_free(tmp_le);
346         toku_free(le);
347         ule_cleanup(&tmp_ule);
348     }
349 }
350 
351 static void
test_le_pack_provpair(int num_placeholders)352 test_le_pack_provpair (int num_placeholders) {
353     test_le_pack_uncommitted(XR_DELETE, XR_INSERT, num_placeholders);
354 }
355 
356 static void
test_le_pack_provdel(int num_placeholders)357 test_le_pack_provdel (int num_placeholders) {
358     test_le_pack_uncommitted(XR_INSERT, XR_DELETE, num_placeholders);
359 }
360 
361 static void
test_le_pack_both(int num_placeholders)362 test_le_pack_both (int num_placeholders) {
363     test_le_pack_uncommitted(XR_INSERT, XR_INSERT, num_placeholders);
364 }
365 
366 //Test of PACK
367 //  Committed leafentry
368 //      delete -> nothing (le_empty_packs_to_nothing)
369 //      insert
370 //          make key/val have diff lengths/content
371 //  Uncommitted
372 //      committed delete
373 //          followed by placeholder*, delete (le_empty_packs_to_nothing)
374 //          followed by placeholder*, insert
375 //      committed insert
376 //          followed by placeholder*, delete
377 //          followed by placeholder*, insert
378 //
379 //  placeholder* is 0,1, or 2 placeholders
380 static void
test_le_pack(void)381 test_le_pack (void) {
382     test_le_empty_packs_to_nothing();
383     test_le_pack_committed();
384     int i;
385     for (i = 0; i < 3; i++) {
386         test_le_pack_provpair(i);
387         test_le_pack_provdel(i);
388         test_le_pack_both(i);
389     }
390 }
391 
392 static void
test_le_apply(ULE ule_initial,const ft_msg & msg,ULE ule_expected)393 test_le_apply(ULE ule_initial, const ft_msg &msg, ULE ule_expected) {
394     int r;
395     LEAFENTRY le_initial;
396     LEAFENTRY le_expected;
397     LEAFENTRY le_result;
398 
399     r = le_pack(ule_initial, nullptr, 0, nullptr, 0, 0, 0, &le_initial, nullptr);
400     CKERR(r);
401 
402     size_t result_memsize = 0;
403     int64_t ignoreme;
404     txn_gc_info gc_info(nullptr, TXNID_NONE, TXNID_NONE, true);
405     toku_le_apply_msg(msg,
406                       le_initial,
407                       nullptr,
408                       0,
409                       0,
410                       &gc_info,
411                       &le_result,
412                       &ignoreme);
413     if (le_result) {
414         result_memsize = leafentry_memsize(le_result);
415         le_verify_accessors(le_result, ule_expected, result_memsize);
416     }
417 
418     size_t expected_memsize = 0;
419     r = le_pack(ule_expected, nullptr, 0, nullptr, 0, 0, 0, &le_expected, nullptr);
420     CKERR(r);
421     if (le_expected) {
422         expected_memsize = leafentry_memsize(le_expected);
423     }
424 
425 
426     verify_le_equal(le_result, le_expected);
427     if (le_result && le_expected) {
428         assert(result_memsize  == expected_memsize);
429     }
430     if (le_initial)  toku_free(le_initial);
431     if (le_result)   toku_free(le_result);
432     if (le_expected) toku_free(le_expected);
433 }
434 
435 static const ULE_S ule_committed_delete = {
436     .num_puxrs = 0,
437     .num_cuxrs = 1,
438     .uxrs_static = {{
439         .type   = XR_DELETE,
440         .vallen = 0,
441         .valp   = NULL,
442         .xid    = 0
443     }},
444     .uxrs = (UXR_S *)ule_committed_delete.uxrs_static
445 };
446 
447 static uint32_t
next_nesting_level(uint32_t current)448 next_nesting_level(uint32_t current) {
449     uint32_t rval = current + 1;
450 
451     if (current > 3 && current < MAX_TRANSACTION_RECORDS - 1) {
452         rval = current + random() % 100;
453         if (rval >= MAX_TRANSACTION_RECORDS)
454             rval = MAX_TRANSACTION_RECORDS - 1;
455     }
456     return rval;
457 }
458 
459 static void
generate_committed_for(ULE ule,DBT * val)460 generate_committed_for(ULE ule, DBT *val) {
461     ule->num_cuxrs = 1;
462     ule->num_puxrs = 0;
463     ule->uxrs = ule->uxrs_static;
464     ule->uxrs[0].type   = XR_INSERT;
465     ule->uxrs[0].vallen = val->size;
466     ule->uxrs[0].valp   = val->data;
467     ule->uxrs[0].xid    = 0;
468 }
469 
470 static void
generate_provpair_for(ULE ule,const ft_msg & msg)471 generate_provpair_for(ULE ule, const ft_msg &msg) {
472     uint32_t level;
473     XIDS xids = msg.xids();
474     ule->uxrs = ule->uxrs_static;
475 
476     ule->num_cuxrs = 1;
477     ule->num_puxrs = toku_xids_get_num_xids(xids);
478     uint32_t num_uxrs = ule->num_cuxrs + ule->num_puxrs;
479     ule->uxrs[0].type   = XR_DELETE;
480     ule->uxrs[0].vallen = 0;
481     ule->uxrs[0].valp   = NULL;
482     ule->uxrs[0].xid    = TXNID_NONE;
483     for (level = 1; level < num_uxrs - 1; level++) {
484         ule->uxrs[level].type   = XR_PLACEHOLDER;
485         ule->uxrs[level].vallen = 0;
486         ule->uxrs[level].valp   = NULL;
487         ule->uxrs[level].xid    = toku_xids_get_xid(xids, level-1);
488     }
489     ule->uxrs[num_uxrs - 1].type   = XR_INSERT;
490     ule->uxrs[num_uxrs - 1].vallen = msg.vdbt()->size;
491     ule->uxrs[num_uxrs - 1].valp   = msg.vdbt()->data;
492     ule->uxrs[num_uxrs - 1].xid    = toku_xids_get_innermost_xid(xids);
493 }
494 
495 //Test all the different things that can happen to a
496 //non-existent leafentry (logical equivalent of a committed delete).
497 static void
test_le_empty_apply(void)498 test_le_empty_apply(void) {
499     ULE_S ule_initial        = ule_committed_delete;
500 
501     DBT key;
502     DBT val;
503     uint8_t keybuf[MAX_SIZE];
504     uint8_t valbuf[MAX_SIZE];
505     uint32_t keysize;
506     uint32_t valsize;
507     uint32_t  nesting_level;
508     for (keysize = 0; keysize < MAX_SIZE; keysize += (random() % MAX_SIZE) + 1) {
509         for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) {
510             for (nesting_level = 0;
511                  nesting_level < MAX_TRANSACTION_RECORDS;
512                  nesting_level = next_nesting_level(nesting_level)) {
513                 XIDS msg_xids = nested_xids[nesting_level];
514                 fillrandom(keybuf, keysize);
515                 fillrandom(valbuf, valsize);
516                 toku_fill_dbt(&key, keybuf, keysize);
517                 toku_fill_dbt(&val, valbuf, valsize);
518 
519                 //COMMIT/ABORT is illegal with TXNID 0
520                 if (nesting_level > 0) {
521                     //Abort/commit of an empty le is an empty le
522                     ULE_S ule_expected = ule_committed_delete;
523 
524                     {
525                         ft_msg msg(&key, &val, FT_COMMIT_ANY, ZERO_MSN, msg_xids);
526                         test_le_apply(&ule_initial, msg, &ule_expected);
527                     }
528                     {
529                         ft_msg msg(&key, &val, FT_COMMIT_BROADCAST_TXN, ZERO_MSN, msg_xids);
530                         test_le_apply(&ule_initial, msg, &ule_expected);
531                     }
532                     {
533                         ft_msg msg(&key, &val, FT_ABORT_ANY, ZERO_MSN, msg_xids);
534                         test_le_apply(&ule_initial, msg, &ule_expected);
535                     }
536                     {
537                         ft_msg msg(&key, &val, FT_ABORT_BROADCAST_TXN, ZERO_MSN, msg_xids);
538                         test_le_apply(&ule_initial, msg, &ule_expected);
539                     }
540                 }
541                 {
542                     //delete of an empty le is an empty le
543                     ULE_S ule_expected = ule_committed_delete;
544 
545                     ft_msg msg(&key, &val, FT_DELETE_ANY, ZERO_MSN, msg_xids);
546                     test_le_apply(&ule_initial, msg, &ule_expected);
547                 }
548                 {
549                     ft_msg msg(&key, &val, FT_INSERT, ZERO_MSN, msg_xids);
550                     ULE_S ule_expected;
551                     generate_provpair_for(&ule_expected, msg);
552                     test_le_apply(&ule_initial, msg, &ule_expected);
553                 }
554                 {
555                     ft_msg msg(&key, &val, FT_INSERT_NO_OVERWRITE, ZERO_MSN, msg_xids);
556                     ULE_S ule_expected;
557                     generate_provpair_for(&ule_expected, msg);
558                     test_le_apply(&ule_initial, msg, &ule_expected);
559                 }
560             }
561         }
562     }
563 }
564 
565 static void
generate_provdel_for(ULE ule,const ft_msg & msg)566 generate_provdel_for(ULE ule, const ft_msg &msg) {
567     uint32_t level;
568     XIDS xids = msg.xids();
569 
570     ule->num_cuxrs = 1;
571     ule->num_puxrs = toku_xids_get_num_xids(xids);
572     uint32_t num_uxrs = ule->num_cuxrs + ule->num_puxrs;
573     ule->uxrs[0].type   = XR_INSERT;
574     ule->uxrs[0].vallen = msg.vdbt()->size;
575     ule->uxrs[0].valp   = msg.vdbt()->data;
576     ule->uxrs[0].xid    = TXNID_NONE;
577     for (level = ule->num_cuxrs; level < ule->num_cuxrs + ule->num_puxrs - 1; level++) {
578         ule->uxrs[level].type   = XR_PLACEHOLDER;
579         ule->uxrs[level].vallen = 0;
580         ule->uxrs[level].valp   = NULL;
581         ule->uxrs[level].xid    = toku_xids_get_xid(xids, level-1);
582     }
583     ule->uxrs[num_uxrs - 1].type   = XR_DELETE;
584     ule->uxrs[num_uxrs - 1].vallen = 0;
585     ule->uxrs[num_uxrs - 1].valp   = NULL;
586     ule->uxrs[num_uxrs - 1].xid    = toku_xids_get_innermost_xid(xids);
587 }
588 
589 static void
generate_both_for(ULE ule,DBT * oldval,const ft_msg & msg)590 generate_both_for(ULE ule, DBT *oldval, const ft_msg &msg) {
591     uint32_t level;
592     XIDS xids = msg.xids();
593 
594     ule->num_cuxrs = 1;
595     ule->num_puxrs = toku_xids_get_num_xids(xids);
596     uint32_t num_uxrs = ule->num_cuxrs + ule->num_puxrs;
597     ule->uxrs[0].type   = XR_INSERT;
598     ule->uxrs[0].vallen = oldval->size;
599     ule->uxrs[0].valp   = oldval->data;
600     ule->uxrs[0].xid    = TXNID_NONE;
601     for (level = ule->num_cuxrs; level < ule->num_cuxrs + ule->num_puxrs - 1; level++) {
602         ule->uxrs[level].type   = XR_PLACEHOLDER;
603         ule->uxrs[level].vallen = 0;
604         ule->uxrs[level].valp   = NULL;
605         ule->uxrs[level].xid    = toku_xids_get_xid(xids, level-1);
606     }
607     ule->uxrs[num_uxrs - 1].type   = XR_INSERT;
608     ule->uxrs[num_uxrs - 1].vallen = msg.vdbt()->size;
609     ule->uxrs[num_uxrs - 1].valp   = msg.vdbt()->data;
610     ule->uxrs[num_uxrs - 1].xid    = toku_xids_get_innermost_xid(xids);
611 }
612 
613 //Test all the different things that can happen to a
614 //committed leafentry (logical equivalent of a committed insert).
615 static void
test_le_committed_apply(void)616 test_le_committed_apply(void) {
617     ULE_S ule_initial;
618     ule_initial.uxrs = ule_initial.uxrs_static;
619 
620     DBT key;
621     DBT val;
622     uint8_t valbuf[MAX_SIZE];
623     uint32_t valsize;
624     uint32_t  nesting_level;
625     for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) {
626         for (nesting_level = 0;
627              nesting_level < MAX_TRANSACTION_RECORDS;
628              nesting_level = next_nesting_level(nesting_level)) {
629             XIDS msg_xids = nested_xids[nesting_level];
630             fillrandom(valbuf, valsize);
631             toku_fill_dbt(&val, valbuf, valsize);
632 
633             //Generate initial ule
634             generate_committed_for(&ule_initial, &val);
635 
636 
637             //COMMIT/ABORT is illegal with TXNID 0
638             if (nesting_level > 0) {
639                 //Commit/abort will not change a committed le
640                 ULE_S ule_expected = ule_initial;
641                 {
642                     ft_msg msg(&key, &val, FT_COMMIT_ANY, ZERO_MSN, msg_xids);
643                     test_le_apply(&ule_initial, msg, &ule_expected);
644                 }
645                 {
646                     ft_msg msg(&key, &val, FT_COMMIT_BROADCAST_TXN, ZERO_MSN, msg_xids);
647                     test_le_apply(&ule_initial, msg, &ule_expected);
648                 }
649                 {
650                     ft_msg msg(&key, &val, FT_ABORT_ANY, ZERO_MSN, msg_xids);
651                     test_le_apply(&ule_initial, msg, &ule_expected);
652                 }
653                 {
654                     ft_msg msg(&key, &val, FT_ABORT_BROADCAST_TXN, ZERO_MSN, msg_xids);
655                     test_le_apply(&ule_initial, msg, &ule_expected);
656                 }
657             }
658 
659             {
660                 ft_msg msg(&key, &val, FT_DELETE_ANY, ZERO_MSN, msg_xids);
661                 ULE_S ule_expected;
662                 ule_expected.uxrs = ule_expected.uxrs_static;
663                 generate_provdel_for(&ule_expected, msg);
664                 test_le_apply(&ule_initial, msg, &ule_expected);
665             }
666 
667             {
668                 uint8_t valbuf2[MAX_SIZE];
669                 uint32_t valsize2 = random() % MAX_SIZE;
670                 fillrandom(valbuf2, valsize2);
671                 DBT val2;
672                 toku_fill_dbt(&val2, valbuf2, valsize2);
673                 ft_msg msg(&key, &val2, FT_INSERT, ZERO_MSN, msg_xids);
674                 ULE_S ule_expected;
675                 ule_expected.uxrs = ule_expected.uxrs_static;
676                 generate_both_for(&ule_expected, &val, msg);
677                 test_le_apply(&ule_initial, msg, &ule_expected);
678             }
679             {
680                 //INSERT_NO_OVERWRITE will not change a committed insert
681                 ULE_S ule_expected = ule_initial;
682                 uint8_t valbuf2[MAX_SIZE];
683                 uint32_t valsize2 = random() % MAX_SIZE;
684                 fillrandom(valbuf2, valsize2);
685                 DBT val2;
686                 toku_fill_dbt(&val2, valbuf2, valsize2);
687                 ft_msg msg(&key, &val2, FT_INSERT_NO_OVERWRITE, ZERO_MSN, msg_xids);
688                 test_le_apply(&ule_initial, msg, &ule_expected);
689             }
690         }
691     }
692 }
693 
694 static void
test_le_apply_messages(void)695 test_le_apply_messages(void) {
696     test_le_empty_apply();
697     test_le_committed_apply();
698 }
699 
ule_worth_running_garbage_collection(ULE ule,TXNID oldest_referenced_xid_known)700 static bool ule_worth_running_garbage_collection(ULE ule, TXNID oldest_referenced_xid_known) {
701     LEAFENTRY le;
702     int r = le_pack(ule, nullptr, 0, nullptr, 0, 0, 0, &le, nullptr); CKERR(r);
703     invariant_notnull(le);
704     txn_gc_info gc_info(nullptr, oldest_referenced_xid_known, oldest_referenced_xid_known, true);
705     bool worth_running = toku_le_worth_running_garbage_collection(le, &gc_info);
706     toku_free(le);
707     return worth_running;
708 }
709 
test_le_garbage_collection_birdie(void)710 static void test_le_garbage_collection_birdie(void) {
711     DBT key;
712     DBT val;
713     ULE_S ule;
714     uint8_t keybuf[MAX_SIZE];
715     uint32_t keysize=8;
716     uint8_t valbuf[MAX_SIZE];
717     uint32_t valsize=8;
718     bool do_garbage_collect;
719 
720     memset(&key, 0, sizeof(key));
721     memset(&val, 0, sizeof(val));
722     fillrandom(keybuf, keysize);
723     fillrandom(valbuf, valsize);
724     memset(&ule, 0, sizeof(ule));
725     ule.uxrs = ule.uxrs_static;
726 
727     //
728     // Test garbage collection "worth-doing" heurstic
729     //
730 
731     // Garbage collection should not be worth doing on a clean leafentry.
732     ule.num_cuxrs = 1;
733     ule.num_puxrs = 0;
734     ule.uxrs[0].xid = TXNID_NONE;
735     ule.uxrs[0].type = XR_INSERT;
736     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
737     invariant(!do_garbage_collect);
738 
739     // It is worth doing when there is more than one committed entry
740     ule.num_cuxrs = 2;
741     ule.num_puxrs = 1;
742     ule.uxrs[1].xid = 500;
743     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
744     invariant(do_garbage_collect);
745 
746     // It is not worth doing when there is one of each, when the
747     // provisional entry is newer than the oldest known referenced xid
748     ule.num_cuxrs = 1;
749     ule.num_puxrs = 1;
750     ule.uxrs[1].xid = 1500;
751     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
752     invariant(!do_garbage_collect);
753     ule.uxrs[1].xid = 200;
754     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
755     invariant(!do_garbage_collect);
756 
757     // It is not worth doing when there is only one committed entry,
758     // multiple provisional entries, but the outermost entry is newer.
759     ule.num_cuxrs = 1;
760     ule.num_puxrs = 3;
761     ule.uxrs[1].xid = 201;
762     ule.uxrs[2].xid = 206;
763     ule.uxrs[3].xid = 215;
764     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
765     invariant(!do_garbage_collect);
766 
767     // It is worth doing when the above scenario has an outermost entry
768     // older than the oldest known, even if its children seem newer.
769     // this children must have commit because the parent is not live.
770     ule.num_cuxrs = 1;
771     ule.num_puxrs = 3;
772     ule.uxrs[1].xid = 190;
773     ule.uxrs[2].xid = 206;
774     ule.uxrs[3].xid = 215;
775     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
776     invariant(do_garbage_collect);
777 
778     // It is worth doing when there is more than one committed entry,
779     // even if a provisional entry exists that is newer than the
780     // oldest known refrenced xid
781     ule.num_cuxrs = 2;
782     ule.num_puxrs = 1;
783     ule.uxrs[1].xid = 499;
784     ule.uxrs[2].xid = 500;
785     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
786     invariant(do_garbage_collect);
787 
788     // It is worth doing when there is one of each, and the provisional
789     // entry is older than the oldest known referenced xid
790     ule.num_cuxrs = 1;
791     ule.num_puxrs = 1;
792     ule.uxrs[1].xid = 199;
793     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
794     invariant(do_garbage_collect);
795 
796     // It is definitely worth doing when the above case is true
797     // and there is more than one provisional entry.
798     ule.num_cuxrs = 1;
799     ule.num_puxrs = 2;
800     ule.uxrs[1].xid = 150;
801     ule.uxrs[2].xid = 175;
802     do_garbage_collect = ule_worth_running_garbage_collection(&ule, 200);
803     invariant(do_garbage_collect);
804 }
805 
test_le_optimize(void)806 static void test_le_optimize(void) {
807     DBT key;
808     DBT val;
809     ULE_S ule_initial;
810     ULE_S ule_expected;
811     uint8_t keybuf[MAX_SIZE];
812     uint32_t keysize=8;
813     uint8_t valbuf[MAX_SIZE];
814     uint32_t valsize=8;
815     ule_initial.uxrs = ule_initial.uxrs_static;
816     ule_expected.uxrs = ule_expected.uxrs_static;
817     TXNID optimize_txnid = 1000;
818     memset(&key, 0, sizeof(key));
819     memset(&val, 0, sizeof(val));
820     XIDS root_xids = toku_xids_get_root_xids();
821     XIDS msg_xids;
822     int r = toku_xids_create_child(root_xids, &msg_xids, optimize_txnid);
823     assert(r==0);
824     ft_msg msg(&key, &val, FT_OPTIMIZE, ZERO_MSN, msg_xids);
825 
826     //
827     // create the key
828     //
829     fillrandom(keybuf, keysize);
830     fillrandom(valbuf, valsize);
831 
832     //
833     // test a clean leafentry has no effect
834     //
835     ule_initial.num_cuxrs = 1;
836     ule_initial.num_puxrs = 0;
837     ule_initial.uxrs[0].type = XR_INSERT;
838     ule_initial.uxrs[0].xid = TXNID_NONE;
839     ule_initial.uxrs[0].vallen = valsize;
840     ule_initial.uxrs[0].valp = valbuf;
841 
842     ule_expected.num_cuxrs = 1;
843     ule_expected.num_puxrs = 0;
844     ule_expected.uxrs[0].type = XR_INSERT;
845     ule_expected.uxrs[0].xid = TXNID_NONE;
846     ule_expected.uxrs[0].vallen = valsize;
847     ule_expected.uxrs[0].valp = valbuf;
848 
849     test_msg_modify_ule(&ule_initial, msg);
850     verify_ule_equal(&ule_initial, &ule_expected);
851 
852     //
853     // add another committed entry and ensure no effect
854     //
855     ule_initial.num_cuxrs = 2;
856     ule_initial.uxrs[1].type = XR_DELETE;
857     ule_initial.uxrs[1].xid = 500;
858     ule_initial.uxrs[1].vallen = 0;
859     ule_initial.uxrs[1].valp = NULL;
860 
861     ule_expected.num_cuxrs = 2;
862     ule_expected.uxrs[1].type = XR_DELETE;
863     ule_expected.uxrs[1].xid = 500;
864     ule_expected.uxrs[1].vallen = 0;
865     ule_expected.uxrs[1].valp = NULL;
866 
867     test_msg_modify_ule(&ule_initial, msg);
868     verify_ule_equal(&ule_initial, &ule_expected);
869 
870     //
871     // now test when there is one provisional, three cases, after, equal, and before FT_OPTIMIZE's transaction
872     //
873     ule_initial.num_cuxrs = 1;
874     ule_initial.num_puxrs = 1;
875     ule_initial.uxrs[1].xid = 1500;
876 
877     ule_expected.num_cuxrs = 1;
878     ule_expected.num_puxrs = 1;
879     ule_expected.uxrs[1].xid = 1500;
880     test_msg_modify_ule(&ule_initial, msg);
881     verify_ule_equal(&ule_initial, &ule_expected);
882 
883     ule_initial.uxrs[1].xid = 1000;
884     ule_expected.uxrs[1].xid = 1000;
885     test_msg_modify_ule(&ule_initial, msg);
886     verify_ule_equal(&ule_initial, &ule_expected);
887 
888     ule_initial.uxrs[1].xid = 500;
889     ule_expected.uxrs[1].xid = 500;
890     ule_expected.num_cuxrs = 2;
891     ule_expected.num_puxrs = 0;
892     test_msg_modify_ule(&ule_initial, msg);
893     verify_ule_equal(&ule_initial, &ule_expected);
894 
895     //
896     // now test cases with two provisional
897     //
898     ule_initial.num_cuxrs = 1;
899     ule_initial.num_puxrs = 2;
900     ule_expected.num_cuxrs = 1;
901     ule_expected.num_puxrs = 2;
902 
903     ule_initial.uxrs[2].type = XR_INSERT;
904     ule_initial.uxrs[2].xid = 1500;
905     ule_initial.uxrs[2].vallen = valsize;
906     ule_initial.uxrs[2].valp = valbuf;
907     ule_initial.uxrs[1].xid = 1200;
908 
909     ule_expected.uxrs[2].type = XR_INSERT;
910     ule_expected.uxrs[2].xid = 1500;
911     ule_expected.uxrs[2].vallen = valsize;
912     ule_expected.uxrs[2].valp = valbuf;
913     ule_expected.uxrs[1].xid = 1200;
914     test_msg_modify_ule(&ule_initial, msg);
915     verify_ule_equal(&ule_initial, &ule_expected);
916 
917     ule_initial.uxrs[1].xid = 1000;
918     ule_expected.uxrs[1].xid = 1000;
919     test_msg_modify_ule(&ule_initial, msg);
920     verify_ule_equal(&ule_initial, &ule_expected);
921 
922     ule_initial.uxrs[1].xid = 800;
923     ule_expected.uxrs[1].xid = 800;
924     ule_expected.num_cuxrs = 2;
925     ule_expected.num_puxrs = 0;
926     ule_expected.uxrs[1].type = ule_initial.uxrs[2].type;
927     ule_expected.uxrs[1].valp = ule_initial.uxrs[2].valp;
928     ule_expected.uxrs[1].vallen = ule_initial.uxrs[2].vallen;
929     test_msg_modify_ule(&ule_initial, msg);
930     verify_ule_equal(&ule_initial, &ule_expected);
931 
932 
933     toku_xids_destroy(&msg_xids);
934     toku_xids_destroy(&root_xids);
935 }
936 
937 //TODO: #1125 tests:
938 //      Will probably have to expose ULE_S definition
939 //            - Check memsize function is correct
940 //             - Assert == disksize (almost useless, but go ahead)
941 //            - Check standard accessors
942 //             - le_latest_val_and_len
943 //             - le_latest_val
944 //             - le_latest_vallen
945 //             - le_key_and_len
946 //             - le_innermost_inserted_val_and_len
947 //             - le_innermost_inserted_val
948 //             - le_innermost_inserted_vallen
949 //            - Check le_outermost_uncommitted_xid
950 //            - Check le_latest_is_del
951 //            - Check unpack+pack memcmps equal
952 //            - Check exact memory expected (including size) for various leafentry types.
953 //            - Check apply_msg logic
954 //             - Known start, known expected.. various types.
955 //            - Go through test-leafentry10.c
956 //             - Verify we have tests for all analogous stuff.
957 //
958 //  PACK
959 //  UNPACK
960 //      verify pack+unpack is no-op
961 //      verify unpack+pack is no-op
962 //  accessors
963 //  Test apply_msg logic
964 //      i.e. start with LE, apply message
965 //          in parallel, construct the expected ULE manually, and pack that
966 //          Compare the two results
967 //  Test full_promote
968 
969 static void
init_xids(void)970 init_xids(void) {
971     uint32_t i;
972     nested_xids[0] = toku_xids_get_root_xids();
973     for (i = 1; i < MAX_TRANSACTION_RECORDS; i++) {
974         int r = toku_xids_create_child(nested_xids[i-1], &nested_xids[i], i * 37 + random() % 36);
975         assert(r==0);
976     }
977 }
978 
979 static void
destroy_xids(void)980 destroy_xids(void) {
981     uint32_t i;
982     for (i = 0; i < MAX_TRANSACTION_RECORDS; i++) {
983         toku_xids_destroy(&nested_xids[i]);
984     }
985 }
986 
987 int
test_main(int argc,const char * argv[])988 test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) {
989     srandom(7); //Arbitrary seed.
990     init_xids();
991     test_le_offsets();
992     test_le_pack();
993     test_le_apply_messages();
994     test_le_optimize();
995     test_le_garbage_collection_birdie();
996     destroy_xids();
997     return 0;
998 }
999 
1000