From 8a71d45b69f538c486be0d139df38e08c79e99db Mon Sep 17 00:00:00 2001 From: Yoni Fogel Date: Fri, 16 May 2008 20:09:13 +0000 Subject: [PATCH] Closes #777 omt used to replaced libredblack git-svn-id: file:///svn/tokudb@3986 c7de825b-a66e-492c-adef-691d508d4ae1 --- buildheader/db.h_4_1 | 1 + buildheader/db.h_4_3 | 1 + buildheader/db.h_4_4 | 1 + buildheader/db.h_4_5 | 1 + buildheader/db.h_4_6 | 5 +- buildheader/make_db_h.c | 4 +- include/db.h | 1 + newbrt/omt.c | 29 +- newbrt/omt.h | 23 + src/lock_tree/locktree.c | 118 ++- src/lock_tree/tests/Makefile | 2 +- src/range_tree/Makefile | 3 +- src/range_tree/linear.c | 35 +- src/range_tree/log_nooverlap.c | 429 ++++------ src/range_tree/rangetree.h | 4 +- src/range_tree/tests/Makefile | 11 +- src/range_tree/tests/test.h | 13 +- src/range_tree/tests/test_00000_createclose.c | 2 +- src/range_tree/tests/test_00025_memalloc.c | 7 - src/range_tree/tokuredblack.c | 763 ------------------ src/range_tree/tokuredblack.h | 106 --- 21 files changed, 307 insertions(+), 1252 deletions(-) delete mode 100644 src/range_tree/tokuredblack.c delete mode 100644 src/range_tree/tokuredblack.h diff --git a/buildheader/db.h_4_1 b/buildheader/db.h_4_1 index 28d0c41fa92..4d87cc92ccd 100644 --- a/buildheader/db.h_4_1 +++ b/buildheader/db.h_4_1 @@ -99,6 +99,7 @@ typedef enum { #endif /* TOKUDB specific error codes */ #define TOKUDB_OUT_OF_LOCKS -100000 +#define TOKUDB_SUCCEEDED_EARLY -100001 /* in wrap mode, top-level function txn_begin is renamed, but the field isn't renamed, so we have to hack it here.*/ #ifdef _TOKUDB_WRAP_H #undef txn_begin diff --git a/buildheader/db.h_4_3 b/buildheader/db.h_4_3 index 00e646f1676..d093f1be45d 100644 --- a/buildheader/db.h_4_3 +++ b/buildheader/db.h_4_3 @@ -101,6 +101,7 @@ typedef enum { #endif /* TOKUDB specific error codes */ #define TOKUDB_OUT_OF_LOCKS -100000 +#define TOKUDB_SUCCEEDED_EARLY -100001 /* in wrap mode, top-level function txn_begin is renamed, but the field isn't renamed, so we have to hack it here.*/ #ifdef _TOKUDB_WRAP_H #undef txn_begin diff --git a/buildheader/db.h_4_4 b/buildheader/db.h_4_4 index 10bcb189052..0f8eb63ec60 100644 --- a/buildheader/db.h_4_4 +++ b/buildheader/db.h_4_4 @@ -101,6 +101,7 @@ typedef enum { #endif /* TOKUDB specific error codes */ #define TOKUDB_OUT_OF_LOCKS -100000 +#define TOKUDB_SUCCEEDED_EARLY -100001 /* in wrap mode, top-level function txn_begin is renamed, but the field isn't renamed, so we have to hack it here.*/ #ifdef _TOKUDB_WRAP_H #undef txn_begin diff --git a/buildheader/db.h_4_5 b/buildheader/db.h_4_5 index 755eff9689b..8a421599a3f 100644 --- a/buildheader/db.h_4_5 +++ b/buildheader/db.h_4_5 @@ -101,6 +101,7 @@ typedef enum { #endif /* TOKUDB specific error codes */ #define TOKUDB_OUT_OF_LOCKS -100000 +#define TOKUDB_SUCCEEDED_EARLY -100001 /* in wrap mode, top-level function txn_begin is renamed, but the field isn't renamed, so we have to hack it here.*/ #ifdef _TOKUDB_WRAP_H #undef txn_begin diff --git a/buildheader/db.h_4_6 b/buildheader/db.h_4_6 index e36e6d3f00e..4a4ae77e53c 100644 --- a/buildheader/db.h_4_6 +++ b/buildheader/db.h_4_6 @@ -11,9 +11,9 @@ extern "C" { #define TOKUDB 1 #define DB_VERSION_MAJOR 4 #define DB_VERSION_MINOR 6 -#define DB_VERSION_PATCH 21 +#define DB_VERSION_PATCH 19 #ifndef _TOKUDB_WRAP_H -#define DB_VERSION_STRING "Tokutek: TokuDB 4.6.21" +#define DB_VERSION_STRING "Tokutek: TokuDB 4.6.19" #else #define DB_VERSION_STRING_ydb "Tokutek: TokuDB (wrapped bdb)" #endif @@ -103,6 +103,7 @@ typedef enum { #endif /* TOKUDB specific error codes */ #define TOKUDB_OUT_OF_LOCKS -100000 +#define TOKUDB_SUCCEEDED_EARLY -100001 /* in wrap mode, top-level function txn_begin is renamed, but the field isn't renamed, so we have to hack it here.*/ #ifdef _TOKUDB_WRAP_H #undef txn_begin diff --git a/buildheader/make_db_h.c b/buildheader/make_db_h.c index 49621bb6700..70cd7e4351e 100644 --- a/buildheader/make_db_h.c +++ b/buildheader/make_db_h.c @@ -30,7 +30,8 @@ void print_db_notices (void) { #define dodefine(name) printf("#define %s %d\n", #name, name) enum { - TOKUDB_OUT_OF_LOCKS = -100000, + TOKUDB_OUT_OF_LOCKS = -100000, + TOKUDB_SUCCEEDED_EARLY = -100001 }; void print_defines (void) { @@ -130,6 +131,7 @@ void print_defines (void) { /* TOKUDB specific error codes*/ printf("/* TOKUDB specific error codes */\n"); dodefine(TOKUDB_OUT_OF_LOCKS); + dodefine(TOKUDB_SUCCEEDED_EARLY); } //#define DECL_LIMIT 100 diff --git a/include/db.h b/include/db.h index 10bcb189052..0f8eb63ec60 100644 --- a/include/db.h +++ b/include/db.h @@ -101,6 +101,7 @@ typedef enum { #endif /* TOKUDB specific error codes */ #define TOKUDB_OUT_OF_LOCKS -100000 +#define TOKUDB_SUCCEEDED_EARLY -100001 /* in wrap mode, top-level function txn_begin is renamed, but the field isn't renamed, so we have to hack it here.*/ #ifdef _TOKUDB_WRAP_H #undef txn_begin diff --git a/newbrt/omt.c b/newbrt/omt.c index a8964d7782f..a735eb3dc3f 100644 --- a/newbrt/omt.c +++ b/newbrt/omt.c @@ -134,10 +134,10 @@ static inline int maybe_resize_and_rebuild(OMT omt, u_int32_t n, enum build_choi OMT_NODE new_nodes = NULL; OMTVALUE *tmp_values = NULL; int r = ENOSYS; - u_int32_t new_size = 2*n; + u_int32_t new_size = n<=2 ? 4 : 2*n; if (omt->tmparray_sizetmparray_size/4 >= n && n>=2)) { + (omt->tmparray_size/2 >= new_size)) { /* Malloc and free instead of realloc (saves the memcpy). */ MALLOC_N(new_size, new_tmparray); if (new_tmparray==NULL) { r = errno; goto cleanup; } @@ -147,7 +147,7 @@ static inline int maybe_resize_and_rebuild(OMT omt, u_int32_t n, enum build_choi * We are increasing the number of elements and there is no free space. * The array is too large. */ u_int32_t num_nodes = nweight(omt, omt->root); - if ((omt->node_capacity/4 >= n && n>=2) || + if ((omt->node_capacity/2 >= new_size) || (omt->free_idx>=omt->node_capacity && num_nodesnode_capacitynodes = new_nodes; omt->node_capacity = new_size; omt->free_idx = 0; /* Allocating from mempool starts over. */ + omt->root = NODE_NULL; if (choice==MAYBE_REBUILD) { create_from_sorted_array_internal(omt, &omt->root, tmp_values, num_nodes); } @@ -355,18 +356,25 @@ int toku_omt_fetch(OMT V, u_int32_t i, OMTVALUE *v) { return 0; } -static inline int iterate_internal(OMT omt, node_idx n_idx, u_int32_t idx, +static inline int iterate_internal(OMT omt, u_int32_t left, u_int32_t right, + node_idx n_idx, u_int32_t idx, int (*f)(OMTVALUE, u_int32_t, void*), void*v) { int r; if (n_idx==NODE_NULL) return 0; OMT_NODE n = omt->nodes+n_idx; - if ((r=iterate_internal(omt, n->left, idx, f, v))) return r; - if ((r=f(n->value, idx+nweight(omt, n->left), v))) return r; - return iterate_internal(omt, n->right, idx+nweight(omt, n->left)+1, f, v); + u_int32_t idx_root = idx+nweight(omt,n->left); + if (left< idx_root && (r=iterate_internal(omt, left, right, n->left, idx, f, v))) return r; + if (left<=idx_root && idx_rootvalue, idx_root, v))) return r; + if (idx_root+1right, idx_root+1, f, v); + return 0; } int toku_omt_iterate(OMT omt, int (*f)(OMTVALUE, u_int32_t, void*), void*v) { - return iterate_internal(omt, omt->root, 0, f, v); + return iterate_internal(omt, 0, nweight(omt, omt->root), omt->root, 0, f, v); +} + +int toku_omt_iterate_on_range(OMT omt, u_int32_t left, u_int32_t right, int (*f)(OMTVALUE, u_int32_t, void*), void*v) { + return iterate_internal(omt, left, right, omt->root, 0, f, v); } int toku_omt_insert(OMT omt, OMTVALUE value, int(*h)(OMTVALUE, void*v), void *v, u_int32_t *index) { @@ -511,3 +519,8 @@ cleanup: return r; } +void toku_omt_clear(OMT omt) { + omt->free_idx = 0; + omt->root = NODE_NULL; +} + diff --git a/newbrt/omt.h b/newbrt/omt.h index 7dd51fa2e97..1438a89477f 100644 --- a/newbrt/omt.h +++ b/newbrt/omt.h @@ -95,6 +95,23 @@ u_int32_t toku_omt_size(OMT V); // Requires: V != NULL // Performance: time=O(1) +int toku_omt_iterate_on_range(OMT omt, u_int32_t left, u_int32_t right, int (*f)(OMTVALUE, u_int32_t, void*), void*v); +// Effect: Iterate over the values of the omt, from left to right, calling f on each value. +// The second argument passed to f is the index of the value. +// The third argument passed to f is v. +// The indices run from 0 (inclusive) to toku_omt_size(omt) (exclusive). +// We will iterate only over [left,right) +// +// Requires: omt != NULL +// left <= right +// Requires: f != NULL +// Returns: +// If f ever returns nonzero, then the iteration stops, and the value returned by f is returned by toku_omt_iterate. +// If f always returns zero, then toku_omt_iterate returns 0. +// Requires: Don't modify omt while running. (E.g., f may not insert or delete values form omt.) +// Performance: time=O(i+\log N) where i is the number of times f is called, and N is the number of elements in omt. +// Rational: Although the functional iterator requires defining another function (as opposed to C++ style iterator), it is much easier to read. + int toku_omt_iterate(OMT omt, int (*f)(OMTVALUE, u_int32_t, void*), void*v); // Effect: Iterate over the values of the omt, from left to right, calling f on each value. // The second argument passed to f is the index of the value. @@ -260,4 +277,10 @@ int toku_omt_merge(OMT leftomt, OMT rightomt, OMT *newomt); // On error, nothing is modified. // Performance: time=O(n) is acceptable, but one can imagine implementations that are O(\log n) worst-case. +void toku_omt_clear(OMT omt); +// Effect: Set the tree to be empty. +// Note: Will not resize the array, since void precludes allowing a malloc. +// Performance: time=O(1) + #endif /* #ifndef OMT_H */ + diff --git a/src/lock_tree/locktree.c b/src/lock_tree/locktree.c index 1c3a7f2f80f..e6ae16bde77 100644 --- a/src/lock_tree/locktree.c +++ b/src/lock_tree/locktree.c @@ -926,6 +926,24 @@ static inline void toku__lt_init_full_query(toku_lock_tree* tree, toku_interval* toku__init_query(query, left, right); } +typedef struct { + toku_lock_tree* lt; + toku_range_tree* rtdel; + toku_interval* query; + toku_range* store_value; +} free_contents_info; + +static int free_contents_helper(toku_range* value, void* extra) { + free_contents_info* info = extra; + int r = ENOSYS; + + *info->store_value = *value; + if ((r=toku__lt_free_points(info->lt, info->query, 1, info->rtdel))) { + return toku__lt_panic(info->lt, r); + } + return 0; +} + /* TODO: Refactor. toku__lt_free_points should be replaced (or supplanted) with a @@ -937,20 +955,20 @@ static inline int toku__lt_free_contents(toku_lock_tree* tree, toku_range_tree* if (!rt) return 0; int r; - int r2; - BOOL found = FALSE; toku_interval query; toku_point left; toku_point right; toku__lt_init_full_query(tree, &query, &left, &right); - toku_rt_start_scan(rt); - while ((r = toku_rt_next(rt, &tree->buf[0], &found)) == 0 && found) { - r = toku__lt_free_points(tree, &query, 1, rtdel); - if (r!=0) return toku__lt_panic(tree, r); - } - r2 = toku_rt_close(rt); - assert(r2 == 0); + free_contents_info info; + info.lt = tree; + info.rtdel = rtdel; + info.query = &query; + info.store_value = &tree->buf[0]; + + if ((r=toku_rt_iterate(rt, free_contents_helper, &info))) return r; + r = toku_rt_close(rt); + assert(r == 0); return r; } @@ -1519,8 +1537,29 @@ cleanup: return r; } +typedef struct { + toku_lock_tree* lt; + toku_range_tree* border; + toku_interval* escalate_interval; + TXNID txn; +} escalate_info; + +static int escalate_read_locks_helper(toku_range* border_range, void* extra) { + escalate_info* info = extra; + int r = ENOSYS; + + if (!toku__lt_txn_cmp(border_range->data, info->txn)) { r = 0; goto cleanup; } + info->escalate_interval->right = border_range->ends.left; + r = toku__lt_escalate_read_locks_in_interval(info->lt, + info->escalate_interval, info->txn); + if (r!=0) goto cleanup; + info->escalate_interval->left = border_range->ends.right; + r = 0; +cleanup: + return r; +} -//TODO: Whenever comparing TXNIDs use the comparison function INSTEAD of just '!= or ==' + //TODO: Whenever comparing TXNIDs use the comparison function INSTEAD of just '!= or ==' static int toku__lt_escalate_read_locks(toku_lock_tree* tree, TXNID txn) { int r = ENOSYS; assert(tree); @@ -1534,21 +1573,34 @@ static int toku__lt_escalate_read_locks(toku_lock_tree* tree, TXNID txn) { toku_range_tree* border = tree->borderwrite; assert(border); - toku_range border_range; - BOOL found; - toku_rt_start_scan(border); + escalate_info info; + info.lt = tree; + info.border = border; + info.escalate_interval = &query; + info.txn = txn; + if ((r = toku_rt_iterate(border, escalate_read_locks_helper, &info))) goto cleanup; /* Special case for zero entries in border? Just do the 'after'? */ - while ((r = toku_rt_next(border, &border_range, &found)) == 0 && found) { - if (!toku__lt_txn_cmp(border_range.data, txn)) { continue; } - query.right = border_range.ends.left; - r = toku__lt_escalate_read_locks_in_interval(tree, &query, txn); - if (r!=0) { goto cleanup; } - query.left = border_range.ends.right; - } query.right = &infinite; r = toku__lt_escalate_read_locks_in_interval(tree, &query, txn); - if (r!=0) { goto cleanup; } - goto cleanup; + if (r!=0) goto cleanup; + r = 0; +cleanup: + return r; +} + +static int escalate_write_locks_helper(toku_range* border_range, void* extra) { + toku_lock_tree* tree = extra; + int r = ENOSYS; + BOOL trivial; + if ((r = toku__border_escalation_trivial(tree, border_range, &trivial))) goto cleanup; + if (!trivial) { r = 0; goto cleanup; } + /* + * At this point, we determine that escalation is simple, + * Attempt escalation + */ + r = toku__escalate_writes_from_border_range(tree, border_range); + if (r!=0) { r = toku__lt_panic(tree, r); goto cleanup; } + r = 0; cleanup: return r; } @@ -1562,25 +1614,9 @@ cleanup: static int toku__lt_escalate_write_locks(toku_lock_tree* tree) { int r = ENOSYS; assert(tree); - assert(tree->lock_escalation_allowed); - toku_range_tree* border = tree->borderwrite; - assert(border); - toku_range border_range; - BOOL found = FALSE; - BOOL trivial = FALSE; - - toku_rt_start_scan(border); - while ((r = toku_rt_next(border, &border_range, &found)) == 0 && found) { - r = toku__border_escalation_trivial(tree, &border_range, &trivial); - if (r!=0) { goto cleanup; } - if (!trivial) { continue; } - /* - * At this point, we determine that escalation is simple, - * Attempt escalation - */ - r = toku__escalate_writes_from_border_range(tree, &border_range); - if (r!=0) { r = toku__lt_panic(tree, r); goto cleanup; } - } + assert(tree->borderwrite); + + if ((r = toku_rt_iterate(tree->borderwrite, escalate_write_locks_helper, tree))) goto cleanup; r = 0; cleanup: return r; diff --git a/src/lock_tree/tests/Makefile b/src/lock_tree/tests/Makefile index 3ae123f8b61..b2499740f88 100644 --- a/src/lock_tree/tests/Makefile +++ b/src/lock_tree/tests/Makefile @@ -103,7 +103,7 @@ NEWBRT_BINS = ../../../newbrt/newbrt.o RT_LINEAR_BINS = ../../range_tree/linear.o RT_TLINEAR_BINS = ../../range_tree/linear.o -RT_TLOG_BINS = ../../range_tree/log_nooverlap.o ../../range_tree/tokuredblack.o +RT_TLOG_BINS = ../../range_tree/log_nooverlap.o RT_LOG_BINS = ../../range_tree/log.o LT_BINS = ../lth.o ../rth.o ../idlth.o ../db_id.o diff --git a/src/range_tree/Makefile b/src/range_tree/Makefile index e6c7baf82f5..e4088e84edb 100644 --- a/src/range_tree/Makefile +++ b/src/range_tree/Makefile @@ -24,7 +24,7 @@ ifneq ($(OSX),) CFLAGS+=-fno-common endif -BINS = linear.o log_nooverlap.o tokuredblack.o rangetree.o #log.o +BINS = linear.o log_nooverlap.o rangetree.o #log.o build: $(BINS) cd tests;$(MAKE) build @@ -50,4 +50,3 @@ log.o: log.c $(HEADERS) log_nooverlap.o: log_nooverlap.c $(HEADERS) -tokuredblack.o: tokuredblack.c $(HEADERS) tokuredblack.h diff --git a/src/range_tree/linear.c b/src/range_tree/linear.c index 134938eb707..6ce99b92ddd 100644 --- a/src/range_tree/linear.c +++ b/src/range_tree/linear.c @@ -21,21 +21,12 @@ struct __toku_range_tree_local { //Linear version only fields: toku_range* ranges; u_int32_t ranges_len; - /* - * BOOL that says whether we are allowed to iterate. - */ - BOOL iter_is_valid; - u_int32_t iter_index; }; #include static const u_int32_t minlen = 64; -static inline void toku_rt_invalidate_iteration(toku_range_tree* tree) { - tree->i.iter_is_valid = FALSE; -} - 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); @@ -135,7 +126,6 @@ int toku_rt_create(toku_range_tree** ptree, user_malloc(tmptree->i.ranges_len * sizeof(toku_range)); if (!tmptree->i.ranges) { r = errno; goto died1; } - toku_rt_invalidate_iteration(tmptree); *ptree = tmptree; return 0; @@ -144,7 +134,6 @@ int toku_rt_create(toku_range_tree** ptree, void toku_rt_clear(toku_range_tree* tree) { assert(tree); toku__rt_decrease_capacity(tree, 0); - toku_rt_invalidate_iteration(tree); tree->numelements = 0; } @@ -207,7 +196,6 @@ int toku_rt_insert(toku_range_tree* tree, toku_range* range) { tree->i.ranges[move] = tree->i.ranges[move - 1]; } tree->i.ranges[i] = *range; - toku_rt_invalidate_iteration(tree); return 0; } @@ -227,7 +215,6 @@ int toku_rt_delete(toku_range_tree* tree, toku_range* range) { tree->i.ranges[move] = tree->i.ranges[move + 1]; } toku__rt_decrease_capacity(tree, --tree->numelements); - toku_rt_invalidate_iteration(tree); return 0; } @@ -279,27 +266,15 @@ int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) { return 0; } -void toku_rt_start_scan (toku_range_tree* range_tree) { - assert(range_tree); - range_tree->i.iter_is_valid = TRUE; - range_tree->i.iter_index = 0; - return; -} +int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra) { + u_int32_t index; -int toku_rt_next (toku_range_tree* range_tree, toku_range* out_range, BOOL* elem_found) { int r = ENOSYS; - - if (!range_tree || !out_range || !elem_found) { r = EINVAL; goto cleanup; } - /* Check to see if range tree is in invalid iteration state */ - if (!range_tree->i.iter_is_valid) { r = EDOM; goto cleanup; } - - *elem_found = range_tree->i.iter_index < range_tree->numelements; - range_tree->i.iter_is_valid = range_tree->i.iter_index < range_tree->numelements; - if (*elem_found) { *out_range = range_tree->i.ranges[range_tree->i.iter_index]; } - range_tree->i.iter_index++; + for (index = 0; index < tree->numelements; index++) { + if ((r = f(&tree->i.ranges[index], extra))) goto cleanup; + } r = 0; cleanup: - if (range_tree && r!=0) { toku_rt_invalidate_iteration(range_tree); } return r; } diff --git a/src/range_tree/log_nooverlap.c b/src/range_tree/log_nooverlap.c index c67d4aba50b..d5312ece64c 100644 --- a/src/range_tree/log_nooverlap.c +++ b/src/range_tree/log_nooverlap.c @@ -18,47 +18,16 @@ #include #include #include -#include +typedef void* OMTVALUE; +#include "../../newbrt/omt.h" + struct __toku_range_tree_local { //Logarithmic non-overlapping version only fields: - struct toku_rbt_tree* rbt; - /* - * if iter_at_beginning is TRUE, then iteration is at beginning, - * if iter_at_beginning is FALSE and iter_finger is NOT NULL, - * iteration is ongoing, - * if iter_at_beginning is FALSE and iter_finger is NULL, - * iteration has ended or in invalid state. - */ - - /* - * BOOL that says whether we are allowed to iterate. - */ - BOOL iter_is_valid; - /** - * The range we are currently at in the iterator, if it is set to NULL, that means - * the iteration is no longer valid and/or the iteration is done - * */ - struct toku_rbt_node* iter_finger; + OMT omt; }; #include -/* -Redblack tree. - -lookup (type) returns: - pointer to data (or NULL if not found) - 'elementpointer' (to be used in finger_delete, finger_predecessor, finger_successor) - 'insertpointer' (to be used in finger_insert) - -Finger usefulness: -*/ - -static inline void toku_rt_invalidate_iteration(toku_range_tree* tree) { - tree->i.iter_is_valid = FALSE; -} - -//FIRST PASS int toku_rt_create(toku_range_tree** ptree, int (*end_cmp)(const toku_point*,const toku_point*), int (*data_cmp)(const TXNID,const TXNID), @@ -75,14 +44,9 @@ int toku_rt_create(toku_range_tree** ptree, if (r!=0) { goto cleanup; } //Any local initializers go here. - r = toku_rbt_init(end_cmp, &temptree->i.rbt, user_malloc, user_free, user_realloc); + r = toku_omt_create(&temptree->i.omt); if (r!=0) { goto cleanup; } - /* - * Start range tree in invalid iteration state, toku_rt_start_scan must - * be called to start iteration - */ - toku_rt_invalidate_iteration(temptree); *ptree = temptree; r = 0; cleanup: @@ -92,36 +56,75 @@ cleanup: return r; } -//FIRST PASS +static int rt_clear_helper(OMTVALUE value, u_int32_t UU(index), void* extra) { + void (*user_free)(void*) = extra; + user_free(value); + return 0; +} + int toku_rt_close(toku_range_tree* tree) { if (!tree) { return EINVAL; } - toku_rbt_destroy(tree->i.rbt); + int r = toku_omt_iterate(tree->i.omt, rt_clear_helper, tree->free); + assert(r==0); + toku_omt_destroy(&tree->i.omt); tree->free(tree); return 0; } void toku_rt_clear(toku_range_tree* tree) { assert(tree); - toku_rbt_clear(tree->i.rbt); - toku_rt_invalidate_iteration(tree); + int r = toku_omt_iterate(tree->i.omt, rt_clear_helper, tree->free); + assert(r==0); + toku_omt_clear(tree->i.omt); tree->numelements = 0; } -/* -5- FindOverlaps - O(lg N+1) CMPs Do a lookup (<=) (out found, out elementpointer) - If found - (0+1) CMPs if overlap (if found.right >= query.left) - Increaes buffer - add found to buffer - (0) CMPs do a finger_successor(elementpointer) (out found, out elementpointer) - else - do a lookup (FIRST) (out found, out elementpointer) - O(min(k,K))CMPs while (found && found.left <= query.right - Increaes buffer - add found to buffer - (0) CMPs do a finger_successor(elementpointer) (out found, out elementpointer) -*/ +typedef struct { + int (*end_cmp)(const toku_point*,const toku_point*); + toku_interval query; +} rt_heavi_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; + return 0; +} + +typedef struct { + int (*end_cmp)(const toku_point*,const toku_point*); + toku_interval query; + u_int32_t k; + u_int32_t numfound; + toku_range_tree* rt; + toku_range** buf; + u_int32_t* buflen; +} rt_find_info; + +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; + + if (info->end_cmp(range->ends.left, info->query.right) > 0) { + r = TOKUDB_SUCCEEDED_EARLY; + goto cleanup; + } + + r = toku__rt_increase_buffer(info->rt, info->buf, info->buflen, info->numfound + 1); + if (r!=0) goto cleanup; + (*info->buf)[info->numfound++] = *range; + if (info->numfound>=info->k) { + r = TOKUDB_SUCCEEDED_EARLY; + goto cleanup; + } + r = 0; +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 r = ENOSYS; @@ -131,226 +134,136 @@ int toku_rt_find(toku_range_tree* tree, toku_interval* query, u_int32_t k, } assert(!tree->allow_overlaps); - struct toku_rbt_node* ignore_insert = NULL; - struct toku_rbt_node* succ_finger = NULL; - toku_range* data = NULL; - u_int32_t temp_numfound = 0; - /* k = 0 means return ALL. (infinity) */ if (k == 0) { k = UINT32_MAX; } - r = toku_rbt_lookup(RB_LULTEQ, query, tree->i.rbt, &ignore_insert, &succ_finger, &data); - if (r!=0) { goto cleanup; } - if (data != NULL) { - if (tree->end_cmp(data->ends.right, query->left) >= 0) { - r = toku__rt_increase_buffer(tree, buf, buflen, temp_numfound + 1); - if (r!=0) { goto cleanup; } - (*buf)[temp_numfound++] = *data; - } - if (temp_numfound < k) { - r = toku_rbt_finger_successor(&succ_finger, &data); - if (r!=0) { goto cleanup; } - } - } - else { - r = toku_rbt_lookup(RB_LUFIRST, NULL, tree->i.rbt, &ignore_insert, &succ_finger, &data); - if (r!=0) { goto cleanup; } - } + u_int32_t leftmost; + u_int32_t rightmost = toku_omt_size(tree->i.omt); + rt_heavi_extra extra; + extra.end_cmp = tree->end_cmp; + extra.query = *query; - while (temp_numfound < k && data != NULL) { - if (tree->end_cmp(data->ends.left, query->right) > 0) { break; } - r = toku__rt_increase_buffer(tree, buf, buflen, temp_numfound + 1); - if (r!=0) { goto cleanup; } - (*buf)[temp_numfound++] = *data; - r = toku_rbt_finger_successor(&succ_finger, &data); - if (r!=0) { goto cleanup; } + r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, NULL, &leftmost); + if (r==DB_NOTFOUND) { + /* Nothing overlaps. */ + *numfound = 0; + r = 0; + goto cleanup; } - - *numfound = temp_numfound; + if (r!=0) goto cleanup; + rt_find_info info; + info.end_cmp = tree->end_cmp; + info.query = *query; + info.k = k; + info.numfound = 0; + info.rt = tree; + info.buf = buf; + 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; + *numfound = info.numfound; r = 0; cleanup: return r; } -/* -1- Insert - O(lg N) CMPs We do a lookup(<=) (out elementpointer, out found, out insertpointer) - If found - If overlaps (found.right >= query.left) return error - Do a finger_successor(elementpointer) (out found2) - (0+1) CMPs if (found2 and overlaps (found2.left <= query.right) return error - else - Do a lookup(First) (out found2) - if (found2 and overlaps (found2.left <= query.right) return error - (0) CMPs Do a finger_insert(data, insertpointer) -*/ 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; } assert(!tree->allow_overlaps); - struct toku_rbt_node* insert_finger = NULL; - struct toku_rbt_node* ignore_insert = NULL; - struct toku_rbt_node* succ_finger = NULL; - toku_range* data = NULL; + u_int32_t index; + rt_heavi_extra extra; + extra.end_cmp = tree->end_cmp; + extra.query = range->ends; - r = toku_rbt_lookup(RB_LULTEQ, &range->ends, tree->i.rbt, &insert_finger, &succ_finger, &data); - if (r!=0) { goto cleanup; } - if (data != NULL) { - if (tree->end_cmp(data->ends.right, range->ends.left) >= 0) { - r = EDOM; goto cleanup; - } - r = toku_rbt_finger_successor(&succ_finger, &data); - if (r!=0) { goto cleanup; } - } - else { - r = toku_rbt_lookup(RB_LUFIRST, NULL, tree->i.rbt, &ignore_insert, &succ_finger, &data); - if (r!=0) { goto cleanup; } - } - if (data != NULL && tree->end_cmp(data->ends.left, range->ends.right) <= 0) { - r = EDOM; goto cleanup; - } - r = toku_rbt_finger_insert(range, tree->i.rbt, insert_finger); - if (r!=0) { goto cleanup; } + r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, NULL, &index); + if (r==0) { r = EDOM; goto cleanup; } + if (r!=DB_NOTFOUND) goto cleanup; + insert_range = tree->malloc(sizeof(*insert_range)); + *insert_range = *range; + if ((r = toku_omt_insert_at(tree->i.omt, insert_range, index))) goto cleanup; tree->numelements++; - /* - * invalidate iteration, because we have inserted node - */ - toku_rt_invalidate_iteration(tree); r = 0; cleanup: + if (r!=0) { + if (insert_range) tree->free(insert_range); + } return r; } -/* -2- Delete - O(lg N) CMPs We do a lookup (==). (out found, out elementpointer) - If !found return error. - (== already checks for left end point) - Data cmp is free (pointer) - (0+1) CMPs if (found.right != to_insert.right || found.data != to_delete.data), return error. - (0) CMPs Do a finger_delete(element_pointer) -*/ int toku_rt_delete(toku_range_tree* tree, toku_range* range) { -/* TODO: */ int r = ENOSYS; - if (!tree || !range) { r = EINVAL; goto cleanup; } assert(!tree->allow_overlaps); - struct toku_rbt_node* ignore_insert = NULL; - struct toku_rbt_node* delete_finger = NULL; - toku_range* data = NULL; - - r = toku_rbt_lookup(RB_LUEQUAL, &range->ends, tree->i.rbt, - &ignore_insert, &delete_finger, &data); - if (r!=0) { goto cleanup; } - if (!data || - tree->data_cmp(data->data, range->data) != 0 || - tree->end_cmp(data->ends.right, range->ends.right) != 0) { - r = EDOM; goto cleanup; + OMTVALUE value = NULL; + u_int32_t index; + rt_heavi_extra extra; + extra.end_cmp = tree->end_cmp; + extra.query = range->ends; + + r = toku_omt_find_zero(tree->i.omt, rt_heaviside, &extra, &value, &index); + if (r!=0) { r = EDOM; goto cleanup; } + assert(value); + toku_range* data = value; + if (tree->end_cmp(data->ends.left, range->ends.left) || + tree->end_cmp(data->ends.right, range->ends.right) || + tree->data_cmp(data->data, range->data)) { + r = EDOM; + goto cleanup; } + if ((r = toku_omt_delete_at(tree->i.omt, index))) goto cleanup; + tree->free(data); - r = toku_rbt_finger_delete(delete_finger, tree->i.rbt); - if (r!=0) { goto cleanup; } - - /* - * invalidate iteration, because we have deleted node - */ - toku_rt_invalidate_iteration(tree); tree->numelements--; - r = 0; + r = 0; cleanup: return r; } -/* -3- Predecessor: - O(lg N) CMPs Do a lookup(<) (out found, out elementpointer) - If !found return "not found" - (0+1) CMPs If overlaps (found.right >= query) - (0) CMPs do a finger_predecessor(elementpointer) (out found2) - If found2 return found2. - else return "not found" - else return found. -*/ -int toku_rt_predecessor (toku_range_tree* tree, toku_point* point, - toku_range* pred, BOOL* wasfound) { +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 || !pred || !wasfound || tree->allow_overlaps) { + if (!tree || !point || !neighbor || !wasfound || tree->allow_overlaps) { r = EINVAL; goto cleanup; } - - struct toku_rbt_node* ignore_insert = NULL; - struct toku_rbt_node* pred_finger = NULL; - toku_range* data = NULL; - toku_interval query; - query.left = point; - query.right = point; - - r = toku_rbt_lookup(RB_LULESS, &query, tree->i.rbt, &ignore_insert, &pred_finger, &data); - if (r!=0) { goto cleanup; } - - if (!data) { - *wasfound = FALSE; - r = 0; - goto cleanup; - } - if (tree->end_cmp(data->ends.right, point) < 0) { - *wasfound = TRUE; - *pred = *data; - r = 0; - goto cleanup; - } - r = toku_rbt_finger_predecessor(&pred_finger, &data); - if (r!=0) { goto cleanup; } - if (!data) { + u_int32_t index; + OMTVALUE value = NULL; + rt_heavi_extra extra; + extra.end_cmp = tree->end_cmp; + extra.query.left = point; + extra.query.right = point; + + assert(direction==1 || direction==-1); + r = toku_omt_find(tree->i.omt, rt_heaviside, &extra, direction, &value, &index); + if (r==DB_NOTFOUND) { *wasfound = FALSE; r = 0; goto cleanup; } + if (r!=0) goto cleanup; + assert(value); + toku_range* data = value; *wasfound = TRUE; - *pred = *data; + *neighbor = *data; r = 0; - cleanup: return r; -} - -/* -4- Successor: - O(lg N) CMPs Do a lookup (>) (out found) - If found, return found. - return "not found." -*/ -int toku_rt_successor (toku_range_tree* tree, toku_point* point, - toku_range* succ, BOOL* wasfound) { - int r = ENOSYS; - if (!tree || !point || !succ || !wasfound || tree->allow_overlaps) { - r = EINVAL; goto cleanup; - } - - struct toku_rbt_node* ignore_insert = NULL; - struct toku_rbt_node* succ_finger = NULL; - toku_range* data = NULL; - toku_interval query; - query.left = point; - query.right = point; +} - r = toku_rbt_lookup(RB_LUGREAT, &query, tree->i.rbt, &ignore_insert, &succ_finger, &data); - if (r!=0) { goto cleanup; } +int toku_rt_predecessor (toku_range_tree* tree, toku_point* point, + toku_range* pred, BOOL* wasfound) { + return rt_neightbor(tree, point, pred, wasfound, -1); +} - if (!data) { - *wasfound = FALSE; - r = 0; - goto cleanup; - } - *wasfound = TRUE; - *succ = *data; - r = 0; -cleanup: - return r; +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) { @@ -366,46 +279,20 @@ int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size) { return 0; } -void toku_rt_start_scan (toku_range_tree* range_tree) { - assert(range_tree); - range_tree->i.iter_is_valid = TRUE; - /* NULL finger means we have not gotten any yet (beginning). */ - range_tree->i.iter_finger = NULL; - return; -} +typedef struct { + int (*f)(toku_range*,void*); + void* extra; +} rt_iter_info; -int toku_rt_next (toku_range_tree* range_tree, toku_range* out_range, BOOL* elem_found) { - int r = ENOSYS; - toku_range* ret_range = NULL; - struct toku_rbt_node* ignore_insert = NULL; - - if (!range_tree || !out_range || !elem_found) { r = EINVAL; goto cleanup; } - /* Check to see if range tree is in invalid iteration state */ - if (!range_tree->i.iter_is_valid) { r = EDOM; goto cleanup; } - - if (range_tree->i.iter_finger == NULL) { - /* Initial scan */ - r = toku_rbt_lookup(RB_LUFIRST, NULL, range_tree->i.rbt, - &ignore_insert, &range_tree->i.iter_finger, &ret_range); - if (r != 0) { goto cleanup; } - } - else { - /* Repeated successor queries. */ - /* - * If there is no successor because we have arrived at the end of the iteration, - * or because of some unexpected error, ret_range will have the value of NULL, - * which we want to return to the user in such cases - */ - r = toku_rbt_finger_successor(&range_tree->i.iter_finger, &ret_range); - if (r != 0) { goto cleanup; } - } +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); +} - *elem_found = ret_range != NULL; - range_tree->i.iter_is_valid = ret_range != NULL; - if (*elem_found) { *out_range = *ret_range; } - r = 0; -cleanup: - if (r!=0) { toku_rt_invalidate_iteration(range_tree); } - return r; +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); } diff --git a/src/range_tree/rangetree.h b/src/range_tree/rangetree.h index 4ff31cf3a9d..d1f1cd1c03a 100644 --- a/src/range_tree/rangetree.h +++ b/src/range_tree/rangetree.h @@ -234,8 +234,6 @@ int toku_rt_successor(toku_range_tree* tree, toku_point* point, */ int toku_rt_get_size(toku_range_tree* tree, u_int32_t* size); -void toku_rt_start_scan (toku_range_tree* range_tree); - -int toku_rt_next (toku_range_tree* range_tree, toku_range* out_range, BOOL* elem_found); +int toku_rt_iterate(toku_range_tree* tree, int (*f)(toku_range*,void*), void* extra); #endif /* #if !defined(TOKU_RANGE_TREE_H) */ diff --git a/src/range_tree/tests/Makefile b/src/range_tree/tests/Makefile index 1d4e8ba7d60..20af6e7533f 100644 --- a/src/range_tree/tests/Makefile +++ b/src/range_tree/tests/Makefile @@ -15,7 +15,7 @@ OPTFLAGS=-O0 # GCOV_FLAGS = -fprofile-arcs -ftest-coverage CFLAGS = -W -Wall -Wextra -Werror $(OPTFLAGS) -g3 -ggdb3 $(GCOV_FLAGS) CFLAGS += -Wbad-function-cast -Wcast-align -Wconversion -Waggregate-return -CFLAGS += -Wmissing-noreturn -Wmissing-format-attribute +CFLAGS += -Wmissing-noreturn -Wmissing-format-attribute -lz CPPFLAGS += -I../ -I../../../newbrt -I../../../include @@ -87,11 +87,14 @@ endif %.tlogrun: %.tlog $(MAYBEATSIGN) $(VGRIND) ./$< $(VERBVERBOSE) -LINEAR_BINS = ../linear.o -TLOG_BINS = ../log_nooverlap.o ../tokuredblack.o -LOG_BINS = ../log.o +LINEAR_BINS = ../linear.o ../../../newbrt/newbrt.o +TLOG_BINS = ../log_nooverlap.o ../../../newbrt/newbrt.o +LOG_BINS = ../log.o ../../../newbrt/newbrt.o HEADERS=../rangetree.h ../rangetree-internal.h test.h +../../../newbrt/newbrt.o: + cd ../../../newbrt && make + %.lin: %.c $(HEADERS) $(LINEAR_BINS) $(CC) -DDIR=\"dir.$<.lin\" $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LINEAR_BINS) %.tlog: %.c $(HEADERS) $(TLOG_BINS) diff --git a/src/range_tree/tests/test.h b/src/range_tree/tests/test.h index 141304e086f..6a32914d6be 100644 --- a/src/range_tree/tests/test.h +++ b/src/range_tree/tests/test.h @@ -5,6 +5,7 @@ #include #include #include +#include "../../../newbrt/memory.h" int verbose=0; #define CKERR(r) ({ if (r!=0) fprintf(stderr, "%s:%d error %d %s\n", __FILE__, __LINE__, r, strerror(r)); assert(r==0); }) @@ -61,18 +62,6 @@ int char_cmp(const TXNID a, const TXNID b) { return x -y; } -void* toku_malloc(size_t size) { - return malloc(size); -} - -void toku_free(void* p) { - free(p); -} - -void* toku_realloc(void *ptr, size_t size) { - return realloc(ptr, size); -} - int mallocced = 0; int failon = -1; diff --git a/src/range_tree/tests/test_00000_createclose.c b/src/range_tree/tests/test_00000_createclose.c index a0f471edf63..d0f577f672c 100644 --- a/src/range_tree/tests/test_00000_createclose.c +++ b/src/range_tree/tests/test_00000_createclose.c @@ -33,7 +33,7 @@ int main(int argc, const char *argv[]) { if (allow_overlaps) continue; #endif int i; - for (i = 1; i <= 2; i++) { + for (i = 1; i <= 1; i++) { mallocced = 0; failon = i; r = toku_rt_create(&tree, int_cmp, char_cmp, allow_overlaps, diff --git a/src/range_tree/tests/test_00025_memalloc.c b/src/range_tree/tests/test_00025_memalloc.c index 7d573fe137d..c9825e2b7ef 100644 --- a/src/range_tree/tests/test_00025_memalloc.c +++ b/src/range_tree/tests/test_00025_memalloc.c @@ -64,13 +64,6 @@ void RunTest (BOOL f_overlaps_allowed) { realloc); CKERR2(r, ENOMEM); - /* Failure when allocating the tree ranges */ - malloc_cnt = 0; - malloc_cntl = 2; - r = toku_rt_create(&tree, int_cmp, char_cmp, f_overlaps_allowed, malloc_fail, free, - realloc); - CKERR2(r, ENOMEM); - } int main(int argc, const char *argv[]) { diff --git a/src/range_tree/tokuredblack.c b/src/range_tree/tokuredblack.c deleted file mode 100644 index 82f7bb35e5a..00000000000 --- a/src/range_tree/tokuredblack.c +++ /dev/null @@ -1,763 +0,0 @@ -/* - Redblack balanced tree algorithm - Copyright (C) Damian Ivereigh 2000 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. See the file COPYING for details. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Implement the red/black tree structure. It is designed to emulate -** the standard tsearch() stuff. i.e. the calling conventions are -** exactly the same -*/ - -#include -#include -#include -#include -#include -#include - -/* Dummy (sentinel) node, so that we can make X->left->up = X -** We then use this instead of NULL to mean the top or bottom -** end of the rb tree. It is a black node. -** -** Initialization of the last field in this initializer is left implicit -** because it could be of any type. We count on the compiler to zero it. -*/ -static struct toku_rbt_node toku_rbt__null; -static struct toku_rbt_node* RBNULL = &toku_rbt__null; - - -static struct toku_rbt_node *toku_rbt__alloc(struct toku_rbt_tree *rbinfo) {return (struct toku_rbt_node *) rbinfo->rb_malloc(sizeof(struct toku_rbt_node));} -static void toku_rbt__free(struct toku_rbt_tree *rbinfo, struct toku_rbt_node *x) {rbinfo->rb_free(x);} - -/* These functions are always needed */ -static void toku_rbt__left_rotate(struct toku_rbt_node **, struct toku_rbt_node *); -static void toku_rbt__right_rotate(struct toku_rbt_node **, struct toku_rbt_node *); -static struct toku_rbt_node *toku_rbt__successor(const struct toku_rbt_node *); -static struct toku_rbt_node *toku_rbt__predecessor(const struct toku_rbt_node *); -static struct toku_rbt_node *toku_rbt__traverse(int, const toku_range * , struct toku_rbt_tree *); - -/* These functions may not be needed */ -static struct toku_rbt_node* toku_rbt__insert( - const toku_range* key, - struct toku_rbt_tree* rbinfo, - struct toku_rbt_node* parent -); - -static struct toku_rbt_node *toku_rbt__lookup(int, const toku_interval * , struct toku_rbt_tree *, struct toku_rbt_node**); - -static void toku_rbt__destroy(struct toku_rbt_tree *rbinfo, struct toku_rbt_node *); - -static void toku_rbt__delete(struct toku_rbt_tree* rbinfo, struct toku_rbt_node **, struct toku_rbt_node *); -static void toku_rbt__delete_fix(struct toku_rbt_node **, struct toku_rbt_node *); - -/* -** OK here we go, the balanced tree stuff. The algorithm is the -** fairly standard red/black taken from "Introduction to Algorithms" -** by Cormen, Leiserson & Rivest. Maybe one of these days I will -** fully understand all this stuff. -** -** Basically a red/black balanced tree has the following properties:- -** 1) Every node is either red or black (colour is RED or BLACK) -** 2) A leaf (RBNULL pointer) is considered black -** 3) If a node is red then its children are black -** 4) Every path from a node to a leaf contains the same no -** of black nodes -** -** 3) & 4) above guarantee that the longest path (alternating -** red and black nodes) is only twice as long as the shortest -** path (all black nodes). Thus the tree remains fairly balanced. -*/ - -/* - * Initialise a tree. Identifies the comparison routine and any config - * data that must be sent to it when called. - * Returns a pointer to the top of the tree. - */ -int toku_rbt_init ( - int (*cmp)(const toku_point*, const toku_point*), - struct toku_rbt_tree** ptree, - void* (*user_malloc) (size_t), - void (*user_free) (void*), - void* (*user_realloc)(void*, size_t) -) -{ - struct toku_rbt_tree* temptree = NULL; - int r = ENOSYS; - - static int toku_rbt__null_is_initialized = 0; - if (!toku_rbt__null_is_initialized) { - toku_rbt__null_is_initialized = 1; - toku_rbt__null.up = &toku_rbt__null; - toku_rbt__null.left = &toku_rbt__null; - toku_rbt__null.right = &toku_rbt__null; - toku_rbt__null.colour = BLACK; - /* Key is initialized since the toku_rbt__null is static. */ - } - - if (!cmp || !ptree || !user_malloc || !user_free || !user_realloc) { - r = EINVAL; goto cleanup; } - temptree=(struct toku_rbt_tree *) user_malloc(sizeof(struct toku_rbt_tree)); - if (!temptree) { r = ENOMEM; goto cleanup; } - - temptree->rb_cmp=cmp; - temptree->rb_root=RBNULL; - temptree->rb_malloc = user_malloc; - temptree->rb_free = user_free; - temptree->rb_realloc = user_realloc; - - - *ptree = temptree; - r = 0; -cleanup: - return r; -} - -void toku_rbt_clear(struct toku_rbt_tree *rbinfo) { - assert(rbinfo); - if (rbinfo->rb_root!=RBNULL) { toku_rbt__destroy(rbinfo, rbinfo->rb_root); } - rbinfo->rb_root = RBNULL; -} - -void toku_rbt_destroy(struct toku_rbt_tree *rbinfo) { - toku_rbt_clear(rbinfo); - rbinfo->rb_free(rbinfo); -} - -int toku_rbt_finger_delete(struct toku_rbt_node* node, struct toku_rbt_tree *rbinfo) { - int r = ENOSYS; - - if (!rbinfo || !node || node == RBNULL) { r = EINVAL; goto cleanup; } - toku_rbt__delete(rbinfo, &rbinfo->rb_root, node); - r = 0; -cleanup: - return r; -} - -int toku_rbt_lookup( - int mode, - const toku_interval* key, - struct toku_rbt_tree* rbinfo, - struct toku_rbt_node** pinsert_finger, - struct toku_rbt_node** pelement_finger, - toku_range** pdata -) -{ - int r = ENOSYS; - - if (!rbinfo || !rbinfo->rb_root || !pdata || - !pinsert_finger || !pelement_finger || - ( - (mode == RB_LUFIRST || mode == RB_LULAST) != (key == NULL) - )) { - r = EINVAL; goto cleanup; } - - *pelement_finger = toku_rbt__lookup(mode, key, rbinfo, pinsert_finger); - *pdata = *pelement_finger == RBNULL ? NULL : RB_GET((*pelement_finger), key); - r = 0; -cleanup: - return r; -} - -/* --------------------------------------------------------------------- */ - -/* Search for and if not found and insert is true, will add a new -** node in. Returns a pointer to the new node, or the node found -*/ -static struct toku_rbt_node * -toku_rbt__traverse(int insert, const toku_range *key, struct toku_rbt_tree *rbinfo) -{ - struct toku_rbt_node *x,*y; - int cmp; - int found=0; - int cmpmods(); - - y=RBNULL; /* points to the parent of x */ - x=rbinfo->rb_root; - - /* walk x down the tree */ - while(x!=RBNULL && found==0) - { - y=x; - /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */ - cmp=rbinfo->rb_cmp(key->ends.left, x->key.ends.left); - - if (cmp<0) - x=x->left; - else if (cmp>0) - x=x->right; - else - found=1; - } - - if (found || !insert) - return(x); - - return toku_rbt__insert(key, rbinfo, y); -} - -static struct toku_rbt_node* toku_rbt__insert( - const toku_range* key, - struct toku_rbt_tree* rbinfo, - struct toku_rbt_node* parent -) { - struct toku_rbt_node* x; - struct toku_rbt_node* y = parent; - struct toku_rbt_node* z; - int cmp; - - if (parent == NULL) { - /* This means we have NOT actually located the right spot. - Locate it with traverse and then insert. */ - return toku_rbt__traverse(1, key, rbinfo); - } - - if ((z=toku_rbt__alloc(rbinfo))==NULL) - { - /* Whoops, no memory */ - return(RBNULL); - } - - RB_SET(z, key, key); - z->up=y; - if (y==RBNULL) - { - rbinfo->rb_root=z; - } - else - { - cmp=rbinfo->rb_cmp(z->key.ends.left, y->key.ends.left); - if (cmp<0) - y->left=z; - else - y->right=z; - } - - z->left=RBNULL; - z->right=RBNULL; - - /* colour this new node red */ - z->colour=RED; - - /* Having added a red node, we must now walk back up the tree balancing - ** it, by a series of rotations and changing of colours - */ - x=z; - - /* While we are not at the top and our parent node is red - ** N.B. Since the root node is garanteed black, then we - ** are also going to stop if we are the child of the root - */ - - while(x != rbinfo->rb_root && (x->up->colour == RED)) - { - /* if our parent is on the left side of our grandparent */ - if (x->up == x->up->up->left) - { - /* get the right side of our grandparent (uncle?) */ - y=x->up->up->right; - if (y->colour == RED) - { - /* make our parent black */ - x->up->colour = BLACK; - /* make our uncle black */ - y->colour = BLACK; - /* make our grandparent red */ - x->up->up->colour = RED; - - /* now consider our grandparent */ - x=x->up->up; - } - else - { - /* if we are on the right side of our parent */ - if (x == x->up->right) - { - /* Move up to our parent */ - x=x->up; - toku_rbt__left_rotate(&rbinfo->rb_root, x); - } - - /* make our parent black */ - x->up->colour = BLACK; - /* make our grandparent red */ - x->up->up->colour = RED; - /* right rotate our grandparent */ - toku_rbt__right_rotate(&rbinfo->rb_root, x->up->up); - } - } - else - { - /* everything here is the same as above, but - ** exchanging left for right - */ - - y=x->up->up->left; - if (y->colour == RED) - { - x->up->colour = BLACK; - y->colour = BLACK; - x->up->up->colour = RED; - - x=x->up->up; - } - else - { - if (x == x->up->left) - { - x=x->up; - toku_rbt__right_rotate(&rbinfo->rb_root, x); - } - - x->up->colour = BLACK; - x->up->up->colour = RED; - toku_rbt__left_rotate(&rbinfo->rb_root, x->up->up); - } - } - } - - /* Set the root node black */ - (rbinfo->rb_root)->colour = BLACK; - - return(z); -} - -/* Search for a key according to mode (see redblack.h) -*/ -static struct toku_rbt_node * -toku_rbt__lookup(int mode, const toku_interval *key, struct toku_rbt_tree *rbinfo, struct toku_rbt_node** pinsert_finger) -{ - struct toku_rbt_node *x,*y; - int cmp = 0; - int found=0; - - y=RBNULL; /* points to the parent of x */ - x=rbinfo->rb_root; - - if (mode==RB_LUFIRST) - { - /* Keep going left until we hit a NULL */ - while(x!=RBNULL) - { - y=x; - x=x->left; - } - - return(y); - } - else if (mode==RB_LULAST) - { - /* Keep going right until we hit a NULL */ - while(x!=RBNULL) - { - y=x; - x=x->right; - } - - return(y); - } - - /* walk x down the tree */ - while(x!=RBNULL && found==0) - { - y=x; - /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */ - cmp=rbinfo->rb_cmp(key->left, x->key.ends.left); - - - if (cmp<0) - x=x->left; - else if (cmp>0) - x=x->right; - else - found=1; - } - if (pinsert_finger) *pinsert_finger = y; - - if (found && (mode==RB_LUEQUAL || mode==RB_LUGTEQ || mode==RB_LULTEQ)) - return(x); - - if (!found && (mode==RB_LUEQUAL || mode==RB_LUNEXT || mode==RB_LUPREV)) - return(RBNULL); - - if (mode==RB_LUGTEQ || (!found && mode==RB_LUGREAT)) - { - if (cmp>0) - return(toku_rbt__successor(y)); - else - return(y); - } - - if (mode==RB_LULTEQ || (!found && mode==RB_LULESS)) - { - if (cmp<0) - return(toku_rbt__predecessor(y)); - else - return(y); - } - - if (mode==RB_LUNEXT || (found && mode==RB_LUGREAT)) - return(toku_rbt__successor(x)); - - if (mode==RB_LUPREV || (found && mode==RB_LULESS)) - return(toku_rbt__predecessor(x)); - - /* Shouldn't get here */ - return(RBNULL); -} - -/* - * Destroy all the elements blow us in the tree - * only useful as part of a complete tree destroy. - */ -static void -toku_rbt__destroy(struct toku_rbt_tree *rbinfo, struct toku_rbt_node *x) -{ - if (x!=RBNULL) - { - if (x->left!=RBNULL) - toku_rbt__destroy(rbinfo, x->left); - if (x->right!=RBNULL) - toku_rbt__destroy(rbinfo, x->right); - toku_rbt__free(rbinfo,x); - } -} - -/* -** Rotate our tree thus:- -** -** X rb_left_rotate(X)---> Y -** / \ / \ -** A Y <---rb_right_rotate(Y) X C -** / \ / \ -** B C A B -** -** N.B. This does not change the ordering. -** -** We assume that neither X or Y is NULL -*/ - -static void -toku_rbt__left_rotate(struct toku_rbt_node **rootp, struct toku_rbt_node *x) -{ - struct toku_rbt_node *y; - - assert(x!=RBNULL); - assert(x->right!=RBNULL); - - y=x->right; /* set Y */ - - /* Turn Y's left subtree into X's right subtree (move B)*/ - x->right = y->left; - - /* If B is not null, set it's parent to be X */ - if (y->left != RBNULL) - y->left->up = x; - - /* Set Y's parent to be what X's parent was */ - y->up = x->up; - - /* if X was the root */ - if (x->up == RBNULL) - { - *rootp=y; - } - else - { - /* Set X's parent's left or right pointer to be Y */ - if (x == x->up->left) - { - x->up->left=y; - } - else - { - x->up->right=y; - } - } - - /* Put X on Y's left */ - y->left=x; - - /* Set X's parent to be Y */ - x->up = y; -} - -static void -toku_rbt__right_rotate(struct toku_rbt_node **rootp, struct toku_rbt_node *y) -{ - struct toku_rbt_node *x; - - assert(y!=RBNULL); - assert(y->left!=RBNULL); - - x=y->left; /* set X */ - - /* Turn X's right subtree into Y's left subtree (move B) */ - y->left = x->right; - - /* If B is not null, set it's parent to be Y */ - if (x->right != RBNULL) - x->right->up = y; - - /* Set X's parent to be what Y's parent was */ - x->up = y->up; - - /* if Y was the root */ - if (y->up == RBNULL) - { - *rootp=x; - } - else - { - /* Set Y's parent's left or right pointer to be X */ - if (y == y->up->left) - { - y->up->left=x; - } - else - { - y->up->right=x; - } - } - - /* Put Y on X's right */ - x->right=y; - - /* Set Y's parent to be X */ - y->up = x; -} - -/* Return a pointer to the smallest key greater than x -*/ -static struct toku_rbt_node * -toku_rbt__successor(const struct toku_rbt_node *x) -{ - struct toku_rbt_node *y; - - if (x->right!=RBNULL) - { - /* If right is not NULL then go right one and - ** then keep going left until we find a node with - ** no left pointer. - */ - for (y=x->right; y->left!=RBNULL; y=y->left); - } - else - { - /* Go up the tree until we get to a node that is on the - ** left of its parent (or the root) and then return the - ** parent. - */ - y=x->up; - while(y!=RBNULL && x==y->right) - { - x=y; - y=y->up; - } - } - return(y); -} - -/* Return a pointer to the largest key smaller than x -*/ -static struct toku_rbt_node * -toku_rbt__predecessor(const struct toku_rbt_node *x) -{ - struct toku_rbt_node *y; - - if (x->left!=RBNULL) - { - /* If left is not NULL then go left one and - ** then keep going right until we find a node with - ** no right pointer. - */ - for (y=x->left; y->right!=RBNULL; y=y->right); - } - else - { - /* Go up the tree until we get to a node that is on the - ** right of its parent (or the root) and then return the - ** parent. - */ - y=x->up; - while(y!=RBNULL && x==y->left) - { - x=y; - y=y->up; - } - } - return(y); -} - -int toku_rbt_finger_predecessor(struct toku_rbt_node** pfinger, - toku_range** ppred_data) { - int r = ENOSYS; - - if (!pfinger || !*pfinger || - *pfinger == RBNULL || !ppred_data) { r = EINVAL; goto cleanup; } - *pfinger = toku_rbt__predecessor(*pfinger); - *ppred_data = (toku_range*) - ((*pfinger==RBNULL) ? NULL : RB_GET((*pfinger), key)); - r = 0; -cleanup: - return r; -} - -int toku_rbt_finger_successor(struct toku_rbt_node** pfinger, - toku_range** psucc_data) { - int r = ENOSYS; - - if (!pfinger || !*pfinger || !psucc_data) { r = EINVAL; goto cleanup; } - if (*pfinger == RBNULL) { r = EDOM; goto cleanup; } - *pfinger = toku_rbt__successor(*pfinger); - *psucc_data = (toku_range*) - ((*pfinger==RBNULL) ? NULL : RB_GET((*pfinger), key)); - r = 0; -cleanup: - return r; -} - -int toku_rbt_finger_insert( - const toku_range* key, - struct toku_rbt_tree* rbinfo, - struct toku_rbt_node* parent -) { - if (!key || !rbinfo || !parent) return EINVAL; - toku_rbt__insert(key, rbinfo, parent); - return 0; -} - -/* Delete the node z, and free up the space -*/ -static void -toku_rbt__delete(struct toku_rbt_tree* rbinfo, struct toku_rbt_node **rootp, struct toku_rbt_node *z) -{ - struct toku_rbt_node *x, *y; - - if (z->left == RBNULL || z->right == RBNULL) - y=z; - else - y=toku_rbt__successor(z); - - if (y->left != RBNULL) - x=y->left; - else - x=y->right; - - x->up = y->up; - - if (y->up == RBNULL) - { - *rootp=x; - } - else - { - if (y==y->up->left) - y->up->left = x; - else - y->up->right = x; - } - - if (y!=z) - { - RB_SET(z, key, RB_GET(y, key)); - } - - if (y->colour == BLACK) - toku_rbt__delete_fix(rootp, x); - - toku_rbt__free(rbinfo,y); -} - -/* Restore the reb-black properties after a delete */ -static void -toku_rbt__delete_fix(struct toku_rbt_node **rootp, struct toku_rbt_node *x) -{ - struct toku_rbt_node *w; - - while (x!=*rootp && x->colour==BLACK) - { - if (x==x->up->left) - { - w=x->up->right; - if (w->colour==RED) - { - w->colour=BLACK; - x->up->colour=RED; - toku_rbt__left_rotate(rootp, x->up); - w=x->up->right; - } - - if (w->left->colour==BLACK && w->right->colour==BLACK) - { - w->colour=RED; - x=x->up; - } - else - { - if (w->right->colour == BLACK) - { - w->left->colour=BLACK; - w->colour=RED; - toku_rbt__right_rotate(rootp, w); - w=x->up->right; - } - - - w->colour=x->up->colour; - x->up->colour = BLACK; - w->right->colour = BLACK; - toku_rbt__left_rotate(rootp, x->up); - x=*rootp; - } - } - else - { - w=x->up->left; - if (w->colour==RED) - { - w->colour=BLACK; - x->up->colour=RED; - toku_rbt__right_rotate(rootp, x->up); - w=x->up->left; - } - - if (w->right->colour==BLACK && w->left->colour==BLACK) - { - w->colour=RED; - x=x->up; - } - else - { - if (w->left->colour == BLACK) - { - w->right->colour=BLACK; - w->colour=RED; - toku_rbt__left_rotate(rootp, w); - w=x->up->left; - } - - w->colour=x->up->colour; - x->up->colour = BLACK; - w->left->colour = BLACK; - toku_rbt__right_rotate(rootp, x->up); - x=*rootp; - } - } - } - - x->colour=BLACK; -} diff --git a/src/range_tree/tokuredblack.h b/src/range_tree/tokuredblack.h deleted file mode 100644 index 49794b0e621..00000000000 --- a/src/range_tree/tokuredblack.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - Redblack balanced tree algorithm - Copyright (C) Damian Ivereigh 2000 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. See the file COPYING for details. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef TOKU_REDBLACK_H -#define TOKU_REDBLACK_H - -#include -#define RB_INLINE - -/* Modes for rblookup */ -typedef enum { - RB_NONE = -1, /* None of those below */ - RB_LUEQUAL = 0, /* Only exact match */ - RB_LUGTEQ = 1, /* Exact match or greater */ - RB_LULTEQ = 2, /* Exact match or less */ - RB_LULESS = 3, /* Less than key (not equal to) */ - RB_LUGREAT = 4, /* Greater than key (not equal to) */ - RB_LUNEXT = 5, /* Next key after current */ - RB_LUPREV = 6, /* Prev key before current */ - RB_LUFIRST = 7, /* First key in index */ - RB_LULAST = 8 /* Last key in index */ -} toku_rbt_look_mode; - -struct toku_rbt_lists { -const struct toku_rbt_node *rootp; -const struct toku_rbt_node *nextp; -}; - -struct toku_rbt_tree { - int (*rb_cmp)(const toku_point*, const toku_point*); - struct toku_rbt_node *rb_root; - void* (*rb_malloc) (size_t); - void (*rb_free) (void*); - void* (*rb_realloc)(void*, size_t); -}; - -int toku_rbt_init ( - int (*cmp)(const toku_point*, const toku_point*), - struct toku_rbt_tree** ptree, - void* (*user_malloc) (size_t), - void (*user_free) (void*), - void* (*user_realloc)(void*, size_t) -); - -/* Sets *pdata to NULL if not found. (unless error) */ -int toku_rbt_lookup( - int mode, - const toku_interval* key, - struct toku_rbt_tree* rbinfo, - struct toku_rbt_node** pinsert_finger, - struct toku_rbt_node** pelement_finger, - toku_range** pdata -); - -int toku_rbt_finger_insert( - const toku_range* key, - struct toku_rbt_tree* rbinfo, - struct toku_rbt_node* parent -); - -int toku_rbt_finger_delete(struct toku_rbt_node* node, struct toku_rbt_tree *rbinfo); - -int toku_rbt_finger_predecessor(struct toku_rbt_node** pfinger, toku_range** ppred_data); - -int toku_rbt_finger_successor(struct toku_rbt_node** pfinger, toku_range** psucc_data); - -void toku_rbt_destroy(struct toku_rbt_tree *); - -void toku_rbt_clear(struct toku_rbt_tree *); - -enum nodecolour { BLACK, RED }; - -struct toku_rbt_node -{ - struct toku_rbt_node *left; /* Left down */ - struct toku_rbt_node *right; /* Right down */ - struct toku_rbt_node *up; /* Up */ - enum nodecolour colour; /* Node colour */ -#ifdef RB_INLINE - toku_range key; /* User's key (and data) */ -#define RB_GET(x,y) &x->y -#define RB_SET(x,y,v) x->y = *(v) -#else - const toku_range *key; /* Pointer to user's key (and data) */ -#define RB_GET(x,y) x->y -#define RB_SET(x,y,v) x->y = v -#endif /* RB_INLINE */ -}; - -#endif /* TOKU_REDBLACK_H */