mirror of
https://github.com/MariaDB/server.git
synced 2025-02-02 03:51:50 +01:00
#3497 merge fractal tree code to main refs[t:3497]
git-svn-id: file:///svn/toku/tokudb@31566 c7de825b-a66e-492c-adef-691d508d4ae1
This commit is contained in:
parent
439d156cdf
commit
0e4a166305
40 changed files with 2814 additions and 994 deletions
|
@ -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);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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();
|
||||
|
|
155
src/lock_tree/tests/test_borderwrite_merge.c
Normal file
155
src/lock_tree/tests/test_borderwrite_merge.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
// 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(<m, 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(<, 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;
|
||||
}
|
172
src/lock_tree/tests/test_global_write_lock.c
Normal file
172
src/lock_tree/tests/test_global_write_lock.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
// 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(<m, 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(<, 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;
|
||||
}
|
117
src/lock_tree/tests/test_ltm_get_status.c
Normal file
117
src/lock_tree/tests/test_ltm_get_status.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* 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(<m, 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(<, NULL, ltm,
|
||||
get_compare_fun_from_db,
|
||||
toku_malloc, toku_free, toku_realloc);
|
||||
CKERR2(r, EINVAL);
|
||||
|
||||
r = toku_lt_create(<, dbpanic, NULL,
|
||||
get_compare_fun_from_db,
|
||||
toku_malloc, toku_free, toku_realloc);
|
||||
CKERR2(r, EINVAL);
|
||||
|
||||
r = toku_lt_create(<, dbpanic, ltm,
|
||||
NULL,
|
||||
toku_malloc, toku_free, toku_realloc);
|
||||
CKERR2(r, EINVAL);
|
||||
|
||||
r = toku_lt_create(<, dbpanic, ltm,
|
||||
get_compare_fun_from_db,
|
||||
NULL, toku_free, toku_realloc);
|
||||
CKERR2(r, EINVAL);
|
||||
r = toku_lt_create(<, dbpanic, ltm,
|
||||
get_compare_fun_from_db,
|
||||
toku_malloc, NULL, toku_realloc);
|
||||
CKERR2(r, EINVAL);
|
||||
r = toku_lt_create(<, 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;
|
||||
}
|
240
src/lock_tree/tests/test_write_range.c
Normal file
240
src/lock_tree/tests/test_write_range.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
// 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(<m, 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(<, 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;
|
||||
}
|
151
src/lock_tree/tests/test_write_range_conflict_read.c
Normal file
151
src/lock_tree/tests/test_write_range_conflict_read.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
// 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(<m, 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(<, 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;
|
||||
}
|
150
src/lock_tree/tests/test_write_range_conflict_write.c
Normal file
150
src/lock_tree/tests/test_write_range_conflict_write.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
// 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(<m, 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(<, 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;
|
||||
}
|
|
@ -27,41 +27,43 @@ struct __toku_range_tree_local {
|
|||
|
||||
static const u_int32_t minlen = 64;
|
||||
|
||||
static inline int toku__rt_decrease_capacity(toku_range_tree* tree,
|
||||
u_int32_t _num) {
|
||||
static inline int
|
||||
toku__rt_decrease_capacity(toku_range_tree* tree, u_int32_t _num) {
|
||||
//TODO: SOME ATTRIBUTE TO REMOVE NEVER EXECUTABLE ERROR: assert(tree);
|
||||
u_int32_t num = _num < minlen ? minlen : _num;
|
||||
|
||||
if (tree->i.ranges_len >= num * 2) {
|
||||
u_int32_t temp_len = tree->i.ranges_len;
|
||||
while (temp_len >= num * 2) temp_len /= 2;
|
||||
while (temp_len >= num * 2)
|
||||
temp_len /= 2;
|
||||
assert(temp_len >= _num); //Sanity check.
|
||||
toku_range* temp_ranges =
|
||||
tree->realloc(tree->i.ranges, temp_len * sizeof(toku_range));
|
||||
if (!temp_ranges) return errno;
|
||||
toku_range* temp_ranges = tree->realloc(tree->i.ranges, temp_len * sizeof(toku_range));
|
||||
if (!temp_ranges)
|
||||
return errno;
|
||||
tree->i.ranges = temp_ranges;
|
||||
tree->i.ranges_len = temp_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int toku__rt_increase_capacity(toku_range_tree* tree,
|
||||
u_int32_t num) {
|
||||
static inline int
|
||||
toku__rt_increase_capacity(toku_range_tree* tree, u_int32_t num) {
|
||||
//TODO: SOME ATTRIBUTE TO REMOVE NEVER EXECUTABLE ERROR: assert(tree);
|
||||
if (tree->i.ranges_len < num) {
|
||||
u_int32_t temp_len = tree->i.ranges_len;
|
||||
while (temp_len < num) temp_len *= 2;
|
||||
toku_range* temp_ranges =
|
||||
tree->realloc(tree->i.ranges, temp_len * sizeof(toku_range));
|
||||
if (!temp_ranges) return errno;
|
||||
while (temp_len < num)
|
||||
temp_len *= 2;
|
||||
toku_range* temp_ranges = tree->realloc(tree->i.ranges, temp_len * sizeof(toku_range));
|
||||
if (!temp_ranges)
|
||||
return errno;
|
||||
tree->i.ranges = temp_ranges;
|
||||
tree->i.ranges_len = temp_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline BOOL toku__rt_overlap(toku_range_tree* tree,
|
||||
toku_interval* a, toku_interval* b) {
|
||||
static inline BOOL
|
||||
toku__rt_overlap(toku_range_tree* tree, toku_interval* a, toku_interval* b) {
|
||||
assert(tree);
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
@ -70,8 +72,8 @@ static inline BOOL toku__rt_overlap(toku_range_tree* tree,
|
|||
(tree->end_cmp(b->left, a->right) <= 0));
|
||||
}
|
||||
|
||||
static inline BOOL toku__rt_exact(toku_range_tree* tree,
|
||||
toku_range* a, toku_range* b) {
|
||||
static inline BOOL
|
||||
toku__rt_exact(toku_range_tree* tree, toku_range* a, toku_range* b) {
|
||||
assert(tree);
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
@ -81,200 +83,243 @@ static inline BOOL toku__rt_exact(toku_range_tree* tree,
|
|||
(tree->data_cmp(a->data, b->data) == 0));
|
||||
}
|
||||
|
||||
static inline int toku__rt_cmp(toku_range_tree* tree,
|
||||
toku_range* a, toku_range* b) {
|
||||
static inline int
|
||||
toku__rt_cmp(toku_range_tree* tree, toku_range* a, toku_range* b) {
|
||||
int cmp = 0;
|
||||
assert(tree);
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
cmp = tree->end_cmp(a->ends.left, b->ends.left);
|
||||
if (cmp!=0) { goto cleanup; }
|
||||
if (cmp != 0)
|
||||
goto cleanup;
|
||||
cmp = tree->end_cmp(a->ends.right, b->ends.right);
|
||||
if (cmp!=0) { goto cleanup; }
|
||||
if (cmp != 0)
|
||||
goto cleanup;
|
||||
cmp = tree->data_cmp(a->data, b->data);
|
||||
if (cmp!=0) { goto cleanup; }
|
||||
if (cmp != 0)
|
||||
goto cleanup;
|
||||
|
||||
cmp = 0;
|
||||
cleanup:
|
||||
return cmp;
|
||||
}
|
||||
|
||||
int toku_rt_create(toku_range_tree** ptree,
|
||||
int (*end_cmp)(const toku_point*,const toku_point*),
|
||||
int (*data_cmp)(const TXNID,const TXNID),
|
||||
BOOL allow_overlaps,
|
||||
void* (*user_malloc) (size_t),
|
||||
void (*user_free) (void*),
|
||||
void* (*user_realloc)(void*, size_t)) {
|
||||
int
|
||||
toku_rt_create(toku_range_tree** ptree,
|
||||
int (*end_cmp)(const toku_point*,const toku_point*),
|
||||
int (*data_cmp)(const TXNID,const TXNID),
|
||||
BOOL allow_overlaps,
|
||||
void* (*user_malloc) (size_t),
|
||||
void (*user_free) (void*),
|
||||
void* (*user_realloc)(void*, size_t)) {
|
||||
int r;
|
||||
toku_range_tree* tmptree;
|
||||
|
||||
if (!ptree) return EINVAL;
|
||||
if (!ptree)
|
||||
return EINVAL;
|
||||
r = toku_rt_super_create(ptree, &tmptree, end_cmp, data_cmp, allow_overlaps,
|
||||
user_malloc, user_free, user_realloc);
|
||||
if (0) {
|
||||
died1:
|
||||
died1:
|
||||
user_free(tmptree);
|
||||
return r;
|
||||
}
|
||||
if (r!=0) return r;
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
//Any local initializers go here.
|
||||
tmptree->i.ranges_len = minlen;
|
||||
tmptree->i.ranges = (toku_range*)
|
||||
user_malloc(tmptree->i.ranges_len * sizeof(toku_range));
|
||||
if (!tmptree->i.ranges) { r = errno; goto died1; }
|
||||
user_malloc(tmptree->i.ranges_len * sizeof(toku_range));
|
||||
if (!tmptree->i.ranges) {
|
||||
r = errno; goto died1;
|
||||
}
|
||||
|
||||
*ptree = tmptree;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void toku_rt_clear(toku_range_tree* tree) {
|
||||
void
|
||||
toku_rt_clear(toku_range_tree* tree) {
|
||||
assert(tree);
|
||||
toku__rt_decrease_capacity(tree, 0);
|
||||
tree->numelements = 0;
|
||||
}
|
||||
|
||||
int toku_rt_close(toku_range_tree* tree) {
|
||||
if (!tree) return EINVAL;
|
||||
int
|
||||
toku_rt_close(toku_range_tree* tree) {
|
||||
if (!tree)
|
||||
return EINVAL;
|
||||
tree->free(tree->i.ranges);
|
||||
tree->free(tree);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
|
||||
toku_range** buf, u_int32_t* buflen, u_int32_t* numfound) {
|
||||
if (!tree || !query || !buf || !buflen || !numfound) return EINVAL;
|
||||
if (*buflen == 0) return EINVAL;
|
||||
int
|
||||
toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
|
||||
toku_range** buf, u_int32_t* buflen, u_int32_t* numfound) {
|
||||
int r;
|
||||
|
||||
if (!tree || !query || !buf || !buflen || !numfound)
|
||||
return EINVAL;
|
||||
if (*buflen == 0)
|
||||
return EINVAL;
|
||||
|
||||
u_int32_t temp_numfound = 0;
|
||||
int r;
|
||||
u_int32_t i;
|
||||
|
||||
for (i = 0; i < tree->numelements; i++) {
|
||||
for (u_int32_t i = 0; i < tree->numelements; i++) {
|
||||
if (toku__rt_overlap(tree, query, &tree->i.ranges[i].ends)) {
|
||||
r = toku__rt_increase_buffer(tree, buf, buflen, temp_numfound + 1);
|
||||
if (r != 0) return r;
|
||||
if (r != 0)
|
||||
return r;
|
||||
(*buf)[temp_numfound++] = tree->i.ranges[i];
|
||||
//k == 0 means limit of infinity, this is not a bug.
|
||||
if (temp_numfound == k) break;
|
||||
if (temp_numfound == k)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*numfound = temp_numfound;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_insert(toku_range_tree* tree, toku_range* range) {
|
||||
if (!tree || !range) return EINVAL;
|
||||
|
||||
u_int32_t i;
|
||||
u_int32_t move;
|
||||
int
|
||||
toku_rt_insert(toku_range_tree* tree, toku_range* range) {
|
||||
int r;
|
||||
|
||||
if (!tree || !range)
|
||||
return EINVAL;
|
||||
|
||||
//EDOM cases
|
||||
u_int32_t i;
|
||||
if (tree->allow_overlaps) {
|
||||
for (i = 0; i < tree->numelements; i++) {
|
||||
if (toku__rt_exact (tree, range, &tree->i.ranges[i])) return EDOM;
|
||||
if (toku__rt_exact (tree, range, &tree->i.ranges[i]))
|
||||
return EDOM;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (i = 0; i < tree->numelements; i++) {
|
||||
if (toku__rt_overlap(tree, &range->ends, &tree->i.ranges[i].ends)) return EDOM;
|
||||
if (toku__rt_overlap(tree, &range->ends, &tree->i.ranges[i].ends))
|
||||
return EDOM;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < tree->numelements; i++) {
|
||||
if (toku__rt_cmp(tree, range, &tree->i.ranges[i]) > 0) { break; }
|
||||
if (toku__rt_cmp(tree, range, &tree->i.ranges[i]) < 0)
|
||||
break;
|
||||
}
|
||||
/* Goes in slot 'i' */
|
||||
r = toku__rt_increase_capacity(tree, tree->numelements + 1);
|
||||
if (r != 0) return r;
|
||||
if (r != 0)
|
||||
return r;
|
||||
tree->numelements++;
|
||||
/* Shift to make room. */
|
||||
for (move = tree->numelements - 1; move > i; move--) {
|
||||
for (u_int32_t move = tree->numelements - 1; move > i; move--) {
|
||||
tree->i.ranges[move] = tree->i.ranges[move - 1];
|
||||
}
|
||||
tree->i.ranges[i] = *range;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_delete(toku_range_tree* tree, toku_range* range) {
|
||||
if (!tree || !range) return EINVAL;
|
||||
int
|
||||
toku_rt_delete(toku_range_tree* tree, toku_range* range) {
|
||||
if (!tree || !range)
|
||||
return EINVAL;
|
||||
u_int32_t i;
|
||||
u_int32_t move;
|
||||
|
||||
for (i = 0;
|
||||
i < tree->numelements &&
|
||||
!toku__rt_exact(tree, range, &(tree->i.ranges[i]));
|
||||
i++) {}
|
||||
for (i = 0; i < tree->numelements &&
|
||||
!toku__rt_exact(tree, range, &(tree->i.ranges[i])); i++) {
|
||||
}
|
||||
//EDOM case: Not Found
|
||||
if (i == tree->numelements) return EDOM;
|
||||
if (i == tree->numelements)
|
||||
return EDOM;
|
||||
/* Shift left. */
|
||||
for (move = i; move < tree->numelements - 1; move++) {
|
||||
for (u_int32_t move = i; move < tree->numelements - 1; move++) {
|
||||
tree->i.ranges[move] = tree->i.ranges[move + 1];
|
||||
}
|
||||
toku__rt_decrease_capacity(tree, --tree->numelements);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_predecessor (toku_range_tree* tree, toku_point* point,
|
||||
toku_range* pred, BOOL* wasfound) {
|
||||
if (!tree || !point || !pred || !wasfound) return EINVAL;
|
||||
if (tree->allow_overlaps) return EINVAL;
|
||||
int
|
||||
toku_rt_predecessor (toku_range_tree* tree, toku_point* point, toku_range* pred, BOOL* wasfound) {
|
||||
if (!tree || !point || !pred || !wasfound)
|
||||
return EINVAL;
|
||||
if (tree->allow_overlaps)
|
||||
return EINVAL;
|
||||
toku_range* best = NULL;
|
||||
u_int32_t i;
|
||||
|
||||
for (i = 0; i < tree->numelements; i++) {
|
||||
for (u_int32_t i = 0; i < tree->numelements; i++) {
|
||||
if (toku__rt_p_cmp(tree, point, &tree->i.ranges[i].ends) > 0 &&
|
||||
(!best || tree->end_cmp(best->ends.left, tree->i.ranges[i].ends.left) < 0)) {
|
||||
best = &tree->i.ranges[i];
|
||||
}
|
||||
}
|
||||
*wasfound = (BOOL)(best != NULL);
|
||||
if (best) *pred = *best;
|
||||
if (best)
|
||||
*pred = *best;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_successor (toku_range_tree* tree, toku_point* point,
|
||||
toku_range* succ, BOOL* wasfound) {
|
||||
if (!tree || !point || !succ || !wasfound) return EINVAL;
|
||||
if (tree->allow_overlaps) return EINVAL;
|
||||
int
|
||||
toku_rt_successor (toku_range_tree* tree, toku_point* point, toku_range* succ, BOOL* wasfound) {
|
||||
if (!tree || !point || !succ || !wasfound)
|
||||
return EINVAL;
|
||||
if (tree->allow_overlaps)
|
||||
return EINVAL;
|
||||
toku_range* best = NULL;
|
||||
u_int32_t i;
|
||||
|
||||
for (i = 0; i < tree->numelements; i++) {
|
||||
for (u_int32_t i = 0; i < tree->numelements; i++) {
|
||||
if (toku__rt_p_cmp(tree, point, &tree->i.ranges[i].ends) < 0 &&
|
||||
(!best || tree->end_cmp(best->ends.left, tree->i.ranges[i].ends.left) > 0)) {
|
||||
best = &tree->i.ranges[i];
|
||||
}
|
||||
}
|
||||
*wasfound = (BOOL)(best != NULL);
|
||||
if (best) *succ = *best;
|
||||
if (best)
|
||||
*succ = *best;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed) {
|
||||
if (!tree || !allowed) return EINVAL;
|
||||
int
|
||||
toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed) {
|
||||
if (!tree || !allowed)
|
||||
return EINVAL;
|
||||
*allowed = tree->allow_overlaps;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) {
|
||||
if (!tree || !size) return EINVAL;
|
||||
int
|
||||
toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) {
|
||||
if (!tree || !size)
|
||||
return EINVAL;
|
||||
*size = tree->numelements;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) {
|
||||
int
|
||||
toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) {
|
||||
u_int32_t index;
|
||||
|
||||
int r = ENOSYS;
|
||||
for (index = 0; index < tree->numelements; index++) {
|
||||
if ((r = f(&tree->i.ranges[index], extra))) goto cleanup;
|
||||
if ((r = f(&tree->i.ranges[index], extra)))
|
||||
goto cleanup;
|
||||
}
|
||||
r = 0;
|
||||
cleanup:
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
toku_rt_verify(toku_range_tree *tree) {
|
||||
if (!tree->allow_overlaps) {
|
||||
for (u_int32_t i = 0; i < tree->numelements; i++) {
|
||||
// assert left <= right
|
||||
assert(tree->end_cmp(tree->i.ranges[i].ends.left, tree->i.ranges[i].ends.right) <= 0);
|
||||
// assert ranges are sorted
|
||||
if (i < tree->numelements-1)
|
||||
assert(tree->end_cmp(tree->i.ranges[i].ends.right, tree->i.ranges[i+1].ends.left) < 0);
|
||||
}
|
||||
// verify no overlaps
|
||||
for (u_int32_t i = 1; i < tree->numelements; i++) {
|
||||
assert(!toku__rt_overlap(tree, &tree->i.ranges[i-1].ends, &tree->i.ranges[i].ends));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,53 +27,62 @@ struct __toku_range_tree_local {
|
|||
#include <rangetree-internal.h>
|
||||
|
||||
|
||||
int toku_rt_create(toku_range_tree** ptree,
|
||||
int (*end_cmp)(const toku_point*,const toku_point*),
|
||||
int (*data_cmp)(const TXNID,const TXNID),
|
||||
BOOL allow_overlaps,
|
||||
void* (*user_malloc) (size_t),
|
||||
void (*user_free) (void*),
|
||||
void* (*user_realloc)(void*, size_t)) {
|
||||
int
|
||||
toku_rt_create(toku_range_tree** ptree,
|
||||
int (*end_cmp)(const toku_point*,const toku_point*),
|
||||
int (*data_cmp)(const TXNID,const TXNID),
|
||||
BOOL allow_overlaps,
|
||||
void* (*user_malloc) (size_t),
|
||||
void (*user_free) (void*),
|
||||
void* (*user_realloc)(void*, size_t)) {
|
||||
int r = ENOSYS;
|
||||
toku_range_tree* temptree = NULL;
|
||||
|
||||
if (allow_overlaps) return EINVAL;
|
||||
if (allow_overlaps)
|
||||
return EINVAL;
|
||||
r = toku_rt_super_create(ptree, &temptree, end_cmp, data_cmp, allow_overlaps,
|
||||
user_malloc, user_free, user_realloc);
|
||||
if (r!=0) { goto cleanup; }
|
||||
if (r != 0)
|
||||
goto cleanup;
|
||||
|
||||
//Any local initializers go here.
|
||||
r = toku_omt_create(&temptree->i.omt);
|
||||
if (r!=0) { goto cleanup; }
|
||||
if (r != 0)
|
||||
goto cleanup;
|
||||
|
||||
*ptree = temptree;
|
||||
r = 0;
|
||||
cleanup:
|
||||
if (r!=0) {
|
||||
if (temptree) user_free(temptree);
|
||||
if (r != 0) {
|
||||
if (temptree)
|
||||
user_free(temptree);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int rt_clear_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
|
||||
static int
|
||||
rt_clear_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
|
||||
void (*user_free)(void*) = (void(*)(void*))extra;
|
||||
user_free(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_close(toku_range_tree* tree) {
|
||||
if (!tree) { return EINVAL; }
|
||||
int
|
||||
toku_rt_close(toku_range_tree* tree) {
|
||||
if (!tree)
|
||||
return EINVAL;
|
||||
int r = toku_omt_iterate(tree->i.omt, rt_clear_helper, tree->free);
|
||||
assert(r==0);
|
||||
assert_zero(r);
|
||||
toku_omt_destroy(&tree->i.omt);
|
||||
tree->free(tree);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void toku_rt_clear(toku_range_tree* tree) {
|
||||
void
|
||||
toku_rt_clear(toku_range_tree* tree) {
|
||||
assert(tree);
|
||||
int r = toku_omt_iterate(tree->i.omt, rt_clear_helper, tree->free);
|
||||
assert(r==0);
|
||||
assert_zero(r);
|
||||
toku_omt_clear(tree->i.omt);
|
||||
tree->numelements = 0;
|
||||
}
|
||||
|
@ -83,12 +92,15 @@ typedef struct {
|
|||
toku_interval query;
|
||||
} rt_heavi_extra;
|
||||
|
||||
static int rt_heaviside(OMTVALUE candidate, void* extra) {
|
||||
static int
|
||||
rt_heaviside(OMTVALUE candidate, void* extra) {
|
||||
toku_range* range_candidate = candidate;
|
||||
rt_heavi_extra* info = extra;
|
||||
|
||||
if (info->end_cmp(range_candidate->ends.right, info->query.left) < 0) return -1;
|
||||
if (info->end_cmp(range_candidate->ends.left, info->query.right) > 0) return 1;
|
||||
if (info->end_cmp(range_candidate->ends.right, info->query.left) < 0)
|
||||
return -1;
|
||||
if (info->end_cmp(range_candidate->ends.left, info->query.right) > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -102,7 +114,8 @@ typedef struct {
|
|||
u_int32_t* buflen;
|
||||
} rt_find_info;
|
||||
|
||||
static int rt_find_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
|
||||
static int
|
||||
rt_find_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
|
||||
rt_find_info* info = extra;
|
||||
toku_range* range = value;
|
||||
int r = ENOSYS;
|
||||
|
@ -113,7 +126,7 @@ static int rt_find_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
|
|||
}
|
||||
|
||||
r = toku__rt_increase_buffer(info->rt, info->buf, info->buflen, info->numfound + 1);
|
||||
if (r!=0) goto cleanup;
|
||||
if (r != 0) goto cleanup;
|
||||
(*info->buf)[info->numfound++] = *range;
|
||||
if (info->numfound>=info->k) {
|
||||
r = TOKUDB_SUCCEEDED_EARLY;
|
||||
|
@ -124,8 +137,9 @@ cleanup:
|
|||
return r;
|
||||
}
|
||||
|
||||
int toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
|
||||
toku_range** buf, u_int32_t* buflen, u_int32_t* numfound) {
|
||||
int
|
||||
toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
|
||||
toku_range** buf, u_int32_t* buflen, u_int32_t* numfound) {
|
||||
int r = ENOSYS;
|
||||
|
||||
if (!tree || !query || !buf || !buflen || !numfound || *buflen == 0) {
|
||||
|
@ -134,7 +148,8 @@ int toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
|
|||
assert(!tree->allow_overlaps);
|
||||
|
||||
/* k = 0 means return ALL. (infinity) */
|
||||
if (k == 0) { k = UINT32_MAX; }
|
||||
if (k == 0)
|
||||
k = UINT32_MAX;
|
||||
|
||||
u_int32_t leftmost;
|
||||
u_int32_t rightmost = toku_omt_size(tree->i.omt);
|
||||
|
@ -143,13 +158,13 @@ int toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
|
|||
extra.query = *query;
|
||||
|
||||
r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, NULL, &leftmost, NULL);
|
||||
if (r==DB_NOTFOUND) {
|
||||
if (r == DB_NOTFOUND) {
|
||||
/* Nothing overlaps. */
|
||||
*numfound = 0;
|
||||
r = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (r!=0) goto cleanup;
|
||||
assert_zero(r);
|
||||
rt_find_info info;
|
||||
info.end_cmp = tree->end_cmp;
|
||||
info.query = *query;
|
||||
|
@ -160,18 +175,23 @@ int toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k,
|
|||
info.buflen = buflen;
|
||||
|
||||
r = toku_omt_iterate_on_range(tree->i.omt, leftmost, rightmost, rt_find_helper, &info);
|
||||
if (r==TOKUDB_SUCCEEDED_EARLY) r=0;
|
||||
if (r!=0) goto cleanup;
|
||||
if (r == TOKUDB_SUCCEEDED_EARLY)
|
||||
r = 0;
|
||||
if (r != 0)
|
||||
goto cleanup;
|
||||
*numfound = info.numfound;
|
||||
r = 0;
|
||||
cleanup:
|
||||
return r;
|
||||
}
|
||||
|
||||
int toku_rt_insert(toku_range_tree* tree, toku_range* range) {
|
||||
int
|
||||
toku_rt_insert(toku_range_tree* tree, toku_range* range) {
|
||||
int r = ENOSYS;
|
||||
toku_range* insert_range = NULL;
|
||||
if (!tree || !range) { r = EINVAL; goto cleanup; }
|
||||
if (!tree || !range) {
|
||||
r = EINVAL; goto cleanup;
|
||||
}
|
||||
assert(!tree->allow_overlaps);
|
||||
|
||||
u_int32_t index;
|
||||
|
@ -180,24 +200,31 @@ int toku_rt_insert(toku_range_tree* tree, toku_range* range) {
|
|||
extra.query = range->ends;
|
||||
|
||||
r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, NULL, &index, NULL);
|
||||
if (r==0) { r = EDOM; goto cleanup; }
|
||||
if (r!=DB_NOTFOUND) goto cleanup;
|
||||
if (r == 0) {
|
||||
r = EDOM; goto cleanup;
|
||||
}
|
||||
assert(r == DB_NOTFOUND);
|
||||
insert_range = tree->malloc(sizeof(*insert_range));
|
||||
*insert_range = *range;
|
||||
if ((r = toku_omt_insert_at(tree->i.omt, insert_range, index))) goto cleanup;
|
||||
r = toku_omt_insert_at(tree->i.omt, insert_range, index);
|
||||
assert_zero(r);
|
||||
|
||||
tree->numelements++;
|
||||
r = 0;
|
||||
cleanup:
|
||||
if (r!=0) {
|
||||
if (insert_range) tree->free(insert_range);
|
||||
if (r != 0) {
|
||||
if (insert_range)
|
||||
tree->free(insert_range);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int toku_rt_delete(toku_range_tree* tree, toku_range* range) {
|
||||
int
|
||||
toku_rt_delete(toku_range_tree* tree, toku_range* range) {
|
||||
int r = ENOSYS;
|
||||
if (!tree || !range) { r = EINVAL; goto cleanup; }
|
||||
if (!tree || !range) {
|
||||
r = EINVAL; goto cleanup;
|
||||
}
|
||||
assert(!tree->allow_overlaps);
|
||||
|
||||
OMTVALUE value = NULL;
|
||||
|
@ -207,7 +234,9 @@ int toku_rt_delete(toku_range_tree* tree, toku_range* range) {
|
|||
extra.query = range->ends;
|
||||
|
||||
r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, &value, &index, NULL);
|
||||
if (r!=0) { r = EDOM; goto cleanup; }
|
||||
if (r != 0) {
|
||||
r = EDOM; goto cleanup;
|
||||
}
|
||||
assert(value);
|
||||
toku_range* data = value;
|
||||
if (tree->end_cmp(data->ends.left, range->ends.left) ||
|
||||
|
@ -216,17 +245,19 @@ int toku_rt_delete(toku_range_tree* tree, toku_range* range) {
|
|||
r = EDOM;
|
||||
goto cleanup;
|
||||
}
|
||||
if ((r = toku_omt_delete_at(tree->i.omt, index))) goto cleanup;
|
||||
tree->free(data);
|
||||
r = toku_omt_delete_at(tree->i.omt, index);
|
||||
assert_zero(r);
|
||||
|
||||
tree->free(data);
|
||||
tree->numelements--;
|
||||
r = 0;
|
||||
cleanup:
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline int rt_neightbor(toku_range_tree* tree, toku_point* point,
|
||||
toku_range* neighbor, BOOL* wasfound, int direction) {
|
||||
static inline int
|
||||
rt_neightbor(toku_range_tree* tree, toku_point* point,
|
||||
toku_range* neighbor, BOOL* wasfound, int direction) {
|
||||
int r = ENOSYS;
|
||||
if (!tree || !point || !neighbor || !wasfound || tree->allow_overlaps) {
|
||||
r = EINVAL; goto cleanup;
|
||||
|
@ -240,12 +271,12 @@ static inline int rt_neightbor(toku_range_tree* tree, toku_point* point,
|
|||
|
||||
assert(direction==1 || direction==-1);
|
||||
r = toku_omt_find(tree->i.omt, rt_heaviside, &extra, direction, &value, &index, NULL);
|
||||
if (r==DB_NOTFOUND) {
|
||||
if (r == DB_NOTFOUND) {
|
||||
*wasfound = FALSE;
|
||||
r = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
if (r!=0) goto cleanup;
|
||||
assert_zero(r);
|
||||
assert(value);
|
||||
toku_range* data = value;
|
||||
*wasfound = TRUE;
|
||||
|
@ -255,25 +286,29 @@ cleanup:
|
|||
return r;
|
||||
}
|
||||
|
||||
int toku_rt_predecessor (toku_range_tree* tree, toku_point* point,
|
||||
toku_range* pred, BOOL* wasfound) {
|
||||
int
|
||||
toku_rt_predecessor (toku_range_tree* tree, toku_point* point, toku_range* pred, BOOL* wasfound) {
|
||||
return rt_neightbor(tree, point, pred, wasfound, -1);
|
||||
}
|
||||
|
||||
int toku_rt_successor (toku_range_tree* tree, toku_point* point,
|
||||
toku_range* succ, BOOL* wasfound) {
|
||||
int
|
||||
toku_rt_successor (toku_range_tree* tree, toku_point* point, toku_range* succ, BOOL* wasfound) {
|
||||
return rt_neightbor(tree, point, succ, wasfound, 1);
|
||||
}
|
||||
|
||||
int toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed) {
|
||||
if (!tree || !allowed) return EINVAL;
|
||||
int
|
||||
toku_rt_get_allow_overlaps(toku_range_tree* tree, BOOL* allowed) {
|
||||
if (!tree || !allowed)
|
||||
return EINVAL;
|
||||
assert(!tree->allow_overlaps);
|
||||
*allowed = tree->allow_overlaps;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) {
|
||||
if (!tree || !size) return EINVAL;
|
||||
int
|
||||
toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) {
|
||||
if (!tree || !size)
|
||||
return EINVAL;
|
||||
*size = tree->numelements;
|
||||
return 0;
|
||||
}
|
||||
|
@ -283,15 +318,61 @@ typedef struct {
|
|||
void* extra;
|
||||
} rt_iter_info;
|
||||
|
||||
static int rt_iterate_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
|
||||
static int
|
||||
rt_iterate_helper(OMTVALUE value, u_int32_t UU(index), void* extra) {
|
||||
rt_iter_info* info = extra;
|
||||
return info->f(value, info->extra);
|
||||
}
|
||||
|
||||
int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) {
|
||||
int
|
||||
toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) {
|
||||
rt_iter_info info;
|
||||
info.f = f;
|
||||
info.extra = extra;
|
||||
return toku_omt_iterate(tree->i.omt, rt_iterate_helper, &info);
|
||||
}
|
||||
|
||||
static inline BOOL
|
||||
toku__rt_overlap(toku_range_tree* tree, toku_interval* a, toku_interval* b) {
|
||||
assert(tree);
|
||||
assert(a);
|
||||
assert(b);
|
||||
//a->left <= b->right && b->left <= a->right
|
||||
return (BOOL)((tree->end_cmp(a->left, b->right) <= 0) &&
|
||||
(tree->end_cmp(b->left, a->right) <= 0));
|
||||
}
|
||||
|
||||
void
|
||||
toku_rt_verify(toku_range_tree *tree) {
|
||||
int r;
|
||||
if (!tree->allow_overlaps) {
|
||||
for (u_int32_t i = 0; i < tree->numelements; i++) {
|
||||
// assert left <= right
|
||||
OMTVALUE omtv;
|
||||
r = toku_omt_fetch(tree->i.omt, i, &omtv, NULL);
|
||||
assert_zero(r);
|
||||
toku_range *v = (toku_range *) omtv;
|
||||
assert(tree->end_cmp(v->ends.left, v->ends.right) <= 0);
|
||||
// assert ranges are sorted
|
||||
if (i < tree->numelements-1) {
|
||||
OMTVALUE omtvnext;
|
||||
r = toku_omt_fetch(tree->i.omt, i+1, &omtvnext, NULL);
|
||||
assert_zero(r);
|
||||
toku_range *vnext = (toku_range *) omtvnext;
|
||||
assert(tree->end_cmp(v->ends.right, vnext->ends.left) < 0);
|
||||
}
|
||||
}
|
||||
// verify no overlaps
|
||||
for (u_int32_t i = 1; i < tree->numelements; i++) {
|
||||
OMTVALUE omtvprev;
|
||||
r = toku_omt_fetch(tree->i.omt, i-1, &omtvprev, NULL);
|
||||
assert_zero(r);
|
||||
toku_range *vprev = (toku_range *) omtvprev;
|
||||
OMTVALUE omtv;
|
||||
r = toku_omt_fetch(tree->i.omt, i, &omtv, NULL);
|
||||
assert_zero(r);
|
||||
toku_range *v = (toku_range *) omtv;
|
||||
assert(!toku__rt_overlap(tree, &vprev->ends, &v->ends));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
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[]) {
|
||||
|
|
51
src/range_tree/tests/test_rt_clear.c
Normal file
51
src/range_tree/tests/test_rt_clear.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
// 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;
|
||||
}
|
31
src/range_tree/tests/test_rt_delete_edom.c
Normal file
31
src/range_tree/tests/test_rt_delete_edom.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
// 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 \
|
||||
|
|
104
src/tests/cursor-set-del-rmw.c
Normal file
104
src/tests/cursor-set-del-rmw.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
#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;
|
||||
}
|
114
src/tests/cursor-set-range-rmw.c
Normal file
114
src/tests/cursor-set-range-rmw.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
#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;
|
||||
}
|
70
src/tests/prelock-read-read.c
Normal file
70
src/tests/prelock-read-read.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
#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;
|
||||
}
|
68
src/tests/prelock-read-write.c
Normal file
68
src/tests/prelock-read-write.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
#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;
|
||||
}
|
68
src/tests/prelock-write-read.c
Normal file
68
src/tests/prelock-write-read.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
#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;
|
||||
}
|
68
src/tests/prelock-write-write.c
Normal file
68
src/tests/prelock-write-write.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
#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;
|
||||
}
|
64
src/tests/replace-into-write-lock.c
Normal file
64
src/tests/replace-into-write-lock.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include "test.h"
|
||||
|
||||
// verify that a db->put with NOOVERWRITE grabs a write lock not a read lock.
|
||||
// we use two transactions. the first transaction tries to put with NOOVERWRITE
|
||||
// and finds that the key already exists. it now holds a write lock on the key.
|
||||
// the second transaction trys to put the same key with NOOVERWRITE and gets
|
||||
// LOCK_NOTGRANTED. the second transaction can not put the key until the first
|
||||
// transaction commits.
|
||||
|
||||
int test_main(int argc, char * const argv[]) {
|
||||
int r;
|
||||
|
||||
char *env_dir = ENVDIR;
|
||||
char *db_filename = "replacetest";
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
r = db->put(db, txn1, &key, &val, DB_NOOVERWRITE); assert(r == DB_KEYEXIST);
|
||||
r = db->put(db, txn2, &key, &val, DB_NOOVERWRITE); assert(r == DB_LOCK_NOTGRANTED);
|
||||
r = db->put(db, txn1, &key, &val, DB_YESOVERWRITE); assert_zero(r);
|
||||
r = db->put(db, txn2, &key, &val, DB_YESOVERWRITE); assert(r == DB_LOCK_NOTGRANTED);
|
||||
r = txn1->commit(txn1, 0); assert_zero(r);
|
||||
r = db->put(db, txn2, &key, &val, DB_YESOVERWRITE); assert_zero(r);
|
||||
r = txn2->commit(txn2, 0); assert_zero(r);
|
||||
|
||||
r = db->close(db, 0); assert_zero(r);
|
||||
|
||||
r = env->close(env, 0); assert_zero(r);
|
||||
return 0;
|
||||
}
|
|
@ -12,7 +12,7 @@ static int update_fun(DB *UU(db),
|
|||
void UU((*set_val)(const DBT *new_val,
|
||||
void *set_extra)),
|
||||
void *UU(set_extra)) {
|
||||
assert(0);
|
||||
assert(0); return 0;
|
||||
}
|
||||
|
||||
static void setup (void) {
|
||||
|
|
|
@ -30,7 +30,7 @@ static int increment_update (DB *db __attribute__((__unused__)),
|
|||
set_val(NULL, set_extra);
|
||||
return 0;
|
||||
}
|
||||
assert(0); // enumeration failed.
|
||||
assert(0); return 0; // enumeration failed.
|
||||
}
|
||||
|
||||
static void setup (void) {
|
||||
|
|
|
@ -218,13 +218,17 @@ struct __toku_dbc_internal {
|
|||
TOKU_ISOLATION iso;
|
||||
struct simple_dbt skey_s,sval_s;
|
||||
struct simple_dbt *skey,*sval;
|
||||
|
||||
// if the rmw flag is asserted, cursor operations (like set) grab write locks instead of read locks
|
||||
// the rmw flag is set when the cursor is created with the DB_RMW flag set
|
||||
BOOL rmw;
|
||||
};
|
||||
|
||||
int toku_db_pre_acquire_table_lock(DB *db, DB_TXN *txn, BOOL just_lock);
|
||||
|
||||
int toku_grab_write_lock (DB* db, DBT* key, TOKUTXN tokutxn);
|
||||
int toku_grab_write_lock(DB *db, DBT *key, TOKUTXN tokutxn);
|
||||
|
||||
int toku_grab_read_lock_on_directory (DB* db, DB_TXN * txn);
|
||||
int toku_grab_read_lock_on_directory(DB *db, DB_TXN *txn);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
266
src/ydb.c
266
src/ydb.c
|
@ -3067,8 +3067,7 @@ get_cursor_prelocked_flags(u_int32_t flags, DBC* dbc) {
|
|||
u_int32_t lock_flags = flags & (DB_PRELOCKED | DB_PRELOCKED_WRITE | DB_PRELOCKED_FILE_READ);
|
||||
|
||||
//DB_READ_UNCOMMITTED and DB_READ_COMMITTED transactions 'own' all read locks for user-data dictionaries.
|
||||
if (dbc_struct_i(dbc)->iso != TOKU_ISO_SERIALIZABLE)
|
||||
{
|
||||
if (dbc_struct_i(dbc)->iso != TOKU_ISO_SERIALIZABLE) {
|
||||
lock_flags |= DB_PRELOCKED;
|
||||
}
|
||||
return lock_flags;
|
||||
|
@ -3190,7 +3189,7 @@ locked_c_getf_set_range_reverse(DBC *c, u_int32_t flag, DBT * key, YDB_CALLBACK_
|
|||
}
|
||||
|
||||
typedef struct {
|
||||
BOOL is_read_lock;
|
||||
BOOL is_write_lock;
|
||||
DB_TXN *txn;
|
||||
DB *db;
|
||||
toku_lock_tree *lt;
|
||||
|
@ -3200,12 +3199,12 @@ typedef struct {
|
|||
|
||||
static void
|
||||
range_lock_request_init(RANGE_LOCK_REQUEST request,
|
||||
BOOL is_read_lock,
|
||||
BOOL is_write_lock,
|
||||
DB_TXN *txn,
|
||||
DB *db,
|
||||
DBT const *left_key,
|
||||
DBT const *right_key) {
|
||||
request->is_read_lock = is_read_lock;
|
||||
request->is_write_lock = is_write_lock;
|
||||
request->txn = txn;
|
||||
request->db = db;
|
||||
request->lt = db->i->lt;
|
||||
|
@ -3219,8 +3218,7 @@ read_lock_request_init(RANGE_LOCK_REQUEST request,
|
|||
DB *db,
|
||||
DBT const *left_key,
|
||||
DBT const *right_key) {
|
||||
range_lock_request_init(request, TRUE, txn, db,
|
||||
left_key, right_key);
|
||||
range_lock_request_init(request, FALSE, txn, db, left_key, right_key);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3229,8 +3227,7 @@ write_lock_request_init(RANGE_LOCK_REQUEST request,
|
|||
DB *db,
|
||||
DBT const *left_key,
|
||||
DBT const *right_key) {
|
||||
range_lock_request_init(request, FALSE, txn, db,
|
||||
left_key, right_key);
|
||||
range_lock_request_init(request, TRUE, txn, db, left_key, right_key);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -3241,12 +3238,12 @@ grab_range_lock(RANGE_LOCK_REQUEST request) {
|
|||
r = toku_txn_add_lt(txn_anc, request->lt);
|
||||
if (r==0) {
|
||||
TXNID txn_anc_id = toku_txn_get_txnid(db_txn_struct_i(txn_anc)->tokutxn);
|
||||
if (request->is_read_lock)
|
||||
r = toku_lt_acquire_range_read_lock(request->lt, request->db, txn_anc_id,
|
||||
request->left_key, request->right_key);
|
||||
else
|
||||
if (request->is_write_lock)
|
||||
r = toku_lt_acquire_range_write_lock(request->lt, request->db, txn_anc_id,
|
||||
request->left_key, request->right_key);
|
||||
else
|
||||
r = toku_lt_acquire_range_read_lock(request->lt, request->db, txn_anc_id,
|
||||
request->left_key, request->right_key);
|
||||
}
|
||||
//TODO: (Multithreading) Release lock protecting lock tree
|
||||
return r;
|
||||
|
@ -3254,7 +3251,6 @@ grab_range_lock(RANGE_LOCK_REQUEST request) {
|
|||
|
||||
int
|
||||
toku_grab_read_lock_on_directory (DB* db, DB_TXN * txn) {
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
char * dname = db->i->dname;
|
||||
DBT key_in_directory;
|
||||
|
||||
|
@ -3264,13 +3260,9 @@ toku_grab_read_lock_on_directory (DB* db, DB_TXN * txn) {
|
|||
|
||||
toku_fill_dbt(&key_in_directory, dname, strlen(dname)+1);
|
||||
//Left end of range == right end of range (point lock)
|
||||
read_lock_request_init(
|
||||
&request,
|
||||
txn,
|
||||
db->dbenv->i->directory,
|
||||
&key_in_directory,
|
||||
&key_in_directory
|
||||
);
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
read_lock_request_init(&request, txn, db->dbenv->i->directory,
|
||||
&key_in_directory, &key_in_directory);
|
||||
int r = grab_range_lock(&request);
|
||||
if (r == 0)
|
||||
directory_read_locks++;
|
||||
|
@ -3282,10 +3274,6 @@ toku_grab_read_lock_on_directory (DB* db, DB_TXN * txn) {
|
|||
//This is the user level callback function given to ydb layer functions like
|
||||
//toku_c_getf_first
|
||||
|
||||
typedef struct __toku_is_write_op {
|
||||
BOOL is_write_op;
|
||||
} WRITE_OP;
|
||||
|
||||
typedef struct query_context_base_t {
|
||||
BRT_CURSOR c;
|
||||
DB_TXN *txn;
|
||||
|
@ -3308,39 +3296,38 @@ typedef struct query_context_with_input_t {
|
|||
DBT *input_val;
|
||||
} *QUERY_CONTEXT_WITH_INPUT, QUERY_CONTEXT_WITH_INPUT_S;
|
||||
|
||||
|
||||
static void
|
||||
query_context_base_init(QUERY_CONTEXT_BASE context, DBC *c, u_int32_t flag, WRITE_OP is_write_op, void *extra) {
|
||||
query_context_base_init(QUERY_CONTEXT_BASE context, DBC *c, u_int32_t flag, BOOL is_write_op, void *extra) {
|
||||
context->c = dbc_struct_i(c)->c;
|
||||
context->txn = dbc_struct_i(c)->txn;
|
||||
context->db = c->dbp;
|
||||
context->f_extra = extra;
|
||||
context->is_write_op = is_write_op.is_write_op;
|
||||
context->is_write_op = is_write_op;
|
||||
u_int32_t lock_flags = get_cursor_prelocked_flags(flag, c);
|
||||
flag &= ~lock_flags;
|
||||
if (context->is_write_op) lock_flags &= DB_PRELOCKED_WRITE; // Only care about whether already locked for write
|
||||
assert(flag==0);
|
||||
if (context->is_write_op)
|
||||
lock_flags &= DB_PRELOCKED_WRITE; // Only care about whether already locked for write
|
||||
context->do_locking = (BOOL)(context->db->i->lt!=NULL && !(lock_flags & (DB_PRELOCKED|DB_PRELOCKED_WRITE)));
|
||||
context->r_user_callback = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
query_context_init(QUERY_CONTEXT context, DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
||||
WRITE_OP is_write = {FALSE};
|
||||
query_context_init_read(QUERY_CONTEXT context, DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
||||
BOOL is_write = FALSE;
|
||||
query_context_base_init(&context->base, c, flag, is_write, extra);
|
||||
context->f = f;
|
||||
}
|
||||
|
||||
static void
|
||||
query_context_init_write_op(QUERY_CONTEXT context, DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
||||
WRITE_OP is_write = {TRUE};
|
||||
query_context_init_write(QUERY_CONTEXT context, DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
||||
BOOL is_write = TRUE;
|
||||
query_context_base_init(&context->base, c, flag, is_write, extra);
|
||||
context->f = f;
|
||||
}
|
||||
|
||||
static void
|
||||
query_context_with_input_init(QUERY_CONTEXT_WITH_INPUT context, DBC *c, u_int32_t flag, DBT *key, DBT *val, YDB_CALLBACK_FUNCTION f, void *extra) {
|
||||
WRITE_OP is_write = {FALSE};
|
||||
// grab write locks if the DB_RMW flag is set or the cursor was created with the DB_RMW flag
|
||||
BOOL is_write = ((flag & DB_RMW) != 0) || dbc_struct_i(c)->rmw;
|
||||
query_context_base_init(&context->base, c, flag, is_write, extra);
|
||||
context->f = f;
|
||||
context->input_key = key;
|
||||
|
@ -3368,7 +3355,7 @@ toku_c_del(DBC * c, u_int32_t flags) {
|
|||
else {
|
||||
if (do_locking) {
|
||||
QUERY_CONTEXT_S context;
|
||||
query_context_init_write_op(&context, c, lock_flags, NULL, NULL);
|
||||
query_context_init_write(&context, c, lock_flags, NULL, NULL);
|
||||
//We do not need a read lock, we must already have it.
|
||||
r = toku_c_getf_current_binding(c, DB_PRELOCKED, c_del_callback, &context);
|
||||
}
|
||||
|
@ -3396,8 +3383,7 @@ c_del_callback(DBT const *key, DBT const *val, void *extra) {
|
|||
//Lock:
|
||||
// left(key,val)==right(key,val) == (key, val);
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
write_lock_request_init(&request, context->txn, context->db,
|
||||
key, key);
|
||||
write_lock_request_init(&request, context->txn, context->db, key, key);
|
||||
r = grab_range_lock(&request);
|
||||
|
||||
//Give brt-layer an error (if any) to return from toku_c_getf_current_binding
|
||||
|
@ -3406,13 +3392,24 @@ c_del_callback(DBT const *key, DBT const *val, void *extra) {
|
|||
|
||||
static int c_getf_first_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec val, void *extra);
|
||||
|
||||
static void c_query_context_init(QUERY_CONTEXT context, DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
||||
BOOL is_write_op = FALSE;
|
||||
// grab write locks if the DB_RMW flag is set or the cursor was created with the DB_RMW flag
|
||||
if ((flag & DB_RMW) || dbc_struct_i(c)->rmw)
|
||||
is_write_op = TRUE;
|
||||
if (is_write_op)
|
||||
query_context_init_write(context, c, flag, f, extra);
|
||||
else
|
||||
query_context_init_read(context, c, flag, f, extra);
|
||||
}
|
||||
|
||||
static int
|
||||
toku_c_getf_first(DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
||||
HANDLE_PANICKED_DB(c->dbp);
|
||||
HANDLE_CURSOR_ILLEGAL_WORKING_PARENT_TXN(c);
|
||||
num_point_queries++; // accountability
|
||||
QUERY_CONTEXT_S context; //Describes the context of this query.
|
||||
query_context_init(&context, c, flag, f, extra);
|
||||
c_query_context_init(&context, c, flag, f, extra);
|
||||
//toku_brt_cursor_first will call c_getf_first_callback(..., context) (if query is successful)
|
||||
int r = toku_brt_cursor_first(dbc_struct_i(c)->c, c_getf_first_callback, &context);
|
||||
if (r == TOKUDB_USER_CALLBACK_ERROR) r = context.base.r_user_callback;
|
||||
|
@ -3435,12 +3432,11 @@ c_getf_first_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec val,
|
|||
if (context->do_locking) {
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
if (key!=NULL) {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
toku_lt_neg_infinity, &found_key);
|
||||
}
|
||||
else {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
toku_lt_neg_infinity, toku_lt_infinity);
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
toku_lt_neg_infinity, &found_key);
|
||||
} else {
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
toku_lt_neg_infinity, toku_lt_infinity);
|
||||
}
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
|
@ -3464,7 +3460,7 @@ toku_c_getf_last(DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
|||
HANDLE_CURSOR_ILLEGAL_WORKING_PARENT_TXN(c);
|
||||
num_point_queries++; // accountability
|
||||
QUERY_CONTEXT_S context; //Describes the context of this query.
|
||||
query_context_init(&context, c, flag, f, extra);
|
||||
c_query_context_init(&context, c, flag, f, extra);
|
||||
//toku_brt_cursor_last will call c_getf_last_callback(..., context) (if query is successful)
|
||||
int r = toku_brt_cursor_last(dbc_struct_i(c)->c, c_getf_last_callback, &context);
|
||||
if (r == TOKUDB_USER_CALLBACK_ERROR) r = context.base.r_user_callback;
|
||||
|
@ -3487,12 +3483,11 @@ c_getf_last_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec val, v
|
|||
if (context->do_locking) {
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
if (key!=NULL) {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
&found_key, toku_lt_infinity);
|
||||
}
|
||||
else {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
toku_lt_neg_infinity, toku_lt_infinity);
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
&found_key, toku_lt_infinity);
|
||||
} else {
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
toku_lt_neg_infinity, toku_lt_infinity);
|
||||
}
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
|
@ -3519,7 +3514,7 @@ toku_c_getf_next(DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
|||
else {
|
||||
QUERY_CONTEXT_S context; //Describes the context of this query.
|
||||
num_sequential_queries++; // accountability
|
||||
query_context_init(&context, c, flag, f, extra);
|
||||
c_query_context_init(&context, c, flag, f, extra);
|
||||
//toku_brt_cursor_next will call c_getf_next_callback(..., context) (if query is successful)
|
||||
r = toku_brt_cursor_next(dbc_struct_i(c)->c, c_getf_next_callback, &context);
|
||||
if (r == TOKUDB_USER_CALLBACK_ERROR) r = context.base.r_user_callback;
|
||||
|
@ -3547,9 +3542,8 @@ c_getf_next_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec val, v
|
|||
const DBT *right_key = key==NULL ? toku_lt_infinity : &found_key;
|
||||
|
||||
toku_brt_cursor_peek(context->c, &prevkey, &prevval);
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
prevkey,
|
||||
right_key);
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
prevkey, right_key);
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
else r = 0;
|
||||
|
@ -3575,7 +3569,7 @@ toku_c_getf_prev(DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra) {
|
|||
else {
|
||||
QUERY_CONTEXT_S context; //Describes the context of this query.
|
||||
num_sequential_queries++; // accountability
|
||||
query_context_init(&context, c, flag, f, extra);
|
||||
c_query_context_init(&context, c, flag, f, extra);
|
||||
//toku_brt_cursor_prev will call c_getf_prev_callback(..., context) (if query is successful)
|
||||
r = toku_brt_cursor_prev(dbc_struct_i(c)->c, c_getf_prev_callback, &context);
|
||||
if (r == TOKUDB_USER_CALLBACK_ERROR) r = context.base.r_user_callback;
|
||||
|
@ -3603,9 +3597,8 @@ c_getf_prev_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec val, v
|
|||
const DBT *left_key = key==NULL ? toku_lt_neg_infinity : &found_key;
|
||||
|
||||
toku_brt_cursor_peek(context->c, &prevkey, &prevval);
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
left_key,
|
||||
prevkey);
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
left_key, prevkey);
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
else r = 0;
|
||||
|
@ -3629,7 +3622,7 @@ toku_c_getf_current(DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, void *extra
|
|||
|
||||
QUERY_CONTEXT_S context; //Describes the context of this query.
|
||||
num_sequential_queries++; // accountability
|
||||
query_context_init(&context, c, flag, f, extra);
|
||||
c_query_context_init(&context, c, flag, f, extra);
|
||||
//toku_brt_cursor_current will call c_getf_current_callback(..., context) (if query is successful)
|
||||
int r = toku_brt_cursor_current(dbc_struct_i(c)->c, DB_CURRENT, c_getf_current_callback, &context);
|
||||
if (r == TOKUDB_USER_CALLBACK_ERROR) r = context.base.r_user_callback;
|
||||
|
@ -3665,7 +3658,7 @@ toku_c_getf_current_binding(DBC *c, u_int32_t flag, YDB_CALLBACK_FUNCTION f, voi
|
|||
|
||||
QUERY_CONTEXT_S context; //Describes the context of this query.
|
||||
num_sequential_queries++; // accountability
|
||||
query_context_init(&context, c, flag, f, extra);
|
||||
c_query_context_init(&context, c, flag, f, extra);
|
||||
//toku_brt_cursor_current will call c_getf_current_callback(..., context) (if query is successful)
|
||||
int r = toku_brt_cursor_current(dbc_struct_i(c)->c, DB_CURRENT_BINDING, c_getf_current_callback, &context);
|
||||
if (r == TOKUDB_USER_CALLBACK_ERROR) r = context.base.r_user_callback;
|
||||
|
@ -3706,19 +3699,11 @@ c_getf_set_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec val, vo
|
|||
// right(key,val) = (input_key, found ? found_val : infinity)
|
||||
if (context->do_locking) {
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
if (key!=NULL) {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
super_context->input_key,
|
||||
super_context->input_key);
|
||||
}
|
||||
else {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
super_context->input_key,
|
||||
super_context->input_key);
|
||||
}
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
super_context->input_key, super_context->input_key);
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
else r = 0;
|
||||
} else
|
||||
r = 0;
|
||||
|
||||
//Call application-layer callback if found and locks were successfully obtained.
|
||||
if (r==0 && key!=NULL) {
|
||||
|
@ -3765,16 +3750,12 @@ c_getf_set_range_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, bytevec v
|
|||
// right(val) = found ? found_val : infinity
|
||||
if (context->do_locking) {
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
if (key!=NULL) {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
super_context->input_key,
|
||||
&found_key);
|
||||
}
|
||||
else {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
super_context->input_key,
|
||||
toku_lt_infinity);
|
||||
}
|
||||
if (key!=NULL)
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
super_context->input_key, &found_key);
|
||||
else
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
super_context->input_key, toku_lt_infinity);
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
else r = 0;
|
||||
|
@ -3825,14 +3806,11 @@ c_getf_set_range_reverse_callback(ITEMLEN keylen, bytevec key, ITEMLEN vallen, b
|
|||
if (context->do_locking) {
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
if (key!=NULL) {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
&found_key,
|
||||
super_context->input_key);
|
||||
}
|
||||
else {
|
||||
read_lock_request_init(&request, context->txn, context->db,
|
||||
toku_lt_neg_infinity,
|
||||
super_context->input_key);
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
&found_key, super_context->input_key);
|
||||
} else {
|
||||
range_lock_request_init(&request, context->is_write_op, context->txn, context->db,
|
||||
toku_lt_neg_infinity, super_context->input_key);
|
||||
}
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
|
@ -3920,9 +3898,9 @@ db_getf_set(DB *db, DB_TXN *txn, u_int32_t flags, DBT *key, YDB_CALLBACK_FUNCTIO
|
|||
HANDLE_PANICKED_DB(db);
|
||||
HANDLE_DB_ILLEGAL_WORKING_PARENT_TXN(db, txn);
|
||||
DBC *c;
|
||||
uint32_t iso_flags = flags & DB_ISOLATION_FLAGS;
|
||||
uint32_t create_flags = flags & (DB_ISOLATION_FLAGS | DB_RMW);
|
||||
flags &= ~DB_ISOLATION_FLAGS;
|
||||
int r = toku_db_cursor(db, txn, &c, iso_flags, 1);
|
||||
int r = toku_db_cursor(db, txn, &c, create_flags, 1);
|
||||
if (r==0) {
|
||||
r = toku_c_getf_set(c, flags, key, f, extra);
|
||||
int r2 = toku_c_close(c);
|
||||
|
@ -3965,7 +3943,7 @@ toku_db_del(DB *db, DB_TXN *txn, DBT *key, u_int32_t flags) {
|
|||
}
|
||||
if (r == 0 && error_if_missing) {
|
||||
//Check if the key exists in the db.
|
||||
r = db_getf_set(db, txn, lock_flags|DB_SERIALIZABLE, key, ydb_getf_do_nothing, NULL);
|
||||
r = db_getf_set(db, txn, lock_flags|DB_SERIALIZABLE|DB_RMW, key, ydb_getf_do_nothing, NULL);
|
||||
}
|
||||
if (r == 0 && do_locking) {
|
||||
//Do locking if necessary.
|
||||
|
@ -4118,7 +4096,7 @@ env_del_multiple(
|
|||
BOOL error_if_missing = (BOOL)(!(remaining_flags[which_db]&DB_DELETE_ANY));
|
||||
if (error_if_missing) {
|
||||
//Check if the key exists in the db.
|
||||
r = db_getf_set(db, txn, lock_flags[which_db]|DB_SERIALIZABLE, &del_keys[which_db], ydb_getf_do_nothing, NULL);
|
||||
r = db_getf_set(db, txn, lock_flags[which_db]|DB_SERIALIZABLE|DB_RMW, &del_keys[which_db], ydb_getf_do_nothing, NULL);
|
||||
if (r != 0) goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -4151,9 +4129,7 @@ cleanup:
|
|||
|
||||
static int
|
||||
locked_c_get(DBC * c, DBT * key, DBT * data, u_int32_t flag) {
|
||||
//{ unsigned int i; printf("cget flags=%d keylen=%d key={", flag, key->size); for(i=0; i<key->size; i++) printf("%d,", ((char*)key->data)[i]); printf("} datalen=%d data={", data->size); for(i=0; i<data->size; i++) printf("%d,", ((char*)data->data)[i]); printf("}\n"); }
|
||||
toku_ydb_lock(); int r = toku_c_get(c, key, data, flag); toku_ydb_unlock();
|
||||
//{ unsigned int i; printf("cgot r=%d keylen=%d key={", r, key->size); for(i=0; i<key->size; i++) printf("%d,", ((char*)key->data)[i]); printf("} datalen=%d data={", data->size); for(i=0; i<data->size; i++) printf("%d,", ((char*)data->data)[i]); printf("}\n"); }
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -4172,7 +4148,7 @@ locked_c_del(DBC * c, u_int32_t flags) {
|
|||
toku_ydb_lock(); int r = toku_c_del(c, flags); toku_ydb_unlock(); return r;
|
||||
}
|
||||
|
||||
static int locked_c_pre_acquire_read_lock(DBC *dbc, const DBT *key_left, const DBT *key_right);
|
||||
static int locked_c_pre_acquire_range_lock(DBC *dbc, const DBT *key_left, const DBT *key_right);
|
||||
|
||||
static int
|
||||
toku_db_cursor(DB * db, DB_TXN * txn, DBC ** c, u_int32_t flags, int is_temporary_cursor) {
|
||||
|
@ -4181,21 +4157,16 @@ toku_db_cursor(DB * db, DB_TXN * txn, DBC ** c, u_int32_t flags, int is_temporar
|
|||
DB_ENV* env = db->dbenv;
|
||||
int r;
|
||||
size_t result_size = sizeof(DBC)+sizeof(struct __toku_dbc_internal); // internal stuff stuck on the end
|
||||
if (!(flags == 0 ||
|
||||
flags == DB_SERIALIZABLE ||
|
||||
flags == DB_INHERIT_ISOLATION)
|
||||
)
|
||||
{
|
||||
if (flags & ~(DB_SERIALIZABLE | DB_INHERIT_ISOLATION | DB_RMW)) {
|
||||
return toku_ydb_do_error(
|
||||
env,
|
||||
EINVAL,
|
||||
"Invalid isolation flags set for toku_db_cursor\n"
|
||||
"Invalid flags set for toku_db_cursor\n"
|
||||
);
|
||||
}
|
||||
r = toku_grab_read_lock_on_directory(db, txn);
|
||||
if (r != 0) {
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
DBC *result = toku_malloc(result_size);
|
||||
if (result == 0)
|
||||
|
@ -4215,7 +4186,7 @@ toku_db_cursor(DB * db, DB_TXN * txn, DBC ** c, u_int32_t flags, int is_temporar
|
|||
SCRS(c_getf_set);
|
||||
SCRS(c_getf_set_range);
|
||||
SCRS(c_getf_set_range_reverse);
|
||||
SCRS(c_pre_acquire_read_lock);
|
||||
SCRS(c_pre_acquire_range_lock);
|
||||
#undef SCRS
|
||||
|
||||
#if !TOKUDB_NATIVE_H
|
||||
|
@ -4223,6 +4194,7 @@ toku_db_cursor(DB * db, DB_TXN * txn, DBC ** c, u_int32_t flags, int is_temporar
|
|||
assert(result->i);
|
||||
#endif
|
||||
result->dbp = db;
|
||||
|
||||
dbc_struct_i(result)->txn = txn;
|
||||
dbc_struct_i(result)->skey_s = (struct simple_dbt){0,0};
|
||||
dbc_struct_i(result)->sval_s = (struct simple_dbt){0,0};
|
||||
|
@ -4233,14 +4205,12 @@ toku_db_cursor(DB * db, DB_TXN * txn, DBC ** c, u_int32_t flags, int is_temporar
|
|||
dbc_struct_i(result)->skey = &dbc_struct_i(result)->skey_s;
|
||||
dbc_struct_i(result)->sval = &dbc_struct_i(result)->sval_s;
|
||||
}
|
||||
switch(flags) {
|
||||
case (DB_SERIALIZABLE):
|
||||
dbc_struct_i(result)->iso = TOKU_ISO_SERIALIZABLE;
|
||||
break;
|
||||
default:
|
||||
dbc_struct_i(result)->iso = txn ? db_txn_struct_i(txn)->iso : TOKU_ISO_SERIALIZABLE;
|
||||
break;
|
||||
if (flags & DB_SERIALIZABLE) {
|
||||
dbc_struct_i(result)->iso = TOKU_ISO_SERIALIZABLE;
|
||||
} else {
|
||||
dbc_struct_i(result)->iso = txn ? db_txn_struct_i(txn)->iso : TOKU_ISO_SERIALIZABLE;
|
||||
}
|
||||
dbc_struct_i(result)->rmw = (flags & DB_RMW) != 0;
|
||||
BOOL is_snapshot_read = FALSE;
|
||||
if (txn) {
|
||||
is_snapshot_read = (dbc_struct_i(result)->iso == TOKU_ISO_READ_COMMITTED ||
|
||||
|
@ -4659,12 +4629,13 @@ db_put_check_overwrite_constraint(DB *db, DB_TXN *txn, DBT *key,
|
|||
u_int32_t lock_flags, u_int32_t overwrite_flag) {
|
||||
int r;
|
||||
|
||||
if (overwrite_flag == 0) { // 0 does not impose constraints.
|
||||
if (overwrite_flag == 0) { // 0 (yesoverwrite) does not impose constraints.
|
||||
r = 0;
|
||||
} else if (overwrite_flag == DB_NOOVERWRITE) {
|
||||
//Check if (key,anything) exists in dictionary.
|
||||
//If exists, fail. Otherwise, do insert.
|
||||
r = db_getf_set(db, txn, lock_flags|DB_SERIALIZABLE, key, ydb_getf_do_nothing, NULL);
|
||||
// Check if (key,anything) exists in dictionary.
|
||||
// If exists, fail. Otherwise, do insert.
|
||||
// The DB_RMW flag causes the cursor to grab a write lock instead of a read lock on the key if it exists.
|
||||
r = db_getf_set(db, txn, lock_flags|DB_SERIALIZABLE|DB_RMW, key, ydb_getf_do_nothing, NULL);
|
||||
if (r == DB_NOTFOUND)
|
||||
r = 0;
|
||||
else if (r == 0)
|
||||
|
@ -4721,7 +4692,6 @@ toku_db_put(DB *db, DB_TXN *txn, DBT *key, DBT *val, u_int32_t flags) {
|
|||
}
|
||||
|
||||
static int toku_db_pre_acquire_fileops_lock(DB *db, DB_TXN *txn) {
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
char * dname = db->i->dname;
|
||||
DBT key_in_directory;
|
||||
//
|
||||
|
@ -4732,13 +4702,9 @@ static int toku_db_pre_acquire_fileops_lock(DB *db, DB_TXN *txn) {
|
|||
}
|
||||
toku_fill_dbt(&key_in_directory, dname, strlen(dname)+1);
|
||||
//Left end of range == right end of range (point lock)
|
||||
write_lock_request_init(
|
||||
&request,
|
||||
txn,
|
||||
db->dbenv->i->directory,
|
||||
&key_in_directory,
|
||||
&key_in_directory
|
||||
);
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
write_lock_request_init(&request, txn, db->dbenv->i->directory,
|
||||
&key_in_directory, &key_in_directory);
|
||||
int r = grab_range_lock(&request);
|
||||
if (r == 0)
|
||||
directory_write_locks++;
|
||||
|
@ -5504,24 +5470,19 @@ cleanup:
|
|||
}
|
||||
|
||||
static int
|
||||
toku_c_pre_acquire_read_lock(DBC *dbc, const DBT *key_left, const DBT *key_right) {
|
||||
DB* db = dbc->dbp;
|
||||
DB_TXN* txn = dbc_struct_i(dbc)->txn;
|
||||
toku_c_pre_acquire_range_lock(DBC *dbc, const DBT *key_left, const DBT *key_right) {
|
||||
DB *db = dbc->dbp;
|
||||
DB_TXN *txn = dbc_struct_i(dbc)->txn;
|
||||
HANDLE_PANICKED_DB(db);
|
||||
if (!db->i->lt || !txn) return EINVAL;
|
||||
if (!db->i->lt || !txn)
|
||||
return EINVAL;
|
||||
//READ_UNCOMMITTED and READ_COMMITTED transactions do not need read locks.
|
||||
if (dbc_struct_i(dbc)->iso != TOKU_ISO_SERIALIZABLE) {
|
||||
return 0;
|
||||
}
|
||||
if (!dbc_struct_i(dbc)->rmw && dbc_struct_i(dbc)->iso != TOKU_ISO_SERIALIZABLE)
|
||||
return 0;
|
||||
|
||||
int r;
|
||||
{
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
read_lock_request_init(&request, txn, db,
|
||||
key_left,
|
||||
key_right);
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
range_lock_request_init(&request, dbc_struct_i(dbc)->rmw, txn, db, key_left, key_right);
|
||||
int r = grab_range_lock(&request);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -5536,13 +5497,8 @@ toku_db_pre_acquire_table_lock(DB *db, DB_TXN *txn, BOOL just_lock) {
|
|||
|
||||
{
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
write_lock_request_init(
|
||||
&request,
|
||||
txn,
|
||||
db,
|
||||
toku_lt_neg_infinity,
|
||||
toku_lt_infinity
|
||||
);
|
||||
write_lock_request_init(&request, txn, db,
|
||||
toku_lt_neg_infinity, toku_lt_infinity);
|
||||
r = grab_range_lock(&request);
|
||||
}
|
||||
|
||||
|
@ -5693,9 +5649,9 @@ locked_db_getf_set (DB *db, DB_TXN *txn, u_int32_t flags, DBT *key, YDB_CALLBACK
|
|||
}
|
||||
|
||||
static int
|
||||
locked_c_pre_acquire_read_lock(DBC *dbc, const DBT *key_left, const DBT *key_right) {
|
||||
locked_c_pre_acquire_range_lock(DBC *dbc, const DBT *key_left, const DBT *key_right) {
|
||||
toku_ydb_lock();
|
||||
int r = toku_c_pre_acquire_read_lock(dbc, key_left, key_right);
|
||||
int r = toku_c_pre_acquire_range_lock(dbc, key_left, key_right);
|
||||
toku_ydb_unlock();
|
||||
return r;
|
||||
}
|
||||
|
@ -6480,12 +6436,10 @@ toku_test_get_checkpointing_user_data_status (void) {
|
|||
|
||||
int
|
||||
toku_grab_write_lock (DB* db, DBT* key, TOKUTXN tokutxn) {
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
DB_TXN * txn = toku_txn_get_container_db_txn(tokutxn);
|
||||
//Left end of range == right end of range (point lock)
|
||||
write_lock_request_init(&request, txn, db,
|
||||
key,
|
||||
key);
|
||||
RANGE_LOCK_REQUEST_S request;
|
||||
write_lock_request_init(&request, txn, db, key, key);
|
||||
int r = grab_range_lock(&request);
|
||||
return r;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue