Commit da523d46 authored by Yoni Fogel's avatar Yoni Fogel

addresses #918

Merged current progress into trunk

git-svn-id: file:///svn/tokudb@4581 c7de825b-a66e-492c-adef-691d508d4ae1
parent b6676afe
...@@ -25,7 +25,6 @@ struct omt_node { ...@@ -25,7 +25,6 @@ struct omt_node {
struct omt_array { struct omt_array {
u_int32_t capacity;
u_int32_t start_idx; u_int32_t start_idx;
u_int32_t num_values; u_int32_t num_values;
OMTVALUE *values; OMTVALUE *values;
...@@ -34,16 +33,13 @@ struct omt_array { ...@@ -34,16 +33,13 @@ struct omt_array {
struct omt_tree { struct omt_tree {
node_idx root; node_idx root;
u_int32_t node_capacity;
OMT_NODE nodes; OMT_NODE nodes;
node_idx free_idx; node_idx free_idx;
u_int32_t tmparray_size;
node_idx* tmparray;
}; };
struct omt { struct omt {
BOOL is_array; BOOL is_array;
u_int32_t capacity;
union { union {
struct omt_array a; struct omt_array a;
struct omt_tree t; struct omt_tree t;
...@@ -62,10 +58,10 @@ static int omt_create_internal(OMT *omtp, u_int32_t num_starting_nodes) { ...@@ -62,10 +58,10 @@ static int omt_create_internal(OMT *omtp, u_int32_t num_starting_nodes) {
OMT MALLOC(result); OMT MALLOC(result);
if (result==NULL) return errno; if (result==NULL) return errno;
result->is_array = TRUE; result->is_array = TRUE;
result->capacity = 2*num_starting_nodes;
result->i.a.num_values = 0; result->i.a.num_values = 0;
result->i.a.start_idx = 0; result->i.a.start_idx = 0;
result->i.a.capacity = 2*num_starting_nodes; MALLOC_N(result->capacity, result->i.a.values);
MALLOC_N(result->i.a.capacity, result->i.a.values);
if (result->i.a.values==NULL) { if (result->i.a.values==NULL) {
toku_free(result); toku_free(result);
return errno; return errno;
...@@ -142,12 +138,12 @@ static inline u_int32_t omt_size(OMT omt) { ...@@ -142,12 +138,12 @@ static inline u_int32_t omt_size(OMT omt) {
} }
static inline node_idx omt_node_malloc(OMT omt) { static inline node_idx omt_node_malloc(OMT omt) {
assert(omt->i.t.free_idx < omt->i.t.node_capacity); assert(omt->i.t.free_idx < omt->capacity);
return omt->i.t.free_idx++; return omt->i.t.free_idx++;
} }
static inline void omt_node_free(OMT omt, node_idx idx) { static inline void omt_node_free(OMT omt, node_idx idx) {
assert(idx < omt->i.t.node_capacity); assert(idx < omt->capacity);
} }
static inline void fill_array_with_subtree_values(OMT omt, OMTVALUE *array, node_idx tree_idx) { static inline void fill_array_with_subtree_values(OMT omt, OMTVALUE *array, node_idx tree_idx) {
...@@ -184,15 +180,15 @@ static inline void rebuild_from_sorted_array(OMT omt, node_idx *n_idxp, ...@@ -184,15 +180,15 @@ static inline void rebuild_from_sorted_array(OMT omt, node_idx *n_idxp,
static inline int maybe_resize_array(OMT omt, u_int32_t n) { static inline int maybe_resize_array(OMT omt, u_int32_t n) {
u_int32_t new_size = n<=2 ? 4 : 2*n; u_int32_t new_size = n<=2 ? 4 : 2*n;
u_int32_t room = omt->i.a.capacity - omt->i.a.start_idx; u_int32_t room = omt->capacity - omt->i.a.start_idx;
if (room<n || omt->i.a.capacity/2>=new_size) { if (room<n || omt->capacity/2>=new_size) {
OMTVALUE *MALLOC_N(new_size, tmp_values); OMTVALUE *MALLOC_N(new_size, tmp_values);
if (tmp_values==NULL) return errno; if (tmp_values==NULL) return errno;
memcpy(tmp_values, omt->i.a.values+omt->i.a.start_idx, memcpy(tmp_values, omt->i.a.values+omt->i.a.start_idx,
omt->i.a.num_values*sizeof(*tmp_values)); omt->i.a.num_values*sizeof(*tmp_values));
omt->i.a.start_idx = 0; omt->i.a.start_idx = 0;
omt->i.a.capacity = new_size; omt->capacity = new_size;
toku_free(omt->i.a.values); toku_free(omt->i.a.values);
omt->i.a.values = tmp_values; omt->i.a.values = tmp_values;
} }
...@@ -204,24 +200,15 @@ static int omt_convert_to_tree(OMT omt) { ...@@ -204,24 +200,15 @@ static int omt_convert_to_tree(OMT omt) {
u_int32_t num_nodes = omt_size(omt); u_int32_t num_nodes = omt_size(omt);
u_int32_t new_size = num_nodes*2; u_int32_t new_size = num_nodes*2;
node_idx *new_tmparray = NULL; OMT_NODE MALLOC_N(new_size, new_nodes);
OMT_NODE new_nodes = NULL;
MALLOC_N(new_size, new_nodes);
if (new_nodes==NULL) return errno; if (new_nodes==NULL) return errno;
MALLOC_N(new_size, new_tmparray);
if (new_tmparray==NULL) {
toku_free(new_nodes);
return errno;
}
OMTVALUE *values = omt->i.a.values; OMTVALUE *values = omt->i.a.values;
OMTVALUE *tmp_values = values + omt->i.a.start_idx; OMTVALUE *tmp_values = values + omt->i.a.start_idx;
omt->is_array = FALSE; omt->is_array = FALSE;
omt->i.t.nodes = new_nodes; omt->i.t.nodes = new_nodes;
omt->i.t.node_capacity = new_size; omt->capacity = new_size;
omt->i.t.free_idx = 0; /* Allocating from mempool starts over. */ omt->i.t.free_idx = 0; /* Allocating from mempool starts over. */
omt->i.t.root = NODE_NULL; omt->i.t.root = NODE_NULL;
omt->i.t.tmparray = new_tmparray;
omt->i.t.tmparray_size = new_size;
rebuild_from_sorted_array(omt, &omt->i.t.root, tmp_values, num_nodes); rebuild_from_sorted_array(omt, &omt->i.t.root, tmp_values, num_nodes);
toku_free(values); toku_free(values);
return 0; return 0;
...@@ -234,17 +221,16 @@ static int omt_convert_to_array(OMT omt) { ...@@ -234,17 +221,16 @@ static int omt_convert_to_array(OMT omt) {
OMTVALUE *MALLOC_N(capacity, tmp_values); OMTVALUE *MALLOC_N(capacity, tmp_values);
if (tmp_values==NULL) return errno; if (tmp_values==NULL) return errno;
fill_array_with_subtree_values(omt, tmp_values, omt->i.t.root); fill_array_with_subtree_values(omt, tmp_values, omt->i.t.root);
toku_free(omt->i.t.tmparray);
toku_free(omt->i.t.nodes); toku_free(omt->i.t.nodes);
omt->is_array = TRUE; omt->is_array = TRUE;
omt->i.a.capacity = capacity; omt->capacity = capacity;
omt->i.a.num_values = num_values; omt->i.a.num_values = num_values;
omt->i.a.values = tmp_values; omt->i.a.values = tmp_values;
omt->i.a.start_idx = 0; omt->i.a.start_idx = 0;
return 0; return 0;
} }
static inline int maybe_resize_and_convert(OMT omt, u_int32_t n) { static inline int maybe_resize_or_convert(OMT omt, u_int32_t n) {
if (omt->is_array) return maybe_resize_array(omt, n); if (omt->is_array) return maybe_resize_array(omt, n);
u_int32_t new_size = n<=2 ? 4 : 2*n; u_int32_t new_size = n<=2 ? 4 : 2*n;
...@@ -256,20 +242,11 @@ static inline int maybe_resize_and_convert(OMT omt, u_int32_t n) { ...@@ -256,20 +242,11 @@ static inline int maybe_resize_and_convert(OMT omt, u_int32_t n) {
//Rebuilding means we first turn it to an array. //Rebuilding means we first turn it to an array.
//Lets pause at the array form. //Lets pause at the array form.
u_int32_t num_nodes = nweight(omt, omt->i.t.root); u_int32_t num_nodes = nweight(omt, omt->i.t.root);
if ((omt->i.t.node_capacity/2 >= new_size) || if ((omt->capacity/2 >= new_size) ||
(omt->i.t.free_idx>=omt->i.t.node_capacity && num_nodes<n) || (omt->i.t.free_idx>=omt->capacity && num_nodes<n) ||
(omt->i.t.node_capacity<n)) { (omt->capacity<n)) {
return omt_convert_to_array(omt); return omt_convert_to_array(omt);
} }
if (omt->i.t.tmparray_size<n ||
(omt->i.t.tmparray_size/2 >= new_size)) {
/* Malloc and free instead of realloc (saves the memcpy). */
node_idx *MALLOC_N(new_size, new_tmparray);
if (new_tmparray==NULL) return errno;
toku_free(omt->i.t.tmparray);
omt->i.t.tmparray = new_tmparray;
omt->i.t.tmparray_size = new_size;
}
return 0; return 0;
} }
...@@ -309,8 +286,24 @@ static inline void rebalance(OMT omt, node_idx *n_idxp) { ...@@ -309,8 +286,24 @@ static inline void rebalance(OMT omt, node_idx *n_idxp) {
if (r==0) return; if (r==0) return;
} }
OMT_NODE n = omt->i.t.nodes+idx; OMT_NODE n = omt->i.t.nodes+idx;
fill_array_with_subtree_idxs(omt, omt->i.t.tmparray, idx); node_idx *tmp_array;
rebuild_subtree_from_idxs(omt, n_idxp, omt->i.t.tmparray, n->weight); size_t mem_needed = n->weight*sizeof(*tmp_array);
size_t mem_free = (omt->capacity-omt->i.t.free_idx)*sizeof(*omt->i.t.nodes);
BOOL malloced;
if (mem_needed<=mem_free) {
//There is sufficient free space at the end of the nodes array
//to hold enough node indexes to rebalance.
malloced = FALSE;
tmp_array = (node_idx*)(omt->i.t.nodes+omt->i.t.free_idx);
}
else {
malloced = TRUE;
MALLOC_N(n->weight, tmp_array);
if (tmp_array==NULL) return; //Don't rebalance. Still a working tree.
}
fill_array_with_subtree_idxs(omt, tmp_array, idx);
rebuild_subtree_from_idxs(omt, n_idxp, tmp_array, n->weight);
if (malloced) toku_free(tmp_array);
} }
static inline BOOL will_need_rebalance(OMT omt, node_idx n_idx, int leftmod, int rightmod) { static inline BOOL will_need_rebalance(OMT omt, node_idx n_idx, int leftmod, int rightmod) {
...@@ -637,13 +630,8 @@ int toku_omt_create (OMT *omtp) { ...@@ -637,13 +630,8 @@ int toku_omt_create (OMT *omtp) {
void toku_omt_destroy(OMT *omtp) { void toku_omt_destroy(OMT *omtp) {
OMT omt=*omtp; OMT omt=*omtp;
invalidate_cursors(omt); invalidate_cursors(omt);
if (omt->is_array) { if (omt->is_array) toku_free(omt->i.a.values);
toku_free(omt->i.a.values); else toku_free(omt->i.t.nodes);
}
else {
toku_free(omt->i.t.nodes);
toku_free(omt->i.t.tmparray);
}
toku_free(omt); toku_free(omt);
*omtp=NULL; *omtp=NULL;
} }
...@@ -666,7 +654,7 @@ int toku_omt_insert_at(OMT omt, OMTVALUE value, u_int32_t index) { ...@@ -666,7 +654,7 @@ int toku_omt_insert_at(OMT omt, OMTVALUE value, u_int32_t index) {
int r; int r;
invalidate_cursors(omt); invalidate_cursors(omt);
if (index>omt_size(omt)) return EINVAL; if (index>omt_size(omt)) return EINVAL;
if ((r=maybe_resize_and_convert(omt, 1+omt_size(omt)))) return r; if ((r=maybe_resize_or_convert(omt, 1+omt_size(omt)))) return r;
if (omt->is_array && index!=omt->i.a.num_values && if (omt->is_array && index!=omt->i.a.num_values &&
(index!=0 || omt->i.a.start_idx==0)) { (index!=0 || omt->i.a.start_idx==0)) {
if ((r=omt_convert_to_tree(omt))) return r; if ((r=omt_convert_to_tree(omt))) return r;
...@@ -704,7 +692,7 @@ int toku_omt_delete_at(OMT omt, u_int32_t index) { ...@@ -704,7 +692,7 @@ int toku_omt_delete_at(OMT omt, u_int32_t index) {
int r; int r;
invalidate_cursors(omt); invalidate_cursors(omt);
if (index>=omt_size(omt)) return EINVAL; if (index>=omt_size(omt)) return EINVAL;
if ((r=maybe_resize_and_convert(omt, -1+omt_size(omt)))) return r; if ((r=maybe_resize_or_convert(omt, -1+omt_size(omt)))) return r;
if (omt->is_array && index!=0 && index!=omt->i.a.num_values-1) { if (omt->is_array && index!=0 && index!=omt->i.a.num_values-1) {
if ((r=omt_convert_to_tree(omt))) return r; if ((r=omt_convert_to_tree(omt))) return r;
} }
...@@ -873,10 +861,6 @@ int toku_omt_merge(OMT leftomt, OMT rightomt, OMT *newomtp) { ...@@ -873,10 +861,6 @@ int toku_omt_merge(OMT leftomt, OMT rightomt, OMT *newomtp) {
return 0; return 0;
} }
////TODO: This function can actually clear memory (can free) and require a
//malloc the next time around.
////TODO: Can convert to array using this function.
//If not freeing, can instead reuse old array (either mempool or tmparray)
void toku_omt_clear(OMT omt) { void toku_omt_clear(OMT omt) {
invalidate_cursors(omt); invalidate_cursors(omt);
if (omt->is_array) { if (omt->is_array) {
...@@ -886,13 +870,17 @@ void toku_omt_clear(OMT omt) { ...@@ -886,13 +870,17 @@ void toku_omt_clear(OMT omt) {
else { else {
omt->i.t.free_idx = 0; omt->i.t.free_idx = 0;
omt->i.t.root = NODE_NULL; omt->i.t.root = NODE_NULL;
int r = omt_convert_to_array(omt);
assert((!omt->is_array) == (r!=0));
//If we fail to convert (malloc), then nothing has changed.
//Continue anyway.
} }
} }
unsigned long toku_omt_memory_size (OMT omt) { unsigned long toku_omt_memory_size (OMT omt) {
if (omt->is_array) { if (omt->is_array) {
return sizeof(*omt)+omt->i.a.capacity*sizeof(omt->i.a.values[0]); return sizeof(*omt)+omt->capacity*sizeof(omt->i.a.values[0]);
} }
return sizeof(*omt)+omt->i.t.node_capacity*sizeof(omt->i.t.nodes[0]) + omt->i.t.tmparray_size*sizeof(omt->i.t.tmparray[0]); return sizeof(*omt)+omt->capacity*sizeof(omt->i.t.nodes[0]);
} }
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