mirror of
https://github.com/MariaDB/server.git
synced 2025-01-22 14:54:20 +01:00
3647773864
git-svn-id: file:///svn/toku/tokudb@13544 c7de825b-a66e-492c-adef-691d508d4ae1
768 lines
26 KiB
C
768 lines
26 KiB
C
#include <toku_portability.h>
|
|
#include <string.h>
|
|
|
|
#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_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);
|
|
}
|
|
{
|
|
//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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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_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_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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|