Commit 8a71d45b authored by Yoni Fogel's avatar Yoni Fogel

Closes #777

omt used to replaced libredblack


git-svn-id: file:///svn/tokudb@3986 c7de825b-a66e-492c-adef-691d508d4ae1
parent 94a483dd
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -31,6 +31,7 @@ void print_db_notices (void) {
enum {
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
......
......@@ -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
......
......@@ -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_size<n ||
(omt->tmparray_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_nodes<n) ||
(omt->node_capacity<n)) {
if (choice==MAYBE_REBUILD) {
......@@ -173,6 +173,7 @@ static inline int maybe_resize_and_rebuild(OMT omt, u_int32_t n, enum build_choi
omt->nodes = 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_root<right && (r=f(n->value, idx_root, v))) return r;
if (idx_root+1<right) return iterate_internal(omt, left, right, n->right, 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 @@ int toku_omt_merge(OMT leftomt, OMT rightomt, OMT *newomtp) {
return r;
}
void toku_omt_clear(OMT omt) {
omt->free_idx = 0;
omt->root = NODE_NULL;
}
......@@ -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 */
......@@ -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 @@ static int toku__lt_escalate_read_locks_in_interval(toku_lock_tree* tree,
return r;
}
typedef struct {
toku_lock_tree* lt;
toku_range_tree* border;
toku_interval* escalate_interval;
TXNID txn;
} escalate_info;
//TODO: Whenever comparing TXNIDs use the comparison function INSTEAD of just '!= or =='
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 =='
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 @@ static int toku__lt_escalate_read_locks(toku_lock_tree* tree, TXNID txn) {
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;
assert(tree->borderwrite);
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; }
}
if ((r = toku_rt_iterate(tree->borderwrite, escalate_write_locks_helper, tree))) goto cleanup;
r = 0;
cleanup:
return r;
......
......@@ -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
......
......@@ -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
......@@ -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 <rangetree-internal.h>
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;
}
......@@ -18,47 +18,16 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <tokuredblack.h>
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 <rangetree-internal.h>
/*
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 @@ int toku_rt_create(toku_range_tree** ptree,
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;
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_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 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; }
if (!data) {
*wasfound = FALSE;
r = 0;
goto cleanup;
}
*wasfound = TRUE;
*succ = *data;
r = 0;
cleanup:
return r;
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);
}
......@@ -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) */
......@@ -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)
......
......@@ -5,6 +5,7 @@
#include <assert.h>
#include <rangetree.h>
#include <errno.h>
#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;
......
......@@ -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,
......
......@@ -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[]) {
......
/*
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 <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <tokuredblack.h>
#include <assert.h>
/* 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;
}
/*
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 <rangetree.h>
#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 */
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