Commit 9f6b9f93 authored by Rich Prohaska's avatar Rich Prohaska Committed by Yoni Fogel

#3497 merge fractal tree code to main refs[t:3497]

git-svn-id: file:///svn/toku/tokudb@31566 c7de825b-a66e-492c-adef-691d508d4ae1
parent 9f99c41d
......@@ -509,7 +509,7 @@ struct __toku_dbc {
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_pre_acquire_read_lock)(DBC*, const DBT*, const DBT*);
int (*c_pre_acquire_range_lock)(DBC*, const DBT*, const DBT*);
void* __toku_dummy0[10];
char __toku_dummy1[104];
int (*c_close) (DBC *); /* 32-bit offset=188 size=4, 64=bit offset=272 size=8 */
......
......@@ -524,7 +524,7 @@ struct __toku_dbc {
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_pre_acquire_read_lock)(DBC*, const DBT*, const DBT*);
int (*c_pre_acquire_range_lock)(DBC*, const DBT*, const DBT*);
void* __toku_dummy0[8];
char __toku_dummy1[112];
int (*c_close) (DBC *); /* 32-bit offset=188 size=4, 64=bit offset=264 size=8 */
......
......@@ -530,7 +530,7 @@ struct __toku_dbc {
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_pre_acquire_read_lock)(DBC*, const DBT*, const DBT*);
int (*c_pre_acquire_range_lock)(DBC*, const DBT*, const DBT*);
void* __toku_dummy0[10];
char __toku_dummy1[104];
int (*c_close) (DBC *); /* 32-bit offset=188 size=4, 64=bit offset=272 size=8 */
......
......@@ -530,7 +530,7 @@ struct __toku_dbc {
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_pre_acquire_read_lock)(DBC*, const DBT*, const DBT*);
int (*c_pre_acquire_range_lock)(DBC*, const DBT*, const DBT*);
void* __toku_dummy0[14];
char __toku_dummy1[104];
int (*c_close) (DBC *); /* 32-bit offset=204 size=4, 64=bit offset=304 size=8 */
......
......@@ -534,7 +534,7 @@ struct __toku_dbc {
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_pre_acquire_read_lock)(DBC*, const DBT*, const DBT*);
int (*c_pre_acquire_range_lock)(DBC*, const DBT*, const DBT*);
void* __toku_dummy0[24];
char __toku_dummy1[104];
int (*c_close) (DBC *); /* 32-bit offset=244 size=4, 64=bit offset=384 size=8 */
......
......@@ -731,7 +731,7 @@ int main (int argc __attribute__((__unused__)), char *const argv[] __attribute__
"int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *)",
"int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *)",
"int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *)",
"int (*c_pre_acquire_read_lock)(DBC*, const DBT*, const DBT*)",
"int (*c_pre_acquire_range_lock)(DBC*, const DBT*, const DBT*)",
NULL};
assert(sizeof(dbc_fields32)==sizeof(dbc_fields64));
print_struct("dbc", INTERNAL_AT_END, dbc_fields32, dbc_fields64, sizeof(dbc_fields32)/sizeof(dbc_fields32[0]), extra);
......
......@@ -472,7 +472,7 @@ struct __toku_dbc {
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_pre_acquire_read_lock)(DBC*, const DBT*, const DBT*);
int (*c_pre_acquire_range_lock)(DBC*, const DBT*, const DBT*);
int (*c_close) (DBC *);
int (*c_count) (DBC *, db_recno_t *, u_int32_t);
int (*c_del) (DBC *, u_int32_t);
......
......@@ -472,7 +472,7 @@ struct __toku_dbc {
int (*c_getf_set)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_getf_set_range_reverse)(DBC *, u_int32_t, DBT *, YDB_CALLBACK_FUNCTION, void *);
int (*c_pre_acquire_read_lock)(DBC*, const DBT*, const DBT*);
int (*c_pre_acquire_range_lock)(DBC*, const DBT*, const DBT*);
int (*c_close) (DBC *);
int (*c_count) (DBC *, db_recno_t *, u_int32_t);
int (*c_del) (DBC *, u_int32_t);
......
This diff is collapsed.
......@@ -34,8 +34,7 @@ extern "C" {
/** Errors returned by lock trees */
typedef enum {
TOKU_LT_INCONSISTENT=-1, /**< The member data are in an inconsistent
state */
TOKU_LT_INCONSISTENT=-1, /**< The member data are in an inconsistent state */
} TOKU_LT_ERROR;
typedef int (*toku_dbt_cmp)(DB*,const DBT*,const DBT*);
......@@ -54,6 +53,7 @@ typedef struct __toku_lock_tree toku_lock_tree;
typedef struct __toku_lth toku_lth;
#endif
#define TOKU_LT_USE_BORDERWRITE 1
typedef struct __toku_ltm toku_ltm;
......@@ -61,7 +61,6 @@ typedef struct __toku_ltm toku_ltm;
struct __toku_lock_tree {
/** The database for which this locktree will be handling locks */
DB* db;
toku_range_tree* mainread; /**< See design document */
toku_range_tree* borderwrite; /**< See design document */
toku_rth* rth; /**< Stores local(read|write)set tables */
/**
......@@ -94,7 +93,9 @@ struct __toku_lock_tree {
the lt, we made copies from the DB at some point
*/
toku_range* buf;
uint32_t buflen; /**< The length of buf */
uint32_t buflen; /**< The length of buf */
toku_range* bw_buf;
uint32_t bw_buflen;
/** Whether lock escalation is allowed. */
BOOL lock_escalation_allowed;
/** Lock tree manager */
......@@ -349,10 +350,6 @@ int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB* db, TXNID txn,
//This can cause conflicts, I was unable (so far) to verify that MySQL does or does not use
//this.
/*
* ***************NOTE: This will not be implemented before Feb 1st because
* *************** MySQL does not use DB->del on DB_DUPSORT dbs.
* *************** The only operation that requires a write range lock is
* *************** DB->del on DB_DUPSORT dbs.
* Acquires a write lock on a key range (or key/data range). (Closed range).
* Params:
* tree The lock tree for the db.
......@@ -475,6 +472,8 @@ toku_range_tree* toku_lt_ifexist_selfread(toku_lock_tree* tree, TXNID txn);
toku_range_tree* toku_lt_ifexist_selfwrite(toku_lock_tree* tree, TXNID txn);
void toku_lt_verify(toku_lock_tree *tree, DB *db);
#if defined(__cplusplus)
}
#endif
......
......@@ -28,12 +28,6 @@ static void do_range_test(int (*acquire)(toku_lock_tree*, DB*, TXNID,
CKERR(r);
assert(lt);
if (acquire == toku_lt_acquire_range_write_lock) {
r = acquire(lt, db, txn, key_l, key_r);
CKERR2(r, ENOSYS);
}
r = acquire(NULL, db, txn, key_l, key_r);
CKERR2(r, EINVAL);
r = acquire(lt, db, txn, NULL, key_r);
......
......@@ -87,9 +87,9 @@ static void lt_insert(int key_l, int key_r) {
assert(key_left);
assert(key_right);
r = toku_lt_acquire_range_read_lock(lt, db, txn, key_left,
key_right);
r = toku_lt_acquire_range_read_lock(lt, db, txn, key_left, key_right);
CKERR(r);
toku_lt_verify(lt, db);
}
static void setup_payload_len(void** payload, uint32_t* len, int val) {
......@@ -170,13 +170,11 @@ static void insert_1(int key_l, int key_r,
}
static void runtest(void) {
int i;
const DBT* choices[3];
choices[0] = toku_lt_neg_infinity;
choices[1] = NULL;
choices[2] = toku_lt_infinity;
for (i = 0; i < 9; i++) {
for (int i = 0; i < 9; i++) {
int a = i / 3;
int b = i % 3;
if (a > b) continue;
......@@ -203,7 +201,7 @@ static void runtest(void) {
7,
txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread;
assert(rt);
......@@ -230,7 +228,7 @@ static void runtest(void) {
7,
txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 1,
......@@ -248,7 +246,7 @@ static void runtest(void) {
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find(rt, 2, 3, 3, txn);
lt_find(rt, 2, 4, 4, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 2, 3, 3, txn);
lt_find(rt, 2, 4, 4, txn);
......@@ -257,24 +255,24 @@ static void runtest(void) {
close_tree();
/* ************************************** */
setup_tree();
for (i = 0; i < 20; i += 2) {
for (int i = 0; i < 20; i += 2) {
lt_insert(i, i + 1);
}
rt = toku_lt_ifexist_selfread(lt, txn);
assert(rt);
for (i = 0; i < 20; i += 2) {
for (int i = 0; i < 20; i += 2) {
lt_find(rt, 10, i, i + 1, txn);
}
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
for (i = 0; i < 20; i += 2) {
for (int i = 0; i < 20; i += 2) {
lt_find(rt, 10, i, i + 1, txn);
}
#endif
lt_insert(0, 20);
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find( rt, 1, 0, 20, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find( rt, 1, 0, 20, txn);
#endif
......@@ -291,7 +289,7 @@ static void runtest(void) {
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find(rt, 2, 0, 2, txn);
lt_find(rt, 2, 3, 5, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 2, 0, 2, txn);
lt_find(rt, 2, 3, 5, txn);
......@@ -301,7 +299,7 @@ static void runtest(void) {
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find(rt, 1, 0, 5, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 1, 0, 5, txn);
#endif
......@@ -314,7 +312,7 @@ static void runtest(void) {
lt_insert(2, 5);
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find(rt, 1, 1, 6, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 1, 1, 6, txn);
#endif
......@@ -327,7 +325,7 @@ static void runtest(void) {
lt_insert( 2, 7);
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find(rt, 1, neg_infinite, 8, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 1, neg_infinite, 8, txn);
#endif
......@@ -339,7 +337,7 @@ static void runtest(void) {
lt_insert(2, 3);
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find(rt, 1, 1, infinite, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 1, 1, infinite, txn);
#endif
......@@ -352,7 +350,7 @@ static void runtest(void) {
lt_insert(2, 5);
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find(rt, 1, 1, 6, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 1, 1, 6, txn);
#endif
......@@ -364,19 +362,22 @@ static void runtest(void) {
lt_insert(2, 4);
rt = toku_lt_ifexist_selfread(lt, txn); assert(rt);
lt_find(rt, 1, 1, 5, txn);
#ifndef TOKU_RT_NOOVERLAPS
#if TOKU_LT_USE_MAINREAD && !defined(TOKU_RT_NOOVERLAPS)
rt = lt->mainread; assert(rt);
lt_find(rt, 1, 1, 5, txn);
#endif
close_tree();
/* ************************************** */
setup_tree();
lt_insert(1, 1);
lt_insert(1, 2);
lt_insert(1, 3);
close_tree();
}
static void init_test(void) {
unsigned i;
for (i = 0; i < sizeof(nums)/sizeof(nums[0]); i++) nums[i] = i;
for (unsigned i = 0; i < sizeof(nums)/sizeof(nums[0]); i++)
nums[i] = i;
buflen = 64;
buf = (toku_range*) toku_malloc(buflen*sizeof(toku_range));
......@@ -387,9 +388,6 @@ static void close_test(void) {
toku_free(buf);
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
......
......@@ -111,6 +111,16 @@ static void lt_unlock(char ctxn) {
}
static void runtest(void) {
setup_tree();
lt_insert_write(0, 'a', 1);
toku_lt_verify(lt, NULL);
lt_insert_write(0, 'a', 5);
toku_lt_verify(lt, NULL);
lt_insert_write(0, 'a', 20);
toku_lt_verify(lt, NULL);
lt_insert_write(0, 'b', 10);
toku_lt_verify(lt, NULL);
close_tree();
/* ********************* */
setup_tree();
......
// make sure that the borderwrite merge works
#include "test.h"
int r;
toku_lock_tree* lt = NULL;
toku_ltm* ltm = NULL;
DB* db = (DB*)1;
enum { MAX_LT_LOCKS = 1000 };
uint32_t max_locks = MAX_LT_LOCKS;
uint64_t max_lock_memory = MAX_LT_LOCKS*64;
int nums[100];
DBT _keys_left[2];
DBT _keys_right[2];
DBT* keys_left[2];
DBT* keys_right[2];
toku_point qleft, qright;
toku_interval query;
toku_range* buf;
unsigned buflen;
unsigned numfound;
static void init_query(void) {
init_point(&qleft, lt);
init_point(&qright, lt);
qleft.key_payload = (void *) toku_lt_neg_infinity;
qright.key_payload = (void *) toku_lt_infinity;
memset(&query,0,sizeof(query));
query.left = &qleft;
query.right = &qright;
}
static void setup_tree(void) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, max_lock_memory, dbpanic,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, dbpanic, ltm,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
init_query();
}
static void close_tree(void) {
assert(lt && ltm);
r = toku_lt_close(lt); CKERR(r);
r = toku_ltm_close(ltm); CKERR(r);
lt = NULL;
ltm = NULL;
}
typedef enum { null = -1, infinite = -2, neg_infinite = -3 } lt_infty;
static DBT* set_to_infty(DBT *dbt, int value) {
if (value == infinite)
return (DBT*)toku_lt_infinity;
if (value == neg_infinite)
return (DBT*)toku_lt_neg_infinity;
if (value == null)
return dbt_init(dbt, NULL, 0);
assert(0 <= value && (int) (sizeof nums / sizeof nums[0]));
return dbt_init(dbt, &nums[value], sizeof(nums[0]));
}
static void lt_verify(void) {
toku_lt_verify(lt, NULL);
}
static void lt_insert_write_range(int r_expect, char txn, int key_l, int key_r) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
TXNID local_txn = (TXNID) (size_t) txn;
r = toku_lt_acquire_range_write_lock(lt, db, local_txn, key_left, key_right);
CKERR2(r, r_expect);
lt_verify();
}
static void runtest(void) {
setup_tree();
lt_insert_write_range(0, 'a', 5, 15);
lt_insert_write_range(0, 'a', 10, 20);
for (int k = 5; k <= 20; k++)
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', k, k);
for (int k = 5; k <= 20; k++)
lt_insert_write_range(0, 'a', k, k);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 10, 20);
lt_insert_write_range(0, 'a', 5, 15);
for (int k = 5; k <= 20; k++)
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', k, k);
for (int k = 5; k <= 20; k++)
lt_insert_write_range(0, 'a', k, k);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 10, 20);
for (int k = 10; k <= 20; k++)
lt_insert_write_range(0, 'a', k, k);
for (int k = 10; k <= 20; k++)
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', k, k);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 5, 10);
lt_insert_write_range(0, 'a', 20, 30);
lt_insert_write_range(0, 'a', 1, 8);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 5, 10);
lt_insert_write_range(0, 'a', 20, 30);
lt_insert_write_range(0, 'a', 25, 35);
close_tree();
}
static void init_test(void) {
for (unsigned i = 0; i < sizeof(nums)/sizeof(nums[0]); i++)
nums[i] = i;
buflen = 64;
buf = (toku_range*) toku_malloc(buflen*sizeof(toku_range));
}
static void close_test(void) {
toku_free(buf);
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
init_test();
runtest();
close_test();
return 0;
}
// test global write locks
#include "test.h"
int r;
toku_lock_tree* lt = NULL;
toku_ltm* ltm = NULL;
DB* db = (DB*)1;
enum { MAX_LT_LOCKS = 1000 };
uint32_t max_locks = MAX_LT_LOCKS;
uint64_t max_lock_memory = MAX_LT_LOCKS*64;
int nums[100];
DBT _keys_left[2];
DBT _keys_right[2];
DBT* keys_left[2];
DBT* keys_right[2];
toku_point qleft, qright;
toku_interval query;
toku_range* buf;
unsigned buflen;
unsigned numfound;
static void init_query(void) {
init_point(&qleft, lt);
init_point(&qright, lt);
qleft.key_payload = (void *) toku_lt_neg_infinity;
qright.key_payload = (void *) toku_lt_infinity;
memset(&query,0,sizeof(query));
query.left = &qleft;
query.right = &qright;
}
static void setup_tree(void) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, max_lock_memory, dbpanic,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, dbpanic, ltm,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
init_query();
}
static void close_tree(void) {
assert(lt && ltm);
r = toku_lt_close(lt); CKERR(r);
r = toku_ltm_close(ltm); CKERR(r);
lt = NULL;
ltm = NULL;
}
typedef enum { null = -1, infinite = -2, neg_infinite = -3 } lt_infty;
static DBT* set_to_infty(DBT *dbt, int value) {
if (value == infinite)
return (DBT*)toku_lt_infinity;
if (value == neg_infinite)
return (DBT*)toku_lt_neg_infinity;
if (value == null)
return dbt_init(dbt, NULL, 0);
assert(0 <= value && (int) (sizeof nums / sizeof nums[0]));
return dbt_init(dbt, &nums[value], sizeof(nums[0]));
}
static void lt_verify(void) {
toku_lt_verify(lt, NULL);
}
static void lt_insert_read_range(int r_expect, char txn, int key_l, int key_r) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
TXNID local_txn = (TXNID) (size_t) txn;
r = toku_lt_acquire_range_read_lock(lt, db, local_txn, key_left, key_right);
CKERR2(r, r_expect);
lt_verify();
}
static void lt_insert_write_range(int r_expect, char txn, int key_l, int key_r) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
TXNID local_txn = (TXNID) (size_t) txn;
r = toku_lt_acquire_range_write_lock(lt, db, local_txn, key_left, key_right);
CKERR2(r, r_expect);
lt_verify();
}
static void runtest(void) {
setup_tree();
lt_insert_write_range(0, 'a', neg_infinite, infinite);
close_tree();
setup_tree();
lt_insert_read_range(0, 'a', 1, 2);
lt_insert_write_range(0, 'a', neg_infinite, infinite);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 1, 2);
lt_insert_write_range(0, 'a', neg_infinite, infinite);
close_tree();
setup_tree();
lt_insert_read_range(0, 'b', 1, 2);
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'a', neg_infinite, infinite);
close_tree();
setup_tree();
lt_insert_write_range(0, 'b', 1, 2);
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'a', neg_infinite, infinite);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', neg_infinite, infinite);
lt_insert_write_range(0, 'a', neg_infinite, infinite);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', neg_infinite, infinite);
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', neg_infinite, infinite);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', neg_infinite, infinite);
lt_insert_read_range(0, 'a', 1, 2);
lt_insert_read_range(DB_LOCK_NOTGRANTED, 'b', 10, 20);
close_tree();
}
static void init_test(void) {
for (unsigned i = 0; i < sizeof(nums)/sizeof(nums[0]); i++)
nums[i] = i;
buflen = 64;
buf = (toku_range*) toku_malloc(buflen*sizeof(toku_range));
}
static void close_test(void) {
toku_free(buf);
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
init_test();
runtest();
close_test();
return 0;
}
/* We are going to test whether create and close properly check their input. */
#include "test.h"
enum { MAX_LOCKS = 1000, MAX_LOCK_MEMORY = MAX_LOCKS * 64 };
static void do_ltm_status(toku_ltm *ltm) {
uint32_t max_locks, curr_locks;
uint64_t max_lock_memory, curr_lock_memory;
LTM_STATUS_S s;
toku_ltm_get_status(ltm, &max_locks, &curr_locks, &max_lock_memory, &curr_lock_memory, &s);
assert(max_locks == MAX_LOCKS);
assert(curr_locks == 0);
assert(max_lock_memory == MAX_LOCK_MEMORY);
assert(curr_lock_memory == 0);
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
int r;
toku_ltm *ltm = NULL;
r = toku_ltm_create(&ltm, MAX_LOCKS, MAX_LOCK_MEMORY, dbpanic,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
do_ltm_status(ltm);
#if 0
r = toku_ltm_set_max_locks(NULL, max_locks);
CKERR2(r, EINVAL);
r = toku_ltm_set_max_locks(ltm, 0);
CKERR2(r, EINVAL);
r = toku_ltm_set_max_locks(ltm, max_locks);
CKERR(r);
uint32_t get_max = 73; //Some random number that isn't 0.
r = toku_ltm_get_max_locks(NULL, &get_max);
CKERR2(r, EINVAL);
assert(get_max == 73);
r = toku_ltm_get_max_locks(ltm, NULL);
CKERR2(r, EINVAL);
assert(get_max == 73);
r = toku_ltm_get_max_locks(ltm, &get_max);
CKERR(r);
assert(get_max == max_locks);
r = toku_ltm_set_max_lock_memory(NULL, max_lock_memory);
CKERR2(r, EINVAL);
r = toku_ltm_set_max_lock_memory(ltm, 0);
CKERR2(r, EINVAL);
r = toku_ltm_set_max_lock_memory(ltm, max_lock_memory);
CKERR(r);
uint64_t get_max_memory = 73; //Some random number that isn't 0.
r = toku_ltm_get_max_lock_memory(NULL, &get_max_memory);
CKERR2(r, EINVAL);
assert(get_max_memory == 73);
r = toku_ltm_get_max_lock_memory(ltm, NULL);
CKERR2(r, EINVAL);
assert(get_max_memory == 73);
r = toku_ltm_get_max_lock_memory(ltm, &get_max_memory);
CKERR(r);
assert(get_max_memory == max_lock_memory);
/* create tests. */
{
r = toku_lt_create(NULL, dbpanic, ltm,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, NULL, ltm,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, dbpanic, NULL,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, dbpanic, ltm,
NULL,
toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, dbpanic, ltm,
get_compare_fun_from_db,
NULL, toku_free, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, dbpanic, ltm,
get_compare_fun_from_db,
toku_malloc, NULL, toku_realloc);
CKERR2(r, EINVAL);
r = toku_lt_create(&lt, dbpanic, ltm,
get_compare_fun_from_db,
toku_malloc, toku_free, NULL);
CKERR2(r, EINVAL);
}
/* Close tests. */
r = toku_lt_close(NULL);
CKERR2(r, EINVAL);
do_point_test(toku_lt_acquire_read_lock);
do_point_test(toku_lt_acquire_write_lock);
do_range_test(toku_lt_acquire_range_read_lock);
do_range_test(toku_lt_acquire_range_write_lock);
#endif
toku_ltm_close(ltm);
return 0;
}
// test range write locks
#include "test.h"
int r;
toku_lock_tree* lt = NULL;
toku_ltm* ltm = NULL;
DB* db = (DB*)1;
enum { MAX_LT_LOCKS = 1000 };
uint32_t max_locks = MAX_LT_LOCKS;
uint64_t max_lock_memory = MAX_LT_LOCKS*64;
int nums[100];
DBT _keys_left[2];
DBT _keys_right[2];
DBT* keys_left[2];
DBT* keys_right[2];
toku_point qleft, qright;
toku_interval query;
toku_range* buf;
unsigned buflen;
unsigned numfound;
static void init_query(void) {
init_point(&qleft, lt);
init_point(&qright, lt);
qleft.key_payload = (void *) toku_lt_neg_infinity;
qright.key_payload = (void *) toku_lt_infinity;
memset(&query,0,sizeof(query));
query.left = &qleft;
query.right = &qright;
}
static void setup_tree(void) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, max_lock_memory, dbpanic,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, dbpanic, ltm,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
init_query();
}
static void close_tree(void) {
assert(lt && ltm);
r = toku_lt_close(lt); CKERR(r);
r = toku_ltm_close(ltm); CKERR(r);
lt = NULL;
ltm = NULL;
}
static void lt_verify(void) {
toku_lt_verify(lt, NULL);
}
typedef enum { null = -1, infinite = -2, neg_infinite = -3 } lt_infty;
static DBT* set_to_infty(DBT *dbt, int value) {
if (value == infinite)
return (DBT*)toku_lt_infinity;
if (value == neg_infinite)
return (DBT*)toku_lt_neg_infinity;
if (value == null)
return dbt_init(dbt, NULL, 0);
assert(0 <= value && (int) (sizeof nums / sizeof nums[0]));
return dbt_init(dbt, &nums[value], sizeof(nums[0]));
}
static void lt_insert(int r_expect, char txn, int key_l,
int key_r, BOOL read_flag) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
{
assert(key_left);
assert(!read_flag || key_right);
}
TXNID local_txn = (TXNID) (size_t) txn;
if (read_flag)
r = toku_lt_acquire_range_read_lock(lt, db, local_txn,
key_left,
key_right);
else
r = toku_lt_acquire_write_lock(lt, db, local_txn, key_left);
CKERR2(r, r_expect);
lt_verify();
}
static void lt_insert_read(int r_expect, char txn, int key_l, int key_r) UU();
static void lt_insert_read(int r_expect, char txn, int key_l, int key_r) {
lt_insert(r_expect, txn, key_l, key_r, TRUE);
}
static void lt_insert_write(int r_expect, char txn, int key_l) UU();
static void lt_insert_write(int r_expect, char txn, int key_l) {
lt_insert(r_expect, txn, key_l, 0, FALSE);
}
static void lt_insert_write_range(int r_expect, char txn, int key_l, int key_r) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
TXNID local_txn = (TXNID) (size_t) txn;
r = toku_lt_acquire_range_write_lock(lt, db, local_txn, key_left, key_right);
CKERR2(r, r_expect);
lt_verify();
}
static void lt_unlock(char ctxn) UU();
static void lt_unlock(char ctxn) {
int retval;
retval = toku_lt_unlock(lt, (TXNID) (size_t) ctxn);
CKERR(retval);
}
static void runtest(void) {
// no overlaps
setup_tree();
lt_insert_write(0, 'a', 1);
lt_insert_write_range(0, 'a', 10, 20);
lt_insert_write_range(0, 'a', 30, 40);
lt_insert_write(0, 'a', 25);
lt_insert_write(0, 'a', 50);
close_tree();
// no overlaps (reverse)
setup_tree();
lt_insert_write_range(0, 'a', 30, 40);
lt_insert_write_range(0, 'a', 10, 20);
close_tree();
// overlaps
setup_tree();
lt_insert_write_range(0, 'a', 5, 15);
lt_insert_write_range(0, 'a', 10, 20);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 5, 15);
lt_insert_write_range(0, 'a', 30, 40);
lt_insert_write_range(0, 'a', 10, 20);
close_tree();
// overlaps (reverse)
setup_tree();
lt_insert_write_range(0, 'a', 10, 20);
lt_insert_write_range(0, 'a', 5, 15);
close_tree();
// test borderwrite split
setup_tree();
lt_insert_write_range(0, 'a', 0, 1);
lt_insert_write_range(0, 'a', 5, 6);
lt_insert_write_range(0, 'a', 20, 30);
lt_insert_write_range(0, 'b', 10, 10);
close_tree();
// test borderwrite split
setup_tree();
lt_insert_write_range(0, 'a', 0, 5);
lt_insert_write_range(0, 'a', 20, 30);
lt_insert_write_range(0, 'b', 10, 10);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 15, 20);
lt_insert_write_range(0, 'a', 10, 30);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 10, 30);
lt_insert_write_range(0, 'a', 15, 20);
close_tree();
setup_tree();
lt_insert_write_range(0, 'b', 70, 80);
lt_insert_write_range(0, 'b', 60, 70);
lt_insert_write_range(0, 'b', 80, 90);
close_tree();
setup_tree();
lt_insert_write(0, 'a', 5);
lt_insert_write_range(0, 'a', 1, 20);
close_tree();
setup_tree();
lt_insert_write(0, 'a', 5);
lt_insert_write(0, 'a', 10);
close_tree();
setup_tree();
lt_insert_write(0, 'a', 5);
lt_insert_write(0, 'a', 10);
lt_insert_write_range(0, 'a', 1, 20);
close_tree();
}
static void init_test(void) {
for (unsigned i = 0; i < sizeof(nums)/sizeof(nums[0]); i++)
nums[i] = i;
buflen = 64;
buf = (toku_range*) toku_malloc(buflen*sizeof(toku_range));
}
static void close_test(void) {
toku_free(buf);
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
init_test();
runtest();
close_test();
return 0;
}
// test range write locks
#include "test.h"
int r;
toku_lock_tree* lt = NULL;
toku_ltm* ltm = NULL;
DB* db = (DB*)1;
enum { MAX_LT_LOCKS = 1000 };
uint32_t max_locks = MAX_LT_LOCKS;
uint64_t max_lock_memory = MAX_LT_LOCKS*64;
int nums[100];
DBT _keys_left[2];
DBT _keys_right[2];
DBT* keys_left[2];
DBT* keys_right[2];
toku_point qleft, qright;
toku_interval query;
toku_range* buf;
unsigned buflen;
unsigned numfound;
static void init_query(void) {
init_point(&qleft, lt);
init_point(&qright, lt);
qleft.key_payload = (void *) toku_lt_neg_infinity;
qright.key_payload = (void *) toku_lt_infinity;
memset(&query,0,sizeof(query));
query.left = &qleft;
query.right = &qright;
}
static void setup_tree(void) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, max_lock_memory, dbpanic,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, dbpanic, ltm,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
init_query();
}
static void close_tree(void) {
assert(lt && ltm);
r = toku_lt_close(lt); CKERR(r);
r = toku_ltm_close(ltm); CKERR(r);
lt = NULL;
ltm = NULL;
}
typedef enum { null = -1, infinite = -2, neg_infinite = -3 } lt_infty;
static DBT* set_to_infty(DBT *dbt, int value) {
if (value == infinite)
return (DBT*)toku_lt_infinity;
if (value == neg_infinite)
return (DBT*)toku_lt_neg_infinity;
if (value == null)
return dbt_init(dbt, NULL, 0);
assert(0 <= value && (int) (sizeof nums / sizeof nums[0]));
return dbt_init(dbt, &nums[value], sizeof(nums[0]));
}
static void lt_insert_read_range(int r_expect, char txn, int key_l, int key_r) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
TXNID local_txn = (TXNID) (size_t) txn;
r = toku_lt_acquire_range_read_lock(lt, db, local_txn,
key_left,
key_right);
CKERR2(r, r_expect);
}
static void lt_insert_write_range(int r_expect, char txn, int key_l, int key_r) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
TXNID local_txn = (TXNID) (size_t) txn;
r = toku_lt_acquire_range_write_lock(lt, db, local_txn, key_left, key_right);
CKERR2(r, r_expect);
}
static void lt_unlock(char ctxn) UU();
static void lt_unlock(char ctxn) {
int retval;
retval = toku_lt_unlock(lt, (TXNID) (size_t) ctxn);
CKERR(retval);
}
static void runtest(void) {
setup_tree();
lt_insert_read_range(0, 'a', 1, 50);
lt_insert_write_range(0, 'b', 51, 99);
close_tree();
setup_tree();
lt_insert_read_range(0, 'a', 1, 10);
lt_insert_read_range(0, 'a', 50, 60);
lt_insert_read_range(0, 'b', 80, 90);
lt_insert_write_range(0, 'b', 11, 20);
lt_insert_write_range(0, 'b', 75, 85);
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', 10, 11);
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', 55, 56);
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', 55, 65);
close_tree();
}
static void init_test(void) {
for (unsigned i = 0; i < sizeof(nums)/sizeof(nums[0]); i++)
nums[i] = i;
buflen = 64;
buf = (toku_range*) toku_malloc(buflen*sizeof(toku_range));
}
static void close_test(void) {
toku_free(buf);
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
init_test();
runtest();
close_test();
return 0;
}
// test write lock conflicts with write locks
#include "test.h"
int r;
toku_lock_tree* lt = NULL;
toku_ltm* ltm = NULL;
DB* db = (DB*)1;
enum { MAX_LT_LOCKS = 1000 };
uint32_t max_locks = MAX_LT_LOCKS;
uint64_t max_lock_memory = MAX_LT_LOCKS*64;
int nums[100];
DBT _keys_left[2];
DBT _keys_right[2];
DBT* keys_left[2];
DBT* keys_right[2];
toku_point qleft, qright;
toku_interval query;
toku_range* buf;
unsigned buflen;
unsigned numfound;
static void init_query(void) {
init_point(&qleft, lt);
init_point(&qright, lt);
qleft.key_payload = (void *) toku_lt_neg_infinity;
qright.key_payload = (void *) toku_lt_infinity;
memset(&query,0,sizeof(query));
query.left = &qleft;
query.right = &qright;
}
static void setup_tree(void) {
assert(!lt && !ltm);
r = toku_ltm_create(&ltm, max_locks, max_lock_memory, dbpanic,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(ltm);
r = toku_lt_create(&lt, dbpanic, ltm,
get_compare_fun_from_db,
toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(lt);
init_query();
}
static void close_tree(void) {
assert(lt && ltm);
r = toku_lt_close(lt); CKERR(r);
r = toku_ltm_close(ltm); CKERR(r);
lt = NULL;
ltm = NULL;
}
typedef enum { null = -1, infinite = -2, neg_infinite = -3 } lt_infty;
static DBT* set_to_infty(DBT *dbt, int value) {
if (value == infinite)
return (DBT*)toku_lt_infinity;
if (value == neg_infinite)
return (DBT*)toku_lt_neg_infinity;
if (value == null)
return dbt_init(dbt, NULL, 0);
assert(0 <= value && (int) (sizeof nums / sizeof nums[0]));
return dbt_init(dbt, &nums[value], sizeof(nums[0]));
}
static void lt_insert_read_range(int r_expect, char txn, int key_l, int key_r) UU();
static void lt_insert_read_range(int r_expect, char txn, int key_l, int key_r) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
TXNID local_txn = (TXNID) (size_t) txn;
r = toku_lt_acquire_range_read_lock(lt, db, local_txn,
key_left,
key_right);
CKERR2(r, r_expect);
}
static void lt_insert_write_range(int r_expect, char txn, int key_l, int key_r) {
DBT _key_left;
DBT _key_right;
DBT* key_left = &_key_left;
DBT* key_right = &_key_right;
key_left = set_to_infty(key_left, key_l);
key_right = set_to_infty(key_right, key_r);
TXNID local_txn = (TXNID) (size_t) txn;
r = toku_lt_acquire_range_write_lock(lt, db, local_txn, key_left, key_right);
CKERR2(r, r_expect);
}
static void lt_unlock(char ctxn) UU();
static void lt_unlock(char ctxn) {
int retval;
retval = toku_lt_unlock(lt, (TXNID) (size_t) ctxn);
CKERR(retval);
}
static void runtest(void) {
setup_tree();
lt_insert_write_range(0, 'a', 1, 50);
lt_insert_write_range(0, 'b', 51, 99);
close_tree();
setup_tree();
lt_insert_write_range(0, 'a', 1, 50);
lt_insert_write_range(0, 'b', 70, 80);
lt_insert_write_range(0, 'b', 60, 70);
lt_insert_write_range(0, 'b', 80, 90);
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', 50, 60);
lt_insert_write_range(DB_LOCK_NOTGRANTED, 'b', 50, 50);
close_tree();
}
static void init_test(void) {
for (unsigned i = 0; i < sizeof(nums)/sizeof(nums[0]); i++)
nums[i] = i;
buflen = 64;
buf = (toku_range*) toku_malloc(buflen*sizeof(toku_range));
}
static void close_test(void) {
toku_free(buf);
}
int main(int argc, const char *argv[]) {
parse_args(argc, argv);
init_test();
runtest();
close_test();
return 0;
}
This diff is collapsed.
This diff is collapsed.
......@@ -47,8 +47,10 @@ struct __toku_range_tree {
*/
static inline int toku__rt_p_cmp(toku_range_tree* tree,
toku_point* point, toku_interval* interval) {
if (tree->end_cmp(point, interval->left) < 0) return -1;
if (tree->end_cmp(point, interval->right) > 0) return 1;
if (tree->end_cmp(point, interval->left) < 0)
return -1;
if (tree->end_cmp(point, interval->right) > 0)
return 1;
return 0;
}
......@@ -58,9 +60,9 @@ static inline int toku__rt_increase_buffer(toku_range_tree* tree, toku_range** b
//TODO: SOME ATTRIBUTE TO REMOVE NEVER EXECUTABLE ERROR: assert(buflen);
if (*buflen < num) {
u_int32_t temp_len = *buflen;
while (temp_len < num) temp_len *= 2;
toku_range* temp_buf =
tree->realloc(*buf, temp_len * sizeof(toku_range));
while (temp_len < num)
temp_len *= 2;
toku_range* temp_buf = tree->realloc(*buf, temp_len * sizeof(toku_range));
if (!temp_buf) return errno;
*buf = temp_buf;
*buflen = temp_len;
......@@ -78,10 +80,12 @@ static inline int toku_rt_super_create(toku_range_tree** upperptree,
void* (*user_realloc)(void*, size_t)) {
toku_range_tree* temptree;
if (!upperptree || !ptree || !end_cmp || !data_cmp ||
!user_malloc || !user_free || !user_realloc) return EINVAL;
!user_malloc || !user_free || !user_realloc)
return EINVAL;
temptree = (toku_range_tree*)user_malloc(sizeof(toku_range_tree));
if (!temptree) return ENOMEM;
if (!temptree)
return ENOMEM;
//Any initializers go here.
memset(temptree, 0, sizeof(*temptree));
......
......@@ -241,6 +241,8 @@ int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size);
int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra);
void toku_rt_verify(toku_range_tree *tree);
#if defined(__cplusplus)
}
#endif
......
static toku_interval *
init_query(toku_interval* range, int left, int right) {
assert(0 <= left && left < (int) (sizeof nums / sizeof nums[0]));
range->left = (toku_point*)&nums[left];
assert(0 <= right && right < (int) (sizeof nums / sizeof nums[0]));
range->right = (toku_point*)&nums[right];
return range;
}
......@@ -8,8 +10,12 @@ init_query(toku_interval* range, int left, int right) {
static toku_range *
init_range (toku_range* range, int left, int right, int data) {
init_query(&range->ends, left, right);
if (data < 0) range->data = 0;
else range->data = (TXNID)letters[data];
if (data < 0) {
range->data = 0;
} else {
assert(0 <= data && data < (int) (sizeof letters / sizeof letters[0]));
range->data = (TXNID)letters[data];
}
return range;
}
......@@ -37,6 +43,7 @@ runinsert (int rexpect, toku_range* toinsert) {
int r;
r = toku_rt_insert(tree, toinsert);
CKERR2(r, rexpect);
toku_rt_verify(tree);
}
static __attribute__((__unused__)) void
......@@ -56,6 +63,26 @@ runsearch (int rexpect, toku_interval* query, toku_range* expect) {
char_cmp(buf[0].data, expect->data) == 0);
}
static __attribute__((__unused__)) void
runsearch2 (int rexpect, toku_interval* query, toku_range* expect1, toku_range *expect2);
static void
runsearch2 (int rexpect, toku_interval* query, toku_range* expect1, toku_range *expect2) {
int r;
unsigned found;
r = toku_rt_find(tree, query, 0, &buf, &buflen, &found);
CKERR2(r, rexpect);
if (rexpect != 0) return;
assert(found == 2);
assert(int_cmp(buf[0].ends.left, expect1->ends.left) == 0 &&
int_cmp(buf[0].ends.right, expect1->ends.right) == 0 &&
char_cmp(buf[0].data, expect1->data) == 0);
assert(int_cmp(buf[1].ends.left, expect2->ends.left) == 0 &&
int_cmp(buf[1].ends.right, expect2->ends.right) == 0 &&
char_cmp(buf[1].data, expect2->data) == 0);
}
static __attribute__((__unused__)) void
runlimitsearch (toku_interval* query, unsigned limit, unsigned findexpect);
......
......@@ -15,7 +15,6 @@ int main(int argc, const char *argv[]) {
r = toku_rt_create(&tree, NULL, TXNID_cmp, FALSE, toku_malloc, toku_free, toku_realloc);
CKERR2(r, EINVAL);
assert(tree == NULL);
r = toku_rt_create(&tree, int_cmp, NULL, FALSE, toku_malloc, toku_free, toku_realloc);
......@@ -29,7 +28,6 @@ int main(int argc, const char *argv[]) {
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, toku_malloc, toku_free, NULL);
CKERR2(r, EINVAL);
assert(tree == NULL);
/* Close tests */
......@@ -179,6 +177,20 @@ int main(int argc, const char *argv[]) {
r = toku_rt_close(tree); CKERR(r);
tree = NULL;
/* size tests */
r = toku_rt_create(&tree, int_cmp, TXNID_cmp, FALSE, toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(tree != NULL);
r = toku_rt_get_size(NULL, NULL); CKERR2(r, EINVAL);
r = toku_rt_get_size(tree, NULL); CKERR2(r, EINVAL);
u_int32_t tree_size;
r = toku_rt_get_size(NULL, &tree_size); CKERR2(r, EINVAL);
r = toku_rt_get_size(tree, &tree_size); CKERR(r);
r = toku_rt_close(tree); CKERR(r);
tree = NULL;
/* That's it: clean up and go home */
toku_free(buf);
buf = NULL;
......
......@@ -102,6 +102,17 @@ static void tests(BOOL allow_overlaps) {
setup_tree(allow_overlaps, TRUE, 0, 3, 0);
runinsert((allow_overlaps ? 0 : EDOM), init_range(&toinsert, 0, 3, 1));
close_tree();
/* Tree: {(|1-3|,0),(|5-6|,0)} */
setup_tree(allow_overlaps, TRUE, 1, 3, 0);
runinsert(0, init_range(&toinsert, 5, 6, 0));
runsearch(0, init_query(&query, 3, 4), init_range(&expect, 1, 3, 0));
runsearch(0, init_query(&query, 4, 5), init_range(&expect, 5, 6, 0));
runsearch(0, init_query(&query, 4, 6), init_range(&expect, 5, 6, 0));
runsearch(0, init_query(&query, 4, 7), init_range(&expect, 5, 6, 0));
toku_range expect1, expect2;
runsearch2(0, init_query(&query, 3, 7), init_range(&expect1, 1, 3, 0), init_range(&expect2, 5, 6, 0));
close_tree();
}
int main(int argc, const char *argv[]) {
......
// test that the toku_rt_clear function works
#include "test.h"
static int count_range_callback(toku_range *range UU(), void *extra) {
int *counter = (int *) extra;
*counter += 1;
return 0;
}
static int count_ranges(toku_range_tree *tree) {
int counter = 0;
int r = toku_rt_iterate(tree, count_range_callback, &counter); CKERR(r);
return counter;
}
static void my_init_range(toku_range *range, int *left, int *right, int data) {
range->ends.left = (toku_point *) left;
range->ends.right = (toku_point *) right;
range->data = data;
}
int main(int argc, const char *argv[]) {
int r;
parse_args(argc, argv);
toku_range_tree *tree;
r = toku_rt_create(&tree, int_cmp, char_cmp, FALSE, toku_malloc, toku_free, toku_realloc); CKERR(r);
assert(count_ranges(tree) == 0);
const int nranges = 10;
int nums[nranges];
for (int i = 0; i < nranges; i++) {
assert(count_ranges(tree) == i);
u_int32_t treesize = 0;
r = toku_rt_get_size(tree, &treesize); CKERR(r);
assert(treesize == (u_int32_t) i);
nums[i] = i;
toku_range range; my_init_range(&range, &nums[i], &nums[i], 'a');
r = toku_rt_insert(tree, &range); CKERR(r);
}
assert(count_ranges(tree) == nranges);
toku_rt_clear(tree);
assert(count_ranges(tree) == 0);
r = toku_rt_close(tree); CKERR(r);
return 0;
}
// test that deleting an overlapping range fails
#include "test.h"
static void my_init_range(toku_range *range, int *left, int *right, int data) {
range->ends.left = (toku_point *) left;
range->ends.right = (toku_point *) right;
range->data = data;
}
int main(int argc, const char *argv[]) {
int r;
parse_args(argc, argv);
toku_range_tree *tree;
r = toku_rt_create(&tree, int_cmp, char_cmp, FALSE, toku_malloc, toku_free, toku_realloc); CKERR(r);
int insert_left = 10; int insert_right = 20;
toku_range insert_range; my_init_range(&insert_range, &insert_left, &insert_right, 'a');
r = toku_rt_insert(tree, &insert_range); CKERR(r);
int delete_left = 5; int delete_right = 15;
toku_range delete_range; my_init_range(&delete_range, &delete_left, &delete_right, 'b');
r = toku_rt_delete(tree, &delete_range);
assert(r == EDOM);
r = toku_rt_close(tree); CKERR(r);
return 0;
}
......@@ -91,6 +91,8 @@ BDB_DONTRUN_TESTS = \
checkpoint_stress \
checkpoint_truncate_1 \
cursor-isolation \
cursor-set-del-rmw \
cursor-set-range-rmw \
del-simple \
del-multiple \
del-multiple-huge-primary-row \
......@@ -141,6 +143,10 @@ BDB_DONTRUN_TESTS = \
multiprocess \
mvcc-create-table \
mvcc-many-committed \
prelock-read-read \
prelock-read-write \
prelock-write-read \
prelock-write-write \
powerfail \
preload-db \
preload-db-nested \
......@@ -204,6 +210,7 @@ BDB_DONTRUN_TESTS = \
recovery_fileops_unit \
recovery_stress \
redirect \
replace-into-write-lock \
root_fifo_2 \
root_fifo_32 \
root_fifo_41 \
......
#include "test.h"
// TODO
static void test_del_rmw(DB_ENV *env, DB *db, uint32_t t1_flags, uint32_t t2_flags, uint32_t c1_flags, uint32_t c2_flags, int expect_r) {
int r;
{
DB_TXN *write_txn = NULL;
r = env->txn_begin(env, NULL, &write_txn, 0); assert_zero(r);
for (int i = 1; i <= 3; i++) {
int k = htonl(i); int v = i;
DBT key; dbt_init(&key, &k, sizeof k);
DBT val; dbt_init(&val, &v, sizeof v);
r = db->put(db, write_txn, &key, &val, DB_YESOVERWRITE); assert_zero(r);
}
r = write_txn->commit(write_txn, 0); assert_zero(r);
}
{
DB_TXN *txn1 = NULL;
r = env->txn_begin(env, NULL, &txn1, t1_flags); assert_zero(r);
DB_TXN *txn2 = NULL;
r = env->txn_begin(env, NULL, &txn2, t2_flags); assert_zero(r);
DBC *c1 = NULL;
r = db->cursor(db, txn1, &c1, c1_flags); assert_zero(r);
DBC *c2 = NULL;
r = db->cursor(db, txn2, &c2, c2_flags); assert_zero(r);
r = c1->c_pre_acquire_range_lock(c1, db->dbt_neg_infty(), db->dbt_pos_infty()); assert_zero(r);
int k = htonl(2);
DBT key; dbt_init(&key, &k, sizeof k);
r = db->del(db, txn1, &key, 0); assert_zero(r);
k = htonl(1);
DBT val; memset(&val, 0, sizeof val);
r = c2->c_get(c2, &key, &val, DB_SET); assert(r == expect_r);
r = c1->c_close(c1); assert_zero(r);
r = c2->c_close(c2); assert_zero(r);
r = txn1->commit(txn1, 0); assert_zero(r);
r = txn2->commit(txn2, 0); assert_zero(r);
}
}
int test_main(int argc, char * const argv[]) {
int r;
char *env_dir = ENVDIR;
char *db_filename = "rmwtest";
parse_args(argc, argv);
char rm_cmd[strlen(env_dir) + strlen("rm -rf ") + 1];
snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", env_dir);
r = system(rm_cmd); assert_zero(r);
r = toku_os_mkdir(env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); assert_zero(r);
DB_ENV *env = NULL;
r = db_env_create(&env, 0); assert_zero(r);
int env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG;
r = env->open(env, env_dir, env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
// create the db
DB *db = NULL;
r = db_create(&db, env, 0); assert_zero(r);
DB_TXN *create_txn = NULL;
r = env->txn_begin(env, NULL, &create_txn, 0); assert_zero(r);
r = db->open(db, create_txn, db_filename, NULL, DB_BTREE, DB_CREATE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
r = create_txn->commit(create_txn, 0); assert_zero(r);
// t1: prelock read, del(2)
// t2: set(1)
test_del_rmw(env, db, DB_SERIALIZABLE, DB_READ_UNCOMMITTED, 0, 0, 0);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_READ_COMMITTED, 0, 0, 0);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_TXN_SNAPSHOT, 0, 0, 0);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_SERIALIZABLE, 0, 0, 0);
// t1: prelock write, del(2)
// t2: set(1)
test_del_rmw(env, db, DB_SERIALIZABLE, DB_READ_UNCOMMITTED, DB_RMW, 0, 0);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_READ_COMMITTED, DB_RMW, 0, 0);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_TXN_SNAPSHOT , DB_RMW, 0, 0);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_SERIALIZABLE, DB_RMW, 0, DB_LOCK_NOTGRANTED);
// t1: prelock write, del(2)
// t2: rmw set(1)
test_del_rmw(env, db, DB_SERIALIZABLE, DB_READ_UNCOMMITTED, DB_RMW, DB_RMW, DB_LOCK_NOTGRANTED);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_READ_COMMITTED, DB_RMW, DB_RMW, DB_LOCK_NOTGRANTED);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_TXN_SNAPSHOT , DB_RMW, DB_RMW, DB_LOCK_NOTGRANTED);
test_del_rmw(env, db, DB_SERIALIZABLE, DB_SERIALIZABLE, DB_RMW, DB_RMW, DB_LOCK_NOTGRANTED);
r = db->close(db, 0); assert_zero(r);
r = env->close(env, 0); assert_zero(r);
return 0;
}
#include "test.h"
// verify that the DB_RMW flag on cursor create grabs write locks for cursor set operations
static void test_create_rmw(DB_ENV *env, DB *db, int k, uint32_t txn1_flags, uint32_t txn2_flags, int expect_r) {
int r;
DB_TXN *txn1 = NULL;
r = env->txn_begin(env, NULL, &txn1, 0); assert_zero(r);
DB_TXN *txn2 = NULL;
r = env->txn_begin(env, NULL, &txn2, 0); assert_zero(r);
DBC *c1 = NULL;
r = db->cursor(db, txn1, &c1, txn1_flags); assert_zero(r);
DBC *c2 = NULL;
r = db->cursor(db, txn2, &c2, txn2_flags); assert_zero(r);
DBT key; dbt_init(&key, &k, sizeof k);
DBT val; memset(&val, 0, sizeof val);
r = c1->c_get(c1, &key, &val, DB_SET); assert_zero(r);
r = c2->c_get(c2, &key, &val, DB_SET); assert(r == expect_r);
r = c1->c_close(c1); assert_zero(r);
r = c2->c_close(c2); assert_zero(r);
r = txn1->commit(txn1, 0); assert_zero(r);
r = txn2->commit(txn2, 0); assert_zero(r);
}
// verify that the DB_RMW flag to the cursor set operations grabs write locks
static void test_set_rmw(DB_ENV *env, DB *db, int k, uint32_t txn1_flags, uint32_t txn2_flags, int expect_r) {
int r;
DB_TXN *txn1 = NULL;
r = env->txn_begin(env, NULL, &txn1, 0); assert_zero(r);
DB_TXN *txn2 = NULL;
r = env->txn_begin(env, NULL, &txn2, 0); assert_zero(r);
DBC *c1 = NULL;
r = db->cursor(db, txn1, &c1, 0); assert_zero(r);
DBC *c2 = NULL;
r = db->cursor(db, txn2, &c2, 0); assert_zero(r);
DBT key; dbt_init(&key, &k, sizeof k);
DBT val; memset(&val, 0, sizeof val);
r = c1->c_get(c1, &key, &val, DB_SET + txn1_flags); assert_zero(r);
r = c2->c_get(c2, &key, &val, DB_SET + txn2_flags); assert(r == expect_r);
r = c1->c_close(c1); assert_zero(r);
r = c2->c_close(c2); assert_zero(r);
r = txn1->commit(txn1, 0); assert_zero(r);
r = txn2->commit(txn2, 0); assert_zero(r);
}
int test_main(int argc, char * const argv[]) {
int r;
char *env_dir = ENVDIR;
char *db_filename = "rmwtest";
parse_args(argc, argv);
char rm_cmd[strlen(env_dir) + strlen("rm -rf ") + 1];
snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", env_dir);
r = system(rm_cmd); assert_zero(r);
r = toku_os_mkdir(env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); assert_zero(r);
DB_ENV *env = NULL;
r = db_env_create(&env, 0); assert_zero(r);
int env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG;
r = env->open(env, env_dir, env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
// create the db
DB *db = NULL;
r = db_create(&db, env, 0); assert_zero(r);
DB_TXN *create_txn = NULL;
r = env->txn_begin(env, NULL, &create_txn, 0); assert_zero(r);
r = db->open(db, create_txn, db_filename, NULL, DB_BTREE, DB_CREATE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
r = create_txn->commit(create_txn, 0); assert_zero(r);
DB_TXN *write_txn = NULL;
r = env->txn_begin(env, NULL, &write_txn, 0); assert_zero(r);
int k = htonl(42); int v = 42;
DBT key; dbt_init(&key, &k, sizeof k);
DBT val; dbt_init(&val, &v, sizeof v);
r = db->put(db, write_txn, &key, &val, DB_NOOVERWRITE); assert_zero(r);
r = write_txn->commit(write_txn, 0); assert_zero(r);
test_set_rmw(env, db, k, 0, 0, 0);
test_set_rmw(env, db, k, 0, DB_RMW, DB_LOCK_NOTGRANTED);
test_set_rmw(env, db, k, DB_RMW, 0, DB_LOCK_NOTGRANTED);
test_set_rmw(env, db, k, DB_RMW, DB_RMW, DB_LOCK_NOTGRANTED);
test_create_rmw(env, db, k, 0, 0, 0);
test_create_rmw(env, db, k, 0, DB_RMW, DB_LOCK_NOTGRANTED);
test_create_rmw(env, db, k, DB_RMW, 0, DB_LOCK_NOTGRANTED);
test_create_rmw(env, db, k, DB_RMW, DB_RMW, DB_LOCK_NOTGRANTED);
r = db->close(db, 0); assert_zero(r);
r = env->close(env, 0); assert_zero(r);
return 0;
}
#include "test.h"
// verify that prelocking read ranges on multiple transactions do not conflict
static int prelock_range(DBC *cursor, int left, int right) {
DBT key_left; dbt_init(&key_left, &left, sizeof left);
DBT key_right; dbt_init(&key_right, &right, sizeof right);
int r = cursor->c_pre_acquire_range_lock(cursor, &key_left, &key_right);
return r;
}
static void test_read_read(DB_ENV *env, DB *db, uint32_t iso_flags, int expect_r) {
int r;
DB_TXN *txn_a = NULL;
r = env->txn_begin(env, NULL, &txn_a, iso_flags); assert_zero(r);
DB_TXN *txn_b = NULL;
r = env->txn_begin(env, NULL, &txn_b, iso_flags); assert_zero(r);
DBC *cursor_a = NULL;
r = db->cursor(db, txn_a, &cursor_a, 0); assert_zero(r);
DBC *cursor_b = NULL;
r = db->cursor(db, txn_b, &cursor_b, 0); assert_zero(r);
r = prelock_range(cursor_a, htonl(10), htonl(100)); assert_zero(r);
r = prelock_range(cursor_b, htonl(50), htonl(200)); assert(r == expect_r);
r = cursor_a->c_close(cursor_a); assert_zero(r);
r = cursor_b->c_close(cursor_b); assert_zero(r);
r = txn_a->commit(txn_a, 0); assert_zero(r);
r = txn_b->commit(txn_b, 0); assert_zero(r);
}
int test_main(int argc, char * const argv[]) {
int r;
char *env_dir = ENVDIR;
char *db_filename = "prelocktest";
parse_args(argc, argv);
char rm_cmd[strlen(env_dir) + strlen("rm -rf ") + 1];
snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", env_dir);
r = system(rm_cmd); assert_zero(r);
r = toku_os_mkdir(env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); assert_zero(r);
DB_ENV *env = NULL;
r = db_env_create(&env, 0); assert_zero(r);
int env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG;
r = env->open(env, env_dir, env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
// create the db
DB *db = NULL;
r = db_create(&db, env, 0); assert_zero(r);
DB_TXN *create_txn = NULL;
r = env->txn_begin(env, NULL, &create_txn, 0); assert_zero(r);
r = db->open(db, create_txn, db_filename, NULL, DB_BTREE, DB_CREATE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
r = create_txn->commit(create_txn, 0); assert_zero(r);
test_read_read(env, db, DB_READ_UNCOMMITTED, 0);
test_read_read(env, db, DB_READ_UNCOMMITTED, 0);
test_read_read(env, db, DB_SERIALIZABLE, 0);
r = db->close(db, 0); assert_zero(r);
r = env->close(env, 0); assert_zero(r);
return 0;
}
#include "test.h"
// verify that prelocking a write range that overlapping a read lock conflicts
static int prelock_range(DBC *cursor, int left, int right) {
DBT key_left; dbt_init(&key_left, &left, sizeof left);
DBT key_right; dbt_init(&key_right, &right, sizeof right);
int r = cursor->c_pre_acquire_range_lock(cursor, &key_left, &key_right);
return r;
}
static void test_read_write(DB_ENV *env, DB *db, uint32_t iso_flags, int expect_r) {
int r;
DB_TXN *txn_a = NULL;
r = env->txn_begin(env, NULL, &txn_a, iso_flags); assert_zero(r);
DB_TXN *txn_b = NULL;
r = env->txn_begin(env, NULL, &txn_b, iso_flags); assert_zero(r);
DBC *cursor_a = NULL;
r = db->cursor(db, txn_a, &cursor_a, 0); assert_zero(r);
DBC *cursor_b = NULL;
r = db->cursor(db, txn_b, &cursor_b, DB_RMW); assert_zero(r);
r = prelock_range(cursor_a, htonl(10), htonl(100)); assert_zero(r);
r = prelock_range(cursor_b, htonl(50), htonl(200)); assert(r == expect_r);
r = cursor_a->c_close(cursor_a); assert_zero(r);
r = cursor_b->c_close(cursor_b); assert_zero(r);
r = txn_a->commit(txn_a, 0); assert_zero(r);
r = txn_b->commit(txn_b, 0); assert_zero(r);
}
int test_main(int argc, char * const argv[]) {
int r;
char *env_dir = ENVDIR;
char *db_filename = "prelocktest";
parse_args(argc, argv);
char rm_cmd[strlen(env_dir) + strlen("rm -rf ") + 1];
snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", env_dir);
r = system(rm_cmd); assert_zero(r);
r = toku_os_mkdir(env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); assert_zero(r);
DB_ENV *env = NULL;
r = db_env_create(&env, 0); assert_zero(r);
int env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG;
r = env->open(env, env_dir, env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
// create the db
DB *db = NULL;
r = db_create(&db, env, 0); assert_zero(r);
DB_TXN *create_txn = NULL;
r = env->txn_begin(env, NULL, &create_txn, 0); assert_zero(r);
r = db->open(db, create_txn, db_filename, NULL, DB_BTREE, DB_CREATE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
r = create_txn->commit(create_txn, 0); assert_zero(r);
test_read_write(env, db, DB_SERIALIZABLE, DB_LOCK_NOTGRANTED);
r = db->close(db, 0); assert_zero(r);
r = env->close(env, 0); assert_zero(r);
return 0;
}
#include "test.h"
// verify that prelocking a write range that overlapping a read lock conflicts
static int prelock_range(DBC *cursor, int left, int right) {
DBT key_left; dbt_init(&key_left, &left, sizeof left);
DBT key_right; dbt_init(&key_right, &right, sizeof right);
int r = cursor->c_pre_acquire_range_lock(cursor, &key_left, &key_right);
return r;
}
static void test_write_read(DB_ENV *env, DB *db, uint32_t iso_flags, int expect_r) {
int r;
DB_TXN *txn_a = NULL;
r = env->txn_begin(env, NULL, &txn_a, iso_flags); assert_zero(r);
DB_TXN *txn_b = NULL;
r = env->txn_begin(env, NULL, &txn_b, iso_flags); assert_zero(r);
DBC *cursor_a = NULL;
r = db->cursor(db, txn_a, &cursor_a, DB_RMW); assert_zero(r);
DBC *cursor_b = NULL;
r = db->cursor(db, txn_b, &cursor_b, 0); assert_zero(r);
r = prelock_range(cursor_a, htonl(10), htonl(100)); assert_zero(r);
r = prelock_range(cursor_b, htonl(50), htonl(200)); assert(r == expect_r);
r = cursor_a->c_close(cursor_a); assert_zero(r);
r = cursor_b->c_close(cursor_b); assert_zero(r);
r = txn_a->commit(txn_a, 0); assert_zero(r);
r = txn_b->commit(txn_b, 0); assert_zero(r);
}
int test_main(int argc, char * const argv[]) {
int r;
char *env_dir = ENVDIR;
char *db_filename = "prelocktest";
parse_args(argc, argv);
char rm_cmd[strlen(env_dir) + strlen("rm -rf ") + 1];
snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", env_dir);
r = system(rm_cmd); assert_zero(r);
r = toku_os_mkdir(env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); assert_zero(r);
DB_ENV *env = NULL;
r = db_env_create(&env, 0); assert_zero(r);
int env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG;
r = env->open(env, env_dir, env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
// create the db
DB *db = NULL;
r = db_create(&db, env, 0); assert_zero(r);
DB_TXN *create_txn = NULL;
r = env->txn_begin(env, NULL, &create_txn, 0); assert_zero(r);
r = db->open(db, create_txn, db_filename, NULL, DB_BTREE, DB_CREATE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
r = create_txn->commit(create_txn, 0); assert_zero(r);
test_write_read(env, db, DB_SERIALIZABLE, DB_LOCK_NOTGRANTED);
r = db->close(db, 0); assert_zero(r);
r = env->close(env, 0); assert_zero(r);
return 0;
}
#include "test.h"
// verify that prelocking a write range that overlaps a write lock conflicts
static int prelock_range(DBC *cursor, int left, int right) {
DBT key_left; dbt_init(&key_left, &left, sizeof left);
DBT key_right; dbt_init(&key_right, &right, sizeof right);
int r = cursor->c_pre_acquire_range_lock(cursor, &key_left, &key_right);
return r;
}
static void test_write_write(DB_ENV *env, DB *db, uint32_t iso_flags, int expect_r) {
int r;
DB_TXN *txn_a = NULL;
r = env->txn_begin(env, NULL, &txn_a, iso_flags); assert_zero(r);
DB_TXN *txn_b = NULL;
r = env->txn_begin(env, NULL, &txn_b, iso_flags); assert_zero(r);
DBC *cursor_a = NULL;
r = db->cursor(db, txn_a, &cursor_a, DB_RMW); assert_zero(r);
DBC *cursor_b = NULL;
r = db->cursor(db, txn_b, &cursor_b, DB_RMW); assert_zero(r);
r = prelock_range(cursor_a, htonl(10), htonl(100)); assert_zero(r);
r = prelock_range(cursor_b, htonl(50), htonl(200)); assert(r == expect_r);
r = cursor_a->c_close(cursor_a); assert_zero(r);
r = cursor_b->c_close(cursor_b); assert_zero(r);
r = txn_a->commit(txn_a, 0); assert_zero(r);
r = txn_b->commit(txn_b, 0); assert_zero(r);
}
int test_main(int argc, char * const argv[]) {
int r;
char *env_dir = ENVDIR;
char *db_filename = "prelocktest";
parse_args(argc, argv);
char rm_cmd[strlen(env_dir) + strlen("rm -rf ") + 1];
snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", env_dir);
r = system(rm_cmd); assert_zero(r);
r = toku_os_mkdir(env_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); assert_zero(r);
DB_ENV *env = NULL;
r = db_env_create(&env, 0); assert_zero(r);
int env_open_flags = DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL | DB_INIT_TXN | DB_INIT_LOCK | DB_INIT_LOG;
r = env->open(env, env_dir, env_open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
// create the db
DB *db = NULL;
r = db_create(&db, env, 0); assert_zero(r);
DB_TXN *create_txn = NULL;
r = env->txn_begin(env, NULL, &create_txn, 0); assert_zero(r);
r = db->open(db, create_txn, db_filename, NULL, DB_BTREE, DB_CREATE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); assert_zero(r);
r = create_txn->commit(create_txn, 0); assert_zero(r);
test_write_write(env, db, DB_SERIALIZABLE, DB_LOCK_NOTGRANTED);
r = db->close(db, 0); assert_zero(r);
r = env->close(env, 0); assert_zero(r);
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment