Commit 902b8bb9 authored by Yoni Fogel's avatar Yoni Fogel

Closes #477

created two versions of the lock tree, distinguished by -DTOKU_RT_NOOVERLAPS
modified rth iterator to provide hash key

git-svn-id: file:///svn/tokudb@2588 c7de825b-a66e-492c-adef-691d508d4ae1
parent 25cb6d4b
...@@ -386,21 +386,21 @@ inline static int __toku_lt_meets(toku_lock_tree* tree, toku_range* query, ...@@ -386,21 +386,21 @@ inline static int __toku_lt_meets(toku_lock_tree* tree, toku_range* query,
/* /*
Determines whether 'query' meets 'rt' at txn2 not equal to txn. Determines whether 'query' meets 'rt' at txn2 not equal to txn.
This function supports overlapping trees with heterogenous transactions, This function supports all range trees, but queries must be a single point.
but queries must be a single point.
Uses the standard definition of 'query' meets 'tree' at 'data' from the Uses the standard definition of 'query' meets 'tree' at 'data' from the
design document. design document.
*/ */
inline static int __toku_lt_meets_peer(toku_lock_tree* tree, toku_range* query, inline static int __toku_lt_meets_peer(toku_lock_tree* tree, toku_range* query,
toku_range_tree* rt, DB_TXN* self, BOOL* met) { toku_range_tree* rt, BOOL is_homogenous,
DB_TXN* self, BOOL* met) {
assert(tree && query && rt && self && met); assert(tree && query && rt && self && met);
assert(query->left == query->right); assert(query->left == query->right);
const u_int32_t query_size = 2; const u_int32_t query_size = is_homogenous ? 1 : 2;
toku_range buffer[query_size]; toku_range buffer[2];
u_int32_t buflen = query_size; u_int32_t buflen = query_size;
toku_range* buf = &buffer[0]; toku_range* buf = &buffer[0];
u_int32_t numfound; u_int32_t numfound;
int r; int r;
r = toku_rt_find(rt, query, query_size, &buf, &buflen, &numfound); r = toku_rt_find(rt, query, query_size, &buf, &buflen, &numfound);
...@@ -621,8 +621,10 @@ inline static int __toku_consolidate(toku_lock_tree* tree, ...@@ -621,8 +621,10 @@ inline static int __toku_consolidate(toku_lock_tree* tree,
BOOL alloc_right = TRUE; BOOL alloc_right = TRUE;
toku_range_tree* selfread; toku_range_tree* selfread;
assert(tree && to_insert && txn); assert(tree && to_insert && txn);
#if !defined(TOKU_RT_NOOVERLAPS)
toku_range_tree* mainread = tree->mainread; toku_range_tree* mainread = tree->mainread;
assert(mainread); assert(mainread);
#endif
/* Find the self read tree */ /* Find the self read tree */
r = __toku_lt_selfread(tree, txn, &selfread); r = __toku_lt_selfread(tree, txn, &selfread);
if (r!=0) return r; if (r!=0) return r;
...@@ -651,8 +653,10 @@ inline static int __toku_consolidate(toku_lock_tree* tree, ...@@ -651,8 +653,10 @@ inline static int __toku_consolidate(toku_lock_tree* tree,
/* ... and mainread. /* ... and mainread.
Growth direction: if we had no overlaps, the next line Growth direction: if we had no overlaps, the next line
should be commented out */ should be commented out */
#if !defined(TOKU_RT_NOOVERLAPS)
r = __toku_lt_delete_overlapping_ranges(tree, mainread, numfound); r = __toku_lt_delete_overlapping_ranges(tree, mainread, numfound);
if (r!=0) return __toku_lt_panic(tree, r); if (r!=0) return __toku_lt_panic(tree, r);
#endif
/* Free all the points from ranges in tree->buf[0]..tree->buf[numfound-1] */ /* Free all the points from ranges in tree->buf[0]..tree->buf[numfound-1] */
__toku_lt_free_points(tree, to_insert, numfound, NULL); __toku_lt_free_points(tree, to_insert, numfound, NULL);
/* We don't necessarily need to panic after here unless numfound > 0 /* We don't necessarily need to panic after here unless numfound > 0
...@@ -660,13 +664,16 @@ inline static int __toku_consolidate(toku_lock_tree* tree, ...@@ -660,13 +664,16 @@ inline static int __toku_consolidate(toku_lock_tree* tree,
/* Insert extreme range into selfread. */ /* Insert extreme range into selfread. */
/* VL */ /* VL */
r = toku_rt_insert(selfread, to_insert); r = toku_rt_insert(selfread, to_insert);
#if !defined(TOKU_RT_NOOVERLAPS)
int r2; int r2;
if (0) { died2: r2 = toku_rt_delete(selfread, to_insert); if (0) { died2: r2 = toku_rt_delete(selfread, to_insert);
if (r2!=0) return __toku_lt_panic(tree, r2); goto died1; } if (r2!=0) return __toku_lt_panic(tree, r2); goto died1; }
#endif
if (r!=0) { if (r!=0) {
/* If we deleted/merged anything, this is a panic situation. */ /* If we deleted/merged anything, this is a panic situation. */
if (numfound) return __toku_lt_panic(tree, TOKU_LT_INCONSISTENT); if (numfound) return __toku_lt_panic(tree, TOKU_LT_INCONSISTENT);
goto died1; } goto died1; }
#if !defined(TOKU_RT_NOOVERLAPS)
/* Insert extreme range into mainread. */ /* Insert extreme range into mainread. */
assert(tree->mainread); assert(tree->mainread);
r = toku_rt_insert(tree->mainread, to_insert); r = toku_rt_insert(tree->mainread, to_insert);
...@@ -674,6 +681,7 @@ inline static int __toku_consolidate(toku_lock_tree* tree, ...@@ -674,6 +681,7 @@ inline static int __toku_consolidate(toku_lock_tree* tree,
/* If we deleted/merged anything, this is a panic situation. */ /* If we deleted/merged anything, this is a panic situation. */
if (numfound) return __toku_lt_panic(tree, TOKU_LT_INCONSISTENT); if (numfound) return __toku_lt_panic(tree, TOKU_LT_INCONSISTENT);
goto died2; } goto died2; }
#endif
__toku_lt_range_incr(tree, numfound); __toku_lt_range_incr(tree, numfound);
return 0; return 0;
} }
...@@ -944,11 +952,15 @@ int toku_lt_create(toku_lock_tree** ptree, DB* db, BOOL duplicates, ...@@ -944,11 +952,15 @@ int toku_lt_create(toku_lock_tree** ptree, DB* db, BOOL duplicates,
tmp_tree->malloc = user_malloc; tmp_tree->malloc = user_malloc;
tmp_tree->free = user_free; tmp_tree->free = user_free;
tmp_tree->realloc = user_realloc; tmp_tree->realloc = user_realloc;
#if defined(TOKU_RT_NOOVERLAPS)
if (0) { died2: goto died1; }
#else
r = toku_rt_create(&tmp_tree->mainread, r = toku_rt_create(&tmp_tree->mainread,
__toku_lt_point_cmp, __toku_lt_txn_cmp, TRUE, __toku_lt_point_cmp, __toku_lt_txn_cmp, TRUE,
user_malloc, user_free, user_realloc); user_malloc, user_free, user_realloc);
if (0) { died2: toku_rt_close(tmp_tree->mainread); goto died1; } if (0) { died2: toku_rt_close(tmp_tree->mainread); goto died1; }
if (r!=0) goto died1; if (r!=0) goto died1;
#endif
r = toku_rt_create(&tmp_tree->borderwrite, r = toku_rt_create(&tmp_tree->borderwrite,
__toku_lt_point_cmp, __toku_lt_txn_cmp, FALSE, __toku_lt_point_cmp, __toku_lt_txn_cmp, FALSE,
user_malloc, user_free, user_realloc); user_malloc, user_free, user_realloc);
...@@ -969,8 +981,10 @@ int toku_lt_close(toku_lock_tree* tree) { ...@@ -969,8 +981,10 @@ int toku_lt_close(toku_lock_tree* tree) {
if (!tree) return EINVAL; if (!tree) return EINVAL;
int r; int r;
int r2 = 0; int r2 = 0;
#if !defined(TOKU_RT_NOOVERLAPS)
r = toku_rt_close(tree->mainread); r = toku_rt_close(tree->mainread);
if (r!=0) r2 = r; if (r!=0) r2 = r;
#endif
r = toku_rt_close(tree->borderwrite); r = toku_rt_close(tree->borderwrite);
if (!r2 && r!=0) r2 = r; if (!r2 && r!=0) r2 = r;
...@@ -1043,13 +1057,39 @@ int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn, ...@@ -1043,13 +1057,39 @@ int toku_lt_acquire_range_read_lock(toku_lock_tree* tree, DB_TXN* txn,
return __toku_consolidate(tree, &query, &to_insert, txn); return __toku_consolidate(tree, &query, &to_insert, txn);
} }
static int __toku_lt_write_point_conflicts_reads(toku_lock_tree* tree,
DB_TXN* txn, toku_range* query) {
int r = 0;
BOOL met = FALSE;
#if defined(TOKU_RT_NOOVERLAPS)
toku_rth_start_scan(tree->rth);
toku_rt_forest* forest;
while ((forest = toku_rth_next(tree->rth)) != NULL) {
if (forest->self_read != NULL && forest->hash_key != txn) {
r = __toku_lt_meets_peer(tree, query, forest->self_read, TRUE, txn,
&met);
if (r!=0) goto cleanup;
if (met) { r = DB_LOCK_DEADLOCK; goto cleanup; }
}
}
#else
toku_range_tree* mainread = tree->mainread; assert(mainread);
r = __toku_lt_meets_peer(tree, query, mainread, FALSE, txn, &met);
if (r!=0) goto cleanup;
if (met) { r = DB_LOCK_DEADLOCK; goto cleanup; }
#endif
r = 0;
cleanup:
return r;
}
int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn, int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
const DBT* key, const DBT* data) { const DBT* key, const DBT* data) {
int r; int r;
toku_point endpoint; toku_point endpoint;
toku_range query; toku_range query;
BOOL dominated; BOOL dominated;
toku_range_tree* mainread;
r = __toku_lt_preprocess(tree, txn, key, &data, r = __toku_lt_preprocess(tree, txn, key, &data,
key, &data, key, &data,
...@@ -1061,11 +1101,8 @@ int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn, ...@@ -1061,11 +1101,8 @@ int toku_lt_acquire_write_lock(toku_lock_tree* tree, DB_TXN* txn,
__toku_lt_ifexist_selfwrite(tree, txn), &dominated); __toku_lt_ifexist_selfwrite(tree, txn), &dominated);
if (r || dominated) return r; if (r || dominated) return r;
/* else if K meets mainread at 'txn2' then return failure */ /* else if K meets mainread at 'txn2' then return failure */
BOOL met; r = __toku_lt_write_point_conflicts_reads(tree, txn, &query);
mainread = tree->mainread; assert(mainread); if (r!=0) return r;
r = __toku_lt_meets_peer(tree, &query, mainread, txn, &met);
if (r!=0) return r;
if (met) return DB_LOCK_DEADLOCK;
/* /*
else if 'K' meets borderwrite at 'peer' ('peer'!='txn') && else if 'K' meets borderwrite at 'peer' ('peer'!='txn') &&
'K' meets selfwrite('peer') then return failure. 'K' meets selfwrite('peer') then return failure.
......
...@@ -55,7 +55,7 @@ toku_rt_forest* toku_rth_find(toku_rth* table, DB_TXN* key) { ...@@ -55,7 +55,7 @@ toku_rt_forest* toku_rth_find(toku_rth* table, DB_TXN* key) {
uint32 index = __toku_rth_hash(table, key); uint32 index = __toku_rth_hash(table, key);
toku_rth_elt* element = table->table[index]; toku_rth_elt* element = table->table[index];
while (element && element->key != key) element = element->next; while (element && element->value.hash_key != key) element = element->next;
return element ? &element->value : NULL; return element ? &element->value : NULL;
} }
...@@ -102,7 +102,7 @@ void toku_rth_delete(toku_rth* table, DB_TXN* key) { ...@@ -102,7 +102,7 @@ void toku_rth_delete(toku_rth* table, DB_TXN* key) {
/* Elements of the right hash must exist. */ /* Elements of the right hash must exist. */
assert(element); assert(element);
/* Case where it is the first element. */ /* Case where it is the first element. */
if (element->key == key) { if (element->value.hash_key == key) {
table->table[index] = element->next; table->table[index] = element->next;
table->free(element); table->free(element);
table->num_keys--; table->num_keys--;
...@@ -114,7 +114,7 @@ void toku_rth_delete(toku_rth* table, DB_TXN* key) { ...@@ -114,7 +114,7 @@ void toku_rth_delete(toku_rth* table, DB_TXN* key) {
assert(element); assert(element);
prev = element; prev = element;
element = element->next; element = element->next;
} while (element->key != key); } while (element->value.hash_key != key);
/* Must be found. */ /* Must be found. */
assert(element); assert(element);
prev->next = element->next; prev->next = element->next;
...@@ -134,7 +134,7 @@ int toku_rth_insert(toku_rth* table, DB_TXN* key) { ...@@ -134,7 +134,7 @@ int toku_rth_insert(toku_rth* table, DB_TXN* key) {
toku_rth_elt* element = (toku_rth_elt*)table->malloc(sizeof(*element)); toku_rth_elt* element = (toku_rth_elt*)table->malloc(sizeof(*element));
if (!element) return errno; if (!element) return errno;
memset(element, 0, sizeof(*element)); memset(element, 0, sizeof(*element));
element->key = key; element->value.hash_key = key;
element->next = table->table[index]; element->next = table->table[index];
table->table[index] = element; table->table[index] = element;
table->num_keys++; table->num_keys++;
......
...@@ -20,13 +20,13 @@ typedef u_int32_t uint32; ...@@ -20,13 +20,13 @@ typedef u_int32_t uint32;
typedef struct __toku_rt_forest toku_rt_forest; typedef struct __toku_rt_forest toku_rt_forest;
struct __toku_rt_forest { struct __toku_rt_forest {
DB_TXN* hash_key;
toku_range_tree* self_read; toku_range_tree* self_read;
toku_range_tree* self_write; toku_range_tree* self_write;
}; };
typedef struct __toku_rth_elt toku_rth_elt; typedef struct __toku_rth_elt toku_rth_elt;
struct __toku_rth_elt { struct __toku_rth_elt {
DB_TXN* key;
toku_rt_forest value; toku_rt_forest value;
toku_rth_elt* next; toku_rth_elt* next;
}; };
......
...@@ -44,17 +44,24 @@ default: check ...@@ -44,17 +44,24 @@ default: check
all: make_libs $(ALL_TESTS) all: make_libs $(ALL_TESTS)
#check: check.lin check.tlog check.log check: check.lin check.tlin #check.tlog check.log
check: check.lin #check.tlog check.log @ echo $@ ok
@ echo ok
tests.lin: make_libs $(LIN_TESTS) tests.lin: make_libs $(LIN_TESTS)
@ echo $@ ok
check.lin: make_libs $(RUN_LIN_TESTS) check.lin: make_libs $(RUN_LIN_TESTS)
@ echo $@ ok
tests.tlin: make_libs $(TLIN_TESTS) tests.tlin: make_libs $(TLIN_TESTS)
@ echo $@ ok
check.tlin: make_libs $(RUN_TLIN_TESTS) check.tlin: make_libs $(RUN_TLIN_TESTS)
@ echo $@ ok
tests.tlog: make_libs $(TLOG_TESTS) tests.tlog: make_libs $(TLOG_TESTS)
@ echo $@ ok
check.tlog: make_libs $(RUN_TLOG_TESTS) check.tlog: make_libs $(RUN_TLOG_TESTS)
@ echo $@ ok
tests.log: make_libs $(LOG_TESTS) tests.log: make_libs $(LOG_TESTS)
@ echo $@ ok
check.log: make_libs $(RUN_LOG_TESTS) check.log: make_libs $(RUN_LOG_TESTS)
@ echo $@ ok
# Need these rule so that Make knows about all the file names # Need these rule so that Make knows about all the file names
.PHONY: %.linrun %.tlinrun %.tlogrun %.logrun %.run .PHONY: %.linrun %.tlinrun %.tlogrun %.logrun %.run
...@@ -102,17 +109,17 @@ LT_BINS = ../lth.o ../rth.o ...@@ -102,17 +109,17 @@ LT_BINS = ../lth.o ../rth.o
LT_OVERLAP = ../locktree_global_readset.o LT_OVERLAP = ../locktree_global_readset.o
LT_NOOVERLAP = ../locktree_no_global_readset.o LT_NOOVERLAP = ../locktree_no_global_readset.o
LT_LINEAR = $(LT_OVERLAP) $(LT_BINS) $(RT_LINEAR_BINS) LT_LINEAR = $(LT_OVERLAP) $(LT_BINS) $(RT_LINEAR_BINS)
LT_TLINEAR = $(LT_NOOVERLAP) $(LT_BINS) $(RT_TLINEAR_BINS) -DTOKU_RT_NOOVERLAPS LT_TLINEAR = $(LT_NOOVERLAP) $(LT_BINS) $(RT_TLINEAR_BINS)
LT_TLOG = $(LT_NOOVERLAP) $(LT_BINS) $(RT_TLOG_BINS) -DTOKU_RT_NOOVERLAPS LT_TLOG = $(LT_NOOVERLAP) $(LT_BINS) $(RT_TLOG_BINS)
LT_LOG = $(LT_OVERLAP) $(LT_BINS) $(RT_LOG_BINS) LT_LOG = $(LT_OVERLAP) $(LT_BINS) $(RT_LOG_BINS)
%.lin: %.c ../locktree.h test.h %.lin: %.c ../locktree.h test.h $(LT_LINEAR)
cc -DDIR=\"dir.$<.lin\" $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LT_LINEAR) cc -DDIR=\"dir.$<.lin\" $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LT_LINEAR)
%.tlin: %.c ../locktree.h test.h %.tlin: %.c ../locktree.h test.h $(LT_TLINEAR)
cc -DDIR=\"dir.$<.tlin\" $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LT_TLINEAR) cc -DDIR=\"dir.$<.tlin\" $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LT_TLINEAR) -DTOKU_RT_NOOVERLAPS
%.tlog: %.c ../locktree.h test.h %.tlog: %.c ../locktree.h test.h $(LT_TLOG)
cc -DDIR=\"dir.$<.tlog\" $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LT_TLOG) cc -DDIR=\"dir.$<.tlog\" $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LT_TLOG) -DTOKU_RT_NOOVERLAPS
%.log: %.c ../locktree.h test.h %.log: %.c ../locktree.h test.h $(LT_LOG)
cc -DDIR=\"dir.$<.log\" $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LT_LOG) cc -DDIR=\"dir.$<.log\" $(CPPFLAGS) $(CFLAGS) $< -o $@ $(LT_LOG)
.PHONY: make_libs .PHONY: make_libs
......
...@@ -37,15 +37,20 @@ default: check ...@@ -37,15 +37,20 @@ default: check
all: make_libs $(ALL_TESTS) all: make_libs $(ALL_TESTS)
#check: check.lin check.tlog check.log
check: check.lin #check.tlog check.log check: check.lin #check.tlog check.log
@ echo ok @ echo $@ ok
tests.lin: make_libs $(LIN_TESTS) tests.lin: make_libs $(LIN_TESTS)
@ echo $@ ok
check.lin: make_libs $(RUN_LIN_TESTS) check.lin: make_libs $(RUN_LIN_TESTS)
@ echo $@ ok
tests.tlog: make_libs $(TLOG_TESTS) tests.tlog: make_libs $(TLOG_TESTS)
@ echo $@ ok
check.tlog: make_libs $(RUN_TLOG_TESTS) check.tlog: make_libs $(RUN_TLOG_TESTS)
@ echo $@ ok
tests.log: make_libs $(LOG_TESTS) tests.log: make_libs $(LOG_TESTS)
@ echo $@ ok
check.log: make_libs $(RUN_LOG_TESTS) check.log: make_libs $(RUN_LOG_TESTS)
@ echo $@ ok
# Need these rule so that Make knows about all the file names # Need these rule so that Make knows about all the file names
.PHONY: %.linrun %.logrun %.run %.tlogrun .PHONY: %.linrun %.logrun %.run %.tlogrun
...@@ -83,11 +88,11 @@ LINEAR_BINS = ../linear.o ...@@ -83,11 +88,11 @@ LINEAR_BINS = ../linear.o
TLOG_BINS = ../log_nooverlap.o TLOG_BINS = ../log_nooverlap.o
LOG_BINS = ../log.o LOG_BINS = ../log.o
%.lin: %.c ../rangetree.h test.h %.lin: %.c ../rangetree.h test.h $(LINEAR_BINS)
cc -DDIR=\"dir.$<.lin\" $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LINEAR_BINS) cc -DDIR=\"dir.$<.lin\" $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LINEAR_BINS)
%.tlog: %.c ../rangetree.h test.h %.tlog: %.c ../rangetree.h test.h $(TLOG_BINS)
cc -DDIR=\"dir.$<.log\" $(CFLAGS) $(CPPFLAGS) $< -o $@ $(TLOG_BINS) cc -DDIR=\"dir.$<.log\" $(CFLAGS) $(CPPFLAGS) $< -o $@ $(TLOG_BINS)
%.log: %.c ../rangetree.h test.h %.log: %.c ../rangetree.h test.h $(LOG_BINS)
cc -DDIR=\"dir.$<.log\" $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LOG_BINS) cc -DDIR=\"dir.$<.log\" $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LOG_BINS)
.PHONY: make_libs .PHONY: make_libs
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment