|
|
|
@ -2,36 +2,14 @@ |
|
|
|
|
|
|
|
#include <errno.h> |
|
|
|
#include <sys/types.h> |
|
|
|
#include <stdint.h> |
|
|
|
|
|
|
|
typedef void *OMTVALUE; |
|
|
|
#include "omt.h" |
|
|
|
#include "omt-internal.h" |
|
|
|
#include "../newbrt/memory.h" |
|
|
|
#include "../newbrt/toku_assert.h" |
|
|
|
#include "../include/db.h" |
|
|
|
#include "../newbrt/brttypes.h" |
|
|
|
|
|
|
|
typedef u_int32_t node_idx; |
|
|
|
static const node_idx NODE_NULL = UINT32_MAX; |
|
|
|
|
|
|
|
typedef struct omt_node *OMT_NODE; |
|
|
|
struct omt_node { |
|
|
|
u_int32_t weight; /* Size of subtree rooted at this node (including this one). */ |
|
|
|
node_idx left; /* Index of left subtree. */ |
|
|
|
node_idx right; /* Index of right subtree. */ |
|
|
|
OMTVALUE value; /* The value stored in the node. */ |
|
|
|
}; |
|
|
|
|
|
|
|
struct omt { |
|
|
|
node_idx root; |
|
|
|
|
|
|
|
u_int32_t node_capacity; |
|
|
|
OMT_NODE nodes; |
|
|
|
node_idx free_idx; |
|
|
|
|
|
|
|
u_int32_t tmparray_size; |
|
|
|
node_idx* tmparray; |
|
|
|
}; |
|
|
|
|
|
|
|
static int omt_create_internal(OMT *omtp, u_int32_t num_starting_nodes) { |
|
|
|
if (num_starting_nodes < 2) num_starting_nodes = 2; |
|
|
|
@ -339,21 +317,60 @@ int toku_omt_delete_at(OMT omt, u_int32_t index) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static inline void fetch_internal(OMT V, node_idx idx, u_int32_t i, OMTVALUE *v) { |
|
|
|
static int omtcursor_stack_push(OMTCURSOR c, node_idx idx) { |
|
|
|
if (c->max_pathlen-1<=c->pathlen) { |
|
|
|
//Increase max_pathlen |
|
|
|
u_int32_t new_max = c->max_pathlen*2; |
|
|
|
node_idx *tmp_path = toku_realloc(c->path, new_max*sizeof(*c->path)); |
|
|
|
if (tmp_path==NULL) return errno; |
|
|
|
c->path = tmp_path; |
|
|
|
c->max_pathlen = new_max; |
|
|
|
} |
|
|
|
c->path[c->pathlen++] = idx; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static node_idx omtcursor_stack_peek(OMTCURSOR c) { |
|
|
|
return c->path[c->pathlen-1]; |
|
|
|
} |
|
|
|
|
|
|
|
static node_idx omtcursor_stack_pop(OMTCURSOR c) { |
|
|
|
assert(c->pathlen); |
|
|
|
node_idx value = omtcursor_stack_peek(c);; |
|
|
|
c->pathlen--; |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
static void omtcursor_associate(OMTCURSOR c, OMT omt) { |
|
|
|
c->omt = omt; |
|
|
|
c->pathlen = 0; |
|
|
|
} |
|
|
|
|
|
|
|
static inline int fetch_internal(OMT V, node_idx idx, u_int32_t i, OMTVALUE *v, OMTCURSOR c) { |
|
|
|
int r; |
|
|
|
// Add the current index to the cursor path |
|
|
|
if (c!=NULL && (r=omtcursor_stack_push(c, idx))) return r; |
|
|
|
|
|
|
|
/* Find the node corresponding to index idx */ |
|
|
|
OMT_NODE n = V->nodes+idx; |
|
|
|
|
|
|
|
/* Visit recursively the appropriate sub-tree */ |
|
|
|
if (i < nweight(V, n->left)) { |
|
|
|
fetch_internal(V, n->left, i, v); |
|
|
|
return fetch_internal(V, n->left, i, v, c); |
|
|
|
} else if (i == nweight(V, n->left)) { |
|
|
|
*v = n->value; |
|
|
|
} else { |
|
|
|
fetch_internal(V, n->right, i-nweight(V, n->left)-1, v); |
|
|
|
return fetch_internal(V, n->right, i-nweight(V, n->left)-1, v, c); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int toku_omt_fetch(OMT V, u_int32_t i, OMTVALUE *v) { |
|
|
|
int toku_omt_fetch(OMT V, u_int32_t i, OMTVALUE *v, OMTCURSOR c) { |
|
|
|
if (i>=nweight(V, V->root)) return ERANGE; |
|
|
|
fetch_internal(V, V->root, i, v); |
|
|
|
return 0; |
|
|
|
if (c!=NULL) omtcursor_associate(c, V); |
|
|
|
int r = fetch_internal(V, V->root, i, v, c); |
|
|
|
if (c!=NULL && r!=0) toku_omt_cursor_invalidate(c); |
|
|
|
return r; |
|
|
|
} |
|
|
|
|
|
|
|
static inline int iterate_internal(OMT omt, u_int32_t left, u_int32_t right, |
|
|
|
@ -381,7 +398,7 @@ int toku_omt_insert(OMT omt, OMTVALUE value, int(*h)(OMTVALUE, void*v), void *v, |
|
|
|
int r; |
|
|
|
u_int32_t idx; |
|
|
|
|
|
|
|
r = toku_omt_find_zero(omt, h, v, NULL, &idx); |
|
|
|
r = toku_omt_find_zero(omt, h, v, NULL, &idx, NULL); |
|
|
|
if (r==0) { |
|
|
|
if (index) *index = idx; |
|
|
|
return DB_KEYEXIST; |
|
|
|
@ -394,80 +411,131 @@ int toku_omt_insert(OMT omt, OMTVALUE value, int(*h)(OMTVALUE, void*v), void *v, |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static inline int find_internal_zero(OMT omt, node_idx n_idx, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, u_int32_t *index) { |
|
|
|
static inline int find_internal_zero(OMT omt, node_idx n_idx, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, u_int32_t *index, OMTCURSOR c) { |
|
|
|
int r; |
|
|
|
if (n_idx==NODE_NULL) { |
|
|
|
if (index!=NULL) (*index)=0; |
|
|
|
*index=0; |
|
|
|
return DB_NOTFOUND; |
|
|
|
} |
|
|
|
// Add the current index to the cursor path |
|
|
|
if (c!=NULL && (r=omtcursor_stack_push(c, n_idx))) return r; |
|
|
|
OMT_NODE n = omt->nodes+n_idx; |
|
|
|
int hv = h(n->value, extra); |
|
|
|
if (hv<0) { |
|
|
|
int r = find_internal_zero(omt, n->right, h, extra, value, index); |
|
|
|
if (index!=NULL) (*index) += nweight(omt, n->left)+1; |
|
|
|
r = find_internal_zero(omt, n->right, h, extra, value, index, c); |
|
|
|
*index += nweight(omt, n->left)+1; |
|
|
|
return r; |
|
|
|
} else if (hv>0) { |
|
|
|
return find_internal_zero(omt, n->left, h, extra, value, index); |
|
|
|
r = find_internal_zero(omt, n->left, h, extra, value, index, c); |
|
|
|
if (c!=NULL && r==DB_NOTFOUND && *index==nweight(omt, n->left)) { |
|
|
|
//Truncate the saved cursor path at n_idx. |
|
|
|
while (omtcursor_stack_peek(c)!=n_idx) omtcursor_stack_pop(c); |
|
|
|
} |
|
|
|
return r; |
|
|
|
} else { |
|
|
|
int r = find_internal_zero(omt, n->left, h, extra, value, index); |
|
|
|
r = find_internal_zero(omt, n->left, h, extra, value, index, c); |
|
|
|
if (r==DB_NOTFOUND) { |
|
|
|
if (index!=NULL) *index = nweight(omt, n->left); |
|
|
|
if (value!=NULL) *value = n->value; |
|
|
|
*index = nweight(omt, n->left); |
|
|
|
*value = n->value; |
|
|
|
if (c!=NULL) { |
|
|
|
//Truncate the saved cursor path at n_idx. |
|
|
|
while (omtcursor_stack_peek(c)!=n_idx) omtcursor_stack_pop(c); |
|
|
|
} |
|
|
|
r = 0; |
|
|
|
} |
|
|
|
return r; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int toku_omt_find_zero(OMT V, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, u_int32_t *index) { |
|
|
|
return find_internal_zero(V, V->root, h, extra, value, index); |
|
|
|
int toku_omt_find_zero(OMT V, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, u_int32_t *index, OMTCURSOR c) { |
|
|
|
if (c!=NULL) omtcursor_associate(c, V); |
|
|
|
u_int32_t idx_tmp; |
|
|
|
OMTVALUE val_tmp; |
|
|
|
int r = find_internal_zero(V, V->root, h, extra, &val_tmp, &idx_tmp, c); |
|
|
|
if (c!=NULL && ( (r!=0 && r!=DB_NOTFOUND) || |
|
|
|
idx_tmp==nweight(V, V->root))) { |
|
|
|
toku_omt_cursor_invalidate(c); |
|
|
|
} |
|
|
|
if (c==NULL || r==0 || r==DB_NOTFOUND) { |
|
|
|
if (index!=NULL) *index = idx_tmp; |
|
|
|
if (value!=NULL && r==0) *value = val_tmp; |
|
|
|
} |
|
|
|
return r; |
|
|
|
} |
|
|
|
|
|
|
|
// If direction <0 then find the largest i such that h(V_i,extra)<0. |
|
|
|
static inline int find_internal_minus(OMT omt, node_idx n_idx, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, u_int32_t *index) { |
|
|
|
static inline int find_internal_minus(OMT omt, node_idx n_idx, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, u_int32_t *index, OMTCURSOR c) { |
|
|
|
int r; |
|
|
|
if (n_idx==NODE_NULL) return DB_NOTFOUND; |
|
|
|
// Add the current index to the cursor path |
|
|
|
if (c!=NULL && (r=omtcursor_stack_push(c, n_idx))) return r; |
|
|
|
OMT_NODE n = omt->nodes+n_idx; |
|
|
|
int hv = h(n->value, extra); |
|
|
|
if (hv<0) { |
|
|
|
int r = find_internal_minus(omt, n->right, h, extra, value, index); |
|
|
|
if (r==0 && index!=NULL) (*index) += nweight(omt, n->left)+1; |
|
|
|
r = find_internal_minus(omt, n->right, h, extra, value, index, c); |
|
|
|
if (r==0) (*index) += nweight(omt, n->left)+1; |
|
|
|
else if (r==DB_NOTFOUND) { |
|
|
|
if (index!=NULL) *index = nweight(omt, n->left); |
|
|
|
if (value!=NULL) *value = n->value; |
|
|
|
*index = nweight(omt, n->left); |
|
|
|
*value = n->value; |
|
|
|
if (c!=NULL) { |
|
|
|
//Truncate the saved cursor path at n_idx. |
|
|
|
while (omtcursor_stack_peek(c)!=n_idx) omtcursor_stack_pop(c); |
|
|
|
} |
|
|
|
r = 0; |
|
|
|
} |
|
|
|
return r; |
|
|
|
} else { |
|
|
|
return find_internal_minus(omt, n->left, h, extra, value, index); |
|
|
|
return find_internal_minus(omt, n->left, h, extra, value, index, c); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// If direction >0 then find the smallest i such that h(V_i,extra)>0. |
|
|
|
static inline int find_internal_plus(OMT omt, node_idx n_idx, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, u_int32_t *index) { |
|
|
|
static inline int find_internal_plus(OMT omt, node_idx n_idx, int (*h)(OMTVALUE, void*extra), void*extra, OMTVALUE *value, u_int32_t *index, OMTCURSOR c) { |
|
|
|
int r; |
|
|
|
if (n_idx==NODE_NULL) return DB_NOTFOUND; |
|
|
|
// Add the current index to the cursor path |
|
|
|
if (c!=NULL && (r=omtcursor_stack_push(c, n_idx))) return r; |
|
|
|
OMT_NODE n = omt->nodes+n_idx; |
|
|
|
int hv = h(n->value, extra); |
|
|
|
if (hv>0) { |
|
|
|
int r = find_internal_plus(omt, n->left, h, extra, value, index); |
|
|
|
r = find_internal_plus(omt, n->left, h, extra, value, index, c); |
|
|
|
if (r==DB_NOTFOUND) { |
|
|
|
if (index!=NULL) *index = nweight(omt, n->left); |
|
|
|
if (value!=NULL) *value = n->value; |
|
|
|
*index = nweight(omt, n->left); |
|
|
|
*value = n->value; |
|
|
|
if (c!=NULL) { |
|
|
|
//Truncate the saved cursor path at n_idx. |
|
|
|
while (omtcursor_stack_peek(c)!=n_idx) omtcursor_stack_pop(c); |
|
|
|
} |
|
|
|
r = 0; |
|
|
|
} |
|
|
|
return r; |
|
|
|
} else { |
|
|
|
int r = find_internal_plus(omt, n->right, h, extra, value, index); |
|
|
|
if (r==0 && index!=NULL) (*index) += nweight(omt, n->left)+1; |
|
|
|
r = find_internal_plus(omt, n->right, h, extra, value, index, c); |
|
|
|
if (r==0) (*index) += nweight(omt, n->left)+1; |
|
|
|
return r; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int toku_omt_find(OMT V, int (*h)(OMTVALUE, void*extra), void*extra, int direction, OMTVALUE *value, u_int32_t *index) { |
|
|
|
int toku_omt_find(OMT V, int (*h)(OMTVALUE, void*extra), void*extra, int direction, OMTVALUE *value, u_int32_t *index, OMTCURSOR c) { |
|
|
|
if (direction==0) { |
|
|
|
abort(); |
|
|
|
} else if (direction<0) { |
|
|
|
return find_internal_minus(V, V->root, h, extra, value, index); |
|
|
|
} else { |
|
|
|
return find_internal_plus( V, V->root, h, extra, value, index); |
|
|
|
} |
|
|
|
else { |
|
|
|
int r; |
|
|
|
u_int32_t idx_tmp; |
|
|
|
OMTVALUE val_tmp; |
|
|
|
if (c!=NULL) omtcursor_associate(c, V); |
|
|
|
if (direction<0) { |
|
|
|
r = find_internal_minus(V, V->root, h, extra, &val_tmp, &idx_tmp, c); |
|
|
|
} else { |
|
|
|
r = find_internal_plus( V, V->root, h, extra, &val_tmp, &idx_tmp, c); |
|
|
|
} |
|
|
|
if (c!=NULL && r!=0) toku_omt_cursor_invalidate(c); |
|
|
|
if (r==0) { |
|
|
|
if (index!=NULL) *index = idx_tmp; |
|
|
|
if (value!=NULL) *value = val_tmp; |
|
|
|
} |
|
|
|
return r; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -524,6 +592,114 @@ void toku_omt_clear(OMT omt) { |
|
|
|
omt->root = NODE_NULL; |
|
|
|
} |
|
|
|
|
|
|
|
unsigned long toku_omt_memory_size (OMT omt) { |
|
|
|
int toku_omt_cursor_create(OMTCURSOR *p) { |
|
|
|
OMTCURSOR MALLOC(result); |
|
|
|
if (result==NULL) return errno; |
|
|
|
result->max_pathlen = TOKU_OMTCURSOR_INITIAL_SIZE; |
|
|
|
result->pathlen = 0; |
|
|
|
MALLOC_N(result->max_pathlen, result->path); |
|
|
|
if (result->path==NULL) { |
|
|
|
toku_free(result); |
|
|
|
return errno; |
|
|
|
} |
|
|
|
result->omt = NULL; |
|
|
|
*p = result; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void toku_omt_cursor_destroy(OMTCURSOR *p) { |
|
|
|
OMTCURSOR c=*p; |
|
|
|
toku_free(c->path); |
|
|
|
toku_free(c); |
|
|
|
*p = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
int toku_omt_cursor_is_valid(OMTCURSOR c) { |
|
|
|
return c->pathlen>0 && c->omt!=NULL; |
|
|
|
} |
|
|
|
|
|
|
|
void toku_omt_cursor_invalidate(OMTCURSOR c) { |
|
|
|
c->pathlen = 0; |
|
|
|
c->omt=NULL; |
|
|
|
} |
|
|
|
|
|
|
|
static void omtcursor_current_internal(OMTCURSOR c, OMTVALUE *v) { |
|
|
|
*v = c->omt->nodes[omtcursor_stack_peek(c)].value; |
|
|
|
} |
|
|
|
|
|
|
|
int toku_omt_cursor_current(OMTCURSOR c, OMTVALUE *v) { |
|
|
|
if (!toku_omt_cursor_is_valid(c)) return EINVAL; |
|
|
|
omtcursor_current_internal(c, v); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int omtcursor_next_internal(OMTCURSOR c) { |
|
|
|
if (!toku_omt_cursor_is_valid(c)) return EINVAL; |
|
|
|
OMT_NODE current = c->omt->nodes+omtcursor_stack_peek(c); |
|
|
|
if (current->right!=NODE_NULL) { |
|
|
|
//Enter into subtree |
|
|
|
if (omtcursor_stack_push(c, current->right)) goto invalidate; |
|
|
|
current = c->omt->nodes+current->right; |
|
|
|
while (current->left!=NODE_NULL) { |
|
|
|
if (omtcursor_stack_push(c, current->left)) goto invalidate; |
|
|
|
current = c->omt->nodes+current->left; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
else { |
|
|
|
//Pop the stack till we remove a left child. |
|
|
|
while (c->pathlen>=2) { |
|
|
|
node_idx child_idx = omtcursor_stack_pop(c); |
|
|
|
node_idx parent_idx = omtcursor_stack_peek(c); |
|
|
|
if (c->omt->nodes[parent_idx].left==child_idx) return 0; |
|
|
|
} |
|
|
|
goto invalidate; |
|
|
|
} |
|
|
|
invalidate: |
|
|
|
toku_omt_cursor_invalidate(c); |
|
|
|
return EINVAL; |
|
|
|
} |
|
|
|
|
|
|
|
int toku_omt_cursor_next(OMTCURSOR c, OMTVALUE *v) { |
|
|
|
if (omtcursor_next_internal(c)) return EINVAL; |
|
|
|
omtcursor_current_internal(c, v); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int omtcursor_prev_internal(OMTCURSOR c) { |
|
|
|
if (!toku_omt_cursor_is_valid(c)) return EINVAL; |
|
|
|
OMT_NODE current = c->omt->nodes+omtcursor_stack_peek(c); |
|
|
|
if (current->left!=NODE_NULL) { |
|
|
|
//Enter into subtree |
|
|
|
if (omtcursor_stack_push(c, current->left)) goto invalidate; |
|
|
|
current = c->omt->nodes+current->left; |
|
|
|
while (current->right!=NODE_NULL) { |
|
|
|
if (omtcursor_stack_push(c, current->right)) goto invalidate; |
|
|
|
current = c->omt->nodes+current->right; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
else { |
|
|
|
//Pop the stack till we remove a right child. |
|
|
|
while (c->pathlen>=2) { |
|
|
|
node_idx child_idx = omtcursor_stack_pop(c); |
|
|
|
node_idx parent_idx = omtcursor_stack_peek(c); |
|
|
|
if (c->omt->nodes[parent_idx].right==child_idx) return 0; |
|
|
|
} |
|
|
|
goto invalidate; |
|
|
|
} |
|
|
|
invalidate: |
|
|
|
toku_omt_cursor_invalidate(c); |
|
|
|
return EINVAL; |
|
|
|
} |
|
|
|
|
|
|
|
int toku_omt_cursor_prev(OMTCURSOR c, OMTVALUE *v) { |
|
|
|
if (omtcursor_prev_internal(c)) return EINVAL; |
|
|
|
omtcursor_current_internal(c, v); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
size_t toku_omt_memory_size (OMT omt) { |
|
|
|
return sizeof(*omt)+omt->node_capacity*sizeof(omt->nodes[0]) + omt->tmparray_size*sizeof(omt->tmparray[0]); |
|
|
|
} |
|
|
|
|