#include #include #include "test.h" #include "brttypes.h" #include "includes.h" #include "ule.h" enum {MAX_SIZE = 256}; static XIDS nested_xids[MAX_TRANSACTION_RECORDS]; static void verify_ule_equal(ULE a, ULE b) { assert(a->num_uxrs > 0); assert(a->num_uxrs <= MAX_TRANSACTION_RECORDS); assert(a->num_uxrs == b->num_uxrs); assert(a->keylen == b->keylen); assert(memcmp(a->keyp, b->keyp, a->keylen) == 0); u_int32_t i; for (i = 0; i < a->num_uxrs; i++) { assert(a->uxrs[i].type == b->uxrs[i].type); assert(a->uxrs[i].xid == b->uxrs[i].xid); if (a->uxrs[i].type == XR_INSERT) { assert(a->uxrs[i].vallen == b->uxrs[i].vallen); assert(memcmp(a->uxrs[i].valp, b->uxrs[i].valp, a->uxrs[i].vallen) == 0); } } } static void verify_le_equal(LEAFENTRY a, LEAFENTRY b) { if (a==NULL) assert(b==NULL); else { assert(b!=NULL); size_t size = leafentry_memsize(a); assert(size==leafentry_memsize(b)); assert(memcmp(a, b, size) == 0); ULE_S ule_a; ULE_S ule_b; le_unpack(&ule_a, a); le_unpack(&ule_b, b); verify_ule_equal(&ule_a, &ule_b); } } static void fillrandom(u_int8_t buf[MAX_SIZE], u_int32_t length) { assert(length < MAX_SIZE); u_int32_t i; for (i = 0; i < length; i++) { buf[i] = random() & 0xFF; } } static void test_le_offset_is(LEAFENTRY le, void *field, size_t expected_offset) { size_t le_address = (size_t) le; size_t field_address = (size_t) field; assert(field_address >= le_address); size_t actual_offset = field_address - le_address; assert(actual_offset == expected_offset); } //Fixed offsets in a packed leafentry. enum { LE_OFFSET_NUM = 0, LE_OFFSET_KEYLEN = 1+LE_OFFSET_NUM, LE_OFFSET_VALLEN = 4+LE_OFFSET_KEYLEN, //Vallen of innermost insert record LE_OFFSET_VARIABLE = 4+LE_OFFSET_VALLEN }; static void test_le_fixed_offsets (void) { LEAFENTRY XMALLOC(le); test_le_offset_is(le, &le->num_xrs, LE_OFFSET_NUM); test_le_offset_is(le, &le->keylen, LE_OFFSET_KEYLEN); test_le_offset_is(le, &le->innermost_inserted_vallen, LE_OFFSET_VALLEN); toku_free(le); } //Fixed offsets in a leafentry with no uncommitted transaction records. //(Note, there is no type required.) enum { LE_COMMITTED_OFFSET_KEY = LE_OFFSET_VARIABLE }; static void test_le_committed_offsets (void) { LEAFENTRY XMALLOC(le); test_le_offset_is(le, &le->u.comm.key_val, LE_COMMITTED_OFFSET_KEY); toku_free(le); } //Fixed offsets in a leafentry with uncommitted transaction records. enum { LE_PROVISIONAL_OFFSET_TYPE = LE_OFFSET_VARIABLE, //Type of innermost record LE_PROVISIONAL_OFFSET_XID = 1+LE_PROVISIONAL_OFFSET_TYPE, //XID of outermost noncommitted record LE_PROVISIONAL_OFFSET_KEY = 8+LE_PROVISIONAL_OFFSET_XID }; static void test_le_provisional_offsets (void) { LEAFENTRY XMALLOC(le); test_le_offset_is(le, &le->u.prov.innermost_type, LE_PROVISIONAL_OFFSET_TYPE); test_le_offset_is(le, &le->u.prov.xid_outermost_uncommitted, LE_PROVISIONAL_OFFSET_XID); test_le_offset_is(le, &le->u.prov.key_val_xrs, LE_PROVISIONAL_OFFSET_KEY); toku_free(le); } //We use a packed struct to represent a leafentry. //We want to make sure the compiler correctly represents the offsets. //This test verifies all offsets in a packed leafentry correspond to the required memory format. static void test_le_offsets (void) { test_le_fixed_offsets(); test_le_committed_offsets(); test_le_provisional_offsets(); } static void test_ule_packs_to_nothing (ULE ule) { size_t memsize; size_t disksize; LEAFENTRY le; int r = le_pack(ule, &memsize, &disksize, &le, NULL, NULL, NULL); assert(r==0); assert(le==NULL); } //A leafentry must contain at least one 'insert' (all deletes means the leafentry //should not exist). //Verify that 'le_pack' of any set of all deletes ends up not creating a leafentry. static void test_le_empty_packs_to_nothing (void) { ULE_S ule; int key = random(); //Arbitrary number //Set up defaults. ule.keylen = sizeof(key); ule.keyp = &key; ule.uxrs[0].type = XR_DELETE; ule.uxrs[0].xid = 0; u_int8_t num_xrs; for (num_xrs = 1; num_xrs < MAX_TRANSACTION_RECORDS; num_xrs++) { if (num_xrs > 1) { ule.uxrs[num_xrs-1].type = XR_DELETE, ule.uxrs[num_xrs-1].xid = ule.uxrs[num_xrs-2].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing } ule.num_uxrs = num_xrs; test_ule_packs_to_nothing(&ule); if (num_xrs > 2 && num_xrs % 4) { //Set some of them to placeholders instead of deletes ule.uxrs[num_xrs-2].type = XR_PLACEHOLDER; } test_ule_packs_to_nothing(&ule); } } static void le_verify_accessors(LEAFENTRY le, ULE ule, size_t pre_calculated_memsize, size_t pre_calculated_disksize) { assert(le); assert(ule->num_uxrs > 0); assert(ule->num_uxrs <= MAX_TRANSACTION_RECORDS); assert(ule->uxrs[ule->num_uxrs-1].type != XR_PLACEHOLDER); //Extract expected values from ULE size_t memsize = le_memsize_from_ule(ule); size_t disksize = le_memsize_from_ule(ule); void *latest_key = ule->uxrs[ule->num_uxrs-1].type == XR_DELETE ? NULL : ule->keyp; u_int32_t latest_keylen = ule->uxrs[ule->num_uxrs-1].type == XR_DELETE ? 0 : ule->keylen; void *key = ule->keyp; u_int32_t keylen = ule->keylen; void *latest_val = ule->uxrs[ule->num_uxrs-1].type == XR_DELETE ? NULL : ule->uxrs[ule->num_uxrs-1].valp; u_int32_t latest_vallen = ule->uxrs[ule->num_uxrs-1].type == XR_DELETE ? 0 : ule->uxrs[ule->num_uxrs-1].vallen; void *innermost_inserted_val; u_int32_t innermost_inserted_vallen; { int i; for (i = ule->num_uxrs - 1; i >= 0; i--) { if (ule->uxrs[i].type == XR_INSERT) { innermost_inserted_val = ule->uxrs[i].valp; innermost_inserted_vallen = ule->uxrs[i].vallen; goto found_insert; } } assert(FALSE); } found_insert:; TXNID outermost_uncommitted_xid = ule->num_uxrs == 1 ? 0 : ule->uxrs[1].xid; int is_provdel = ule->uxrs[ule->num_uxrs-1].type == XR_DELETE; assert(le!=NULL); //Verify all accessors assert(memsize == pre_calculated_memsize); assert(disksize == pre_calculated_disksize); assert(memsize == disksize); assert(memsize == leafentry_memsize(le)); assert(disksize == leafentry_disksize(le)); { u_int32_t test_keylen; void* test_keyp = le_latest_key_and_len(le, &test_keylen); if (latest_key != NULL) assert(test_keyp != latest_key); assert(test_keylen == latest_keylen); assert(memcmp(test_keyp, latest_key, test_keylen) == 0); assert(le_latest_key(le) == test_keyp); assert(le_latest_keylen(le) == test_keylen); } { u_int32_t test_keylen; void* test_keyp = le_key_and_len(le, &test_keylen); if (key != NULL) assert(test_keyp != key); assert(test_keylen == keylen); assert(memcmp(test_keyp, key, test_keylen) == 0); assert(le_key(le) == test_keyp); assert(le_keylen(le) == test_keylen); } { u_int32_t test_vallen; void* test_valp = le_latest_val_and_len(le, &test_vallen); if (latest_val != NULL) assert(test_valp != latest_val); assert(test_vallen == latest_vallen); assert(memcmp(test_valp, latest_val, test_vallen) == 0); assert(le_latest_val(le) == test_valp); assert(le_latest_vallen(le) == test_vallen); } { u_int32_t test_vallen; void* test_valp = le_innermost_inserted_val_and_len(le, &test_vallen); if (innermost_inserted_val != NULL) assert(test_valp != innermost_inserted_val); assert(test_vallen == innermost_inserted_vallen); assert(memcmp(test_valp, innermost_inserted_val, test_vallen) == 0); assert(le_innermost_inserted_val(le) == test_valp); assert(le_innermost_inserted_vallen(le) == test_vallen); } { assert(le_outermost_uncommitted_xid(le) == outermost_uncommitted_xid); } { assert((le_is_provdel(le)==0) == (is_provdel==0)); } } static void test_le_pack_committed (void) { ULE_S ule; u_int8_t key[MAX_SIZE]; u_int8_t val[MAX_SIZE]; u_int32_t keysize; u_int32_t valsize; for (keysize = 0; keysize < MAX_SIZE; keysize += (random() % MAX_SIZE) + 1) { for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) { fillrandom(key, keysize); fillrandom(val, valsize); ule.num_uxrs = 1; ule.keylen = keysize; ule.keyp = key; ule.uxrs[0].type = XR_INSERT; ule.uxrs[0].xid = 0; ule.uxrs[0].valp = val; ule.uxrs[0].vallen = valsize; size_t memsize; size_t disksize; LEAFENTRY le; int r = le_pack(&ule, &memsize, &disksize, &le, NULL, NULL, NULL); assert(r==0); assert(le!=NULL); le_verify_accessors(le, &ule, memsize, disksize); ULE_S tmp_ule; le_unpack(&tmp_ule, le); verify_ule_equal(&ule, &tmp_ule); LEAFENTRY tmp_le; size_t tmp_memsize; size_t tmp_disksize; r = le_pack(&tmp_ule, &tmp_memsize, &tmp_disksize, &tmp_le, NULL, NULL, NULL); assert(r==0); assert(tmp_memsize == memsize); assert(tmp_disksize == disksize); assert(memcmp(le, tmp_le, memsize) == 0); toku_free(tmp_le); toku_free(le); } } } static void test_le_pack_uncommitted (u_int8_t committed_type, u_int8_t prov_type, int num_placeholders) { ULE_S ule; u_int8_t key[MAX_SIZE]; u_int8_t cval[MAX_SIZE]; u_int8_t pval[MAX_SIZE]; u_int32_t keysize; u_int32_t cvalsize; u_int32_t pvalsize; for (keysize = 0; keysize < MAX_SIZE; keysize += (random() % MAX_SIZE) + 1) { for (cvalsize = 0; cvalsize < MAX_SIZE; cvalsize += (random() % MAX_SIZE) + 1) { pvalsize = (cvalsize + random()) % MAX_SIZE; fillrandom(key, keysize); if (committed_type == XR_INSERT) fillrandom(cval, cvalsize); if (prov_type == XR_INSERT) fillrandom(pval, pvalsize); ule.uxrs[0].type = committed_type; ule.uxrs[0].xid = 0; ule.uxrs[0].vallen = cvalsize; ule.uxrs[0].valp = cval; ule.keylen = keysize; ule.keyp = key; ule.num_uxrs = 2 + num_placeholders; u_int8_t idx; for (idx = 1; idx <= num_placeholders; idx++) { ule.uxrs[idx].type = XR_PLACEHOLDER; ule.uxrs[idx].xid = ule.uxrs[idx-1].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing } ule.uxrs[idx].xid = ule.uxrs[idx-1].xid + (random() % 32 + 1); //Abitrary number, xids must be strictly increasing ule.uxrs[idx].type = prov_type; ule.uxrs[idx].vallen = pvalsize; ule.uxrs[idx].valp = pval; size_t memsize; size_t disksize; LEAFENTRY le; int r = le_pack(&ule, &memsize, &disksize, &le, NULL, NULL, NULL); assert(r==0); assert(le!=NULL); le_verify_accessors(le, &ule, memsize, disksize); ULE_S tmp_ule; le_unpack(&tmp_ule, le); verify_ule_equal(&ule, &tmp_ule); LEAFENTRY tmp_le; size_t tmp_memsize; size_t tmp_disksize; r = le_pack(&tmp_ule, &tmp_memsize, &tmp_disksize, &tmp_le, NULL, NULL, NULL); assert(r==0); assert(tmp_memsize == memsize); assert(tmp_disksize == disksize); assert(memcmp(le, tmp_le, memsize) == 0); toku_free(tmp_le); toku_free(le); } } } static void test_le_pack_provpair (int num_placeholders) { test_le_pack_uncommitted(XR_DELETE, XR_INSERT, num_placeholders); } static void test_le_pack_provdel (int num_placeholders) { test_le_pack_uncommitted(XR_INSERT, XR_DELETE, num_placeholders); } static void test_le_pack_both (int num_placeholders) { test_le_pack_uncommitted(XR_INSERT, XR_INSERT, num_placeholders); } //Test of PACK // Committed leafentry // delete -> nothing (le_empty_packs_to_nothing) // insert // make key/val have diff lengths/content // Uncommitted // committed delete // followed by placeholder*, delete (le_empty_packs_to_nothing) // followed by placeholder*, insert // committed insert // followed by placeholder*, delete // followed by placeholder*, insert // // placeholder* is 0,1, or 2 placeholders static void test_le_pack (void) { test_le_empty_packs_to_nothing(); test_le_pack_committed(); int i; for (i = 0; i < 3; i++) { test_le_pack_provpair(i); test_le_pack_provdel(i); test_le_pack_both(i); } } static void test_le_apply(ULE ule_initial, BRT_MSG msg, ULE ule_expected) { int r; LEAFENTRY le_initial; LEAFENTRY le_expected; LEAFENTRY le_result; size_t initial_memsize; size_t initial_disksize; r = le_pack(ule_initial, &initial_memsize, &initial_disksize, &le_initial, NULL, NULL, NULL); CKERR(r); size_t result_memsize; size_t result_disksize; r = apply_msg_to_leafentry(msg, le_initial, &result_memsize, &result_disksize, &le_result, NULL, NULL, NULL); CKERR(r); if (le_result) le_verify_accessors(le_result, ule_expected, result_memsize, result_disksize); size_t expected_memsize; size_t expected_disksize; r = le_pack(ule_expected, &expected_memsize, &expected_disksize, &le_expected, NULL, NULL, NULL); CKERR(r); verify_le_equal(le_result, le_expected); if (le_result && le_expected) { assert(result_memsize == expected_memsize); assert(result_disksize == expected_disksize); } if (le_initial) toku_free(le_initial); if (le_result) toku_free(le_result); if (le_expected) toku_free(le_expected); } static const ULE_S ule_committed_delete = { .num_uxrs = 1, .keylen = 0, .keyp = NULL, .uxrs[0] = { .type = XR_DELETE, .vallen = 0, .xid = 0, .valp = NULL } }; static BRT_MSG msg_init(BRT_MSG msg, int type, XIDS xids, DBT *key, DBT *val) { msg->type = type; msg->xids = xids; msg->u.id.key = key; msg->u.id.val = val; return msg; } static u_int8_t next_nesting_level(u_int8_t current) { u_int8_t rval = current + 1; if (current > 3 && current < MAX_TRANSACTION_RECORDS - 1) { rval = current + random() % 100; if (rval >= MAX_TRANSACTION_RECORDS) rval = MAX_TRANSACTION_RECORDS - 1; } return rval; } static void generate_committed_for(ULE ule, DBT *key, DBT *val) { ule->num_uxrs = 1; ule->keylen = key->size; ule->keyp = key->data; ule->uxrs[0].type = XR_INSERT; ule->uxrs[0].vallen = val->size; ule->uxrs[0].valp = val->data; ule->uxrs[0].xid = 0; } static void generate_provpair_for(ULE ule, BRT_MSG msg) { u_int8_t level; XIDS xids = msg->xids; ule->num_uxrs = xids_get_num_xids(xids); ule->keylen = msg->u.id.key->size; ule->keyp = msg->u.id.key->data; ule->uxrs[0].type = XR_DELETE; ule->uxrs[0].vallen = 0; ule->uxrs[0].valp = NULL; ule->uxrs[0].xid = xids_get_xid(xids, 0); for (level = 1; level < ule->num_uxrs - 1; level++) { ule->uxrs[level].type = XR_PLACEHOLDER; ule->uxrs[level].vallen = 0; ule->uxrs[level].valp = NULL; ule->uxrs[level].xid = xids_get_xid(xids, level); } ule->uxrs[ule->num_uxrs - 1].type = XR_INSERT; ule->uxrs[ule->num_uxrs - 1].vallen = msg->u.id.val->size; ule->uxrs[ule->num_uxrs - 1].valp = msg->u.id.val->data; ule->uxrs[ule->num_uxrs - 1].xid = xids_get_innermost_xid(xids); } //Test all the different things that can happen to a //non-existent leafentry (logical equivalent of a committed delete). static void test_le_empty_apply(void) { ULE_S ule_initial = ule_committed_delete; BRT_MSG_S msg; DBT key; DBT val; u_int8_t keybuf[MAX_SIZE]; u_int8_t valbuf[MAX_SIZE]; u_int32_t keysize; u_int32_t valsize; u_int8_t nesting_level; for (keysize = 0; keysize < MAX_SIZE; keysize += (random() % MAX_SIZE) + 1) { for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) { for (nesting_level = 0; nesting_level < MAX_TRANSACTION_RECORDS; nesting_level = next_nesting_level(nesting_level)) { XIDS msg_xids = nested_xids[nesting_level]; fillrandom(keybuf, keysize); fillrandom(valbuf, valsize); toku_fill_dbt(&key, keybuf, keysize); toku_fill_dbt(&val, valbuf, valsize); //COMMIT/ABORT is illegal with TXNID 0 if (nesting_level > 0) { //Abort/commit of an empty le is an empty le ULE_S ule_expected = ule_committed_delete; msg_init(&msg, BRT_COMMIT_ANY, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_COMMIT_BOTH, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_COMMIT_BROADCAST_TXN, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_ABORT_ANY, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_ABORT_BOTH, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_ABORT_BROADCAST_TXN, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); } { //delete of an empty le is an empty le ULE_S ule_expected = ule_committed_delete; msg_init(&msg, BRT_DELETE_ANY, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_DELETE_BOTH, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); } { msg_init(&msg, BRT_INSERT, msg_xids, &key, &val); ULE_S ule_expected; generate_provpair_for(&ule_expected, &msg); test_le_apply(&ule_initial, &msg, &ule_expected); } { msg_init(&msg, BRT_INSERT_NO_OVERWRITE, msg_xids, &key, &val); ULE_S ule_expected; generate_provpair_for(&ule_expected, &msg); test_le_apply(&ule_initial, &msg, &ule_expected); } } } } } static void generate_provdel_for(ULE ule, BRT_MSG msg) { u_int8_t level; XIDS xids = msg->xids; ule->num_uxrs = xids_get_num_xids(xids); ule->keylen = msg->u.id.key->size; ule->keyp = msg->u.id.key->data; ule->uxrs[0].type = XR_INSERT; ule->uxrs[0].vallen = msg->u.id.val->size; ule->uxrs[0].valp = msg->u.id.val->data; ule->uxrs[0].xid = xids_get_xid(xids, 0); for (level = 1; level < ule->num_uxrs - 1; level++) { ule->uxrs[level].type = XR_PLACEHOLDER; ule->uxrs[level].vallen = 0; ule->uxrs[level].valp = NULL; ule->uxrs[level].xid = xids_get_xid(xids, level); } ule->uxrs[ule->num_uxrs - 1].type = XR_DELETE; ule->uxrs[ule->num_uxrs - 1].vallen = 0; ule->uxrs[ule->num_uxrs - 1].valp = NULL; ule->uxrs[ule->num_uxrs - 1].xid = xids_get_innermost_xid(xids); } static void generate_both_for(ULE ule, DBT *oldval, BRT_MSG msg) { u_int8_t level; XIDS xids = msg->xids; ule->num_uxrs = xids_get_num_xids(xids); ule->keylen = msg->u.id.key->size; ule->keyp = msg->u.id.key->data; ule->uxrs[0].type = XR_INSERT; ule->uxrs[0].vallen = oldval->size; ule->uxrs[0].valp = oldval->data; ule->uxrs[0].xid = xids_get_xid(xids, 0); for (level = 1; level < ule->num_uxrs - 1; level++) { ule->uxrs[level].type = XR_PLACEHOLDER; ule->uxrs[level].vallen = 0; ule->uxrs[level].valp = NULL; ule->uxrs[level].xid = xids_get_xid(xids, level); } ule->uxrs[ule->num_uxrs - 1].type = XR_INSERT; ule->uxrs[ule->num_uxrs - 1].vallen = msg->u.id.val->size; ule->uxrs[ule->num_uxrs - 1].valp = msg->u.id.val->data; ule->uxrs[ule->num_uxrs - 1].xid = xids_get_innermost_xid(xids); } //Test all the different things that can happen to a //committed leafentry (logical equivalent of a committed insert). static void test_le_committed_apply(void) { ULE_S ule_initial; BRT_MSG_S msg; DBT key; DBT val; u_int8_t keybuf[MAX_SIZE]; u_int8_t valbuf[MAX_SIZE]; u_int32_t keysize; u_int32_t valsize; u_int8_t nesting_level; for (keysize = 0; keysize < MAX_SIZE; keysize += (random() % MAX_SIZE) + 1) { for (valsize = 0; valsize < MAX_SIZE; valsize += (random() % MAX_SIZE) + 1) { for (nesting_level = 0; nesting_level < MAX_TRANSACTION_RECORDS; nesting_level = next_nesting_level(nesting_level)) { XIDS msg_xids = nested_xids[nesting_level]; fillrandom(keybuf, keysize); fillrandom(valbuf, valsize); toku_fill_dbt(&key, keybuf, keysize); toku_fill_dbt(&val, valbuf, valsize); //Generate initial ule generate_committed_for(&ule_initial, &key, &val); //COMMIT/ABORT is illegal with TXNID 0 if (nesting_level > 0) { //Commit/abort will not change a committed le ULE_S ule_expected = ule_initial; msg_init(&msg, BRT_COMMIT_ANY, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_COMMIT_BOTH, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_COMMIT_BROADCAST_TXN, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_ABORT_ANY, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_ABORT_BOTH, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_ABORT_BROADCAST_TXN, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); } { msg_init(&msg, BRT_DELETE_ANY, msg_xids, &key, &val); ULE_S ule_expected; generate_provdel_for(&ule_expected, &msg); test_le_apply(&ule_initial, &msg, &ule_expected); msg_init(&msg, BRT_DELETE_BOTH, msg_xids, &key, &val); test_le_apply(&ule_initial, &msg, &ule_expected); } { u_int8_t valbuf2[MAX_SIZE]; u_int32_t valsize2 = random() % MAX_SIZE; fillrandom(valbuf2, valsize2); DBT val2; toku_fill_dbt(&val2, valbuf2, valsize2); msg_init(&msg, BRT_INSERT, msg_xids, &key, &val2); ULE_S ule_expected; generate_both_for(&ule_expected, &val, &msg); test_le_apply(&ule_initial, &msg, &ule_expected); } { //INSERT_NO_OVERWRITE will not change a committed insert ULE_S ule_expected = ule_initial; u_int8_t valbuf2[MAX_SIZE]; u_int32_t valsize2 = random() % MAX_SIZE; fillrandom(valbuf2, valsize2); DBT val2; toku_fill_dbt(&val2, valbuf2, valsize2); msg_init(&msg, BRT_INSERT_NO_OVERWRITE, msg_xids, &key, &val2); test_le_apply(&ule_initial, &msg, &ule_expected); } } } } } static void test_le_apply_messages(void) { test_le_empty_apply(); test_le_committed_apply(); } //TODO: #1125 tests: // Will probably have to expose ULE_S definition // - Check memsize function is correct // - Assert == disksize (almost useless, but go ahead) // - Check standard accessors // - le_latest_key_and_len // - le_latest_key // - le_latest_keylen // - le_latest_val_and_len // - le_latest_val // - le_latest_vallen // - le_key_and_len // - le_key // - le_keylen // - le_innermost_inserted_val_and_len // - le_innermost_inserted_val // - le_innermost_inserted_vallen // - Check le_outermost_uncommitted_xid // - Check le_is_provdel // - Check unpack+pack memcmps equal // - Check exact memory expected (including size) for various leafentry types. // - Check apply_msg logic // - Known start, known expected.. various types. // - Go through test-leafentry10.c // - Verify we have tests for all analogous stuff. // // PACK // UNPACK // verify pack+unpack is no-op // verify unpack+pack is no-op // accessors // Test apply_msg logic // i.e. start with LE, apply message // in parallel, construct the expected ULE manually, and pack that // Compare the two results // Test full_promote static void init_xids(void) { u_int8_t i; nested_xids[0] = xids_get_root_xids(); for (i = 1; i < MAX_TRANSACTION_RECORDS; i++) { int r = xids_create_child(nested_xids[i-1], &nested_xids[i], i * 37 + random() % 36); assert(r==0); } } static void destroy_xids(void) { u_int8_t i; for (i = 0; i < MAX_TRANSACTION_RECORDS; i++) { xids_destroy(&nested_xids[i]); } } int test_main (int argc __attribute__((__unused__)), const char *argv[] __attribute__((__unused__))) { srandom(7); //Arbitrary seed. init_xids(); test_le_offsets(); test_le_pack(); test_le_apply_messages(); destroy_xids(); return 0; }