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