summaryrefslogtreecommitdiff
path: root/mysys/tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/tree.c')
-rw-r--r--mysys/tree.c68
1 files changed, 53 insertions, 15 deletions
diff --git a/mysys/tree.c b/mysys/tree.c
index ccf0aa05509..8cae30e2d3e 100644
--- a/mysys/tree.c
+++ b/mysys/tree.c
@@ -66,7 +66,7 @@
#define DEFAULT_ALLOC_SIZE 8192
#define DEFAULT_ALIGN_SIZE 8192
-static void delete_tree_element(TREE *,TREE_ELEMENT *);
+static int delete_tree_element(TREE *,TREE_ELEMENT *, my_bool abort);
static int tree_walk_left_root_right(TREE *,TREE_ELEMENT *,
tree_walk_action,void *);
static int tree_walk_right_root_left(TREE *,TREE_ELEMENT *,
@@ -128,28 +128,37 @@ void init_tree(TREE *tree, size_t default_alloc_size, size_t memory_limit,
}
if (!(tree->with_delete= MY_TEST(my_flags & MY_TREE_WITH_DELETE)))
{
- init_alloc_root(&tree->mem_root, default_alloc_size, 0, MYF(my_flags));
+ init_alloc_root(&tree->mem_root, "tree", default_alloc_size, 0,
+ MYF(my_flags));
tree->mem_root.min_malloc= sizeof(TREE_ELEMENT)+tree->size_of_element;
}
DBUG_VOID_RETURN;
}
-static void free_tree(TREE *tree, myf free_flags)
+static int free_tree(TREE *tree, my_bool abort, myf free_flags)
{
+ int error, first_error= 0;
DBUG_ENTER("free_tree");
DBUG_PRINT("enter",("tree: %p", tree));
if (tree->root) /* If initialized */
{
if (tree->with_delete)
- delete_tree_element(tree,tree->root);
+ {
+ if ((error= delete_tree_element(tree, tree->root, abort)))
+ {
+ first_error= first_error ? first_error : error;
+ abort= 1;
+ }
+ }
else
{
if (tree->free)
{
if (tree->memory_limit)
(*tree->free)(NULL, free_init, tree->custom_arg);
- delete_tree_element(tree,tree->root);
+ if ((error= delete_tree_element(tree, tree->root, abort)))
+ first_error= first_error ? first_error : error;
if (tree->memory_limit)
(*tree->free)(NULL, free_end, tree->custom_arg);
}
@@ -160,32 +169,61 @@ static void free_tree(TREE *tree, myf free_flags)
tree->elements_in_tree=0;
tree->allocated=0;
- DBUG_VOID_RETURN;
+ DBUG_RETURN(first_error);
}
-void delete_tree(TREE* tree)
+
+/**
+ Delete tree.
+
+ @param tree Tree
+ @param abort 0 if normal, 1 if tree->free should not be called.
+
+ @return 0 ok
+ <> 0 Returns first <> 0 from (tree->free)(*,free_free,*)
+
+ @Notes
+ If one (tree->free)(,free_free,) returns <> 0, no future
+ tree->free(*,free_free,*) will be called.
+ Other tree->free operations (free_init, free_end) will be called
+*/
+
+
+int delete_tree(TREE* tree, my_bool abort)
{
- free_tree(tree, MYF(0)); /* my_free() mem_root if applicable */
+ return free_tree(tree, abort, MYF(0)); /* my_free() mem_root if applicable */
}
-void reset_tree(TREE* tree)
+int reset_tree(TREE* tree)
{
/* do not free mem_root, just mark blocks as free */
- free_tree(tree, MYF(MY_MARK_BLOCKS_FREE));
+ return free_tree(tree, 0, MYF(MY_MARK_BLOCKS_FREE));
}
-static void delete_tree_element(TREE *tree, TREE_ELEMENT *element)
+static int delete_tree_element(TREE *tree, TREE_ELEMENT *element,
+ my_bool abort)
{
+ int error, first_error= 0;
if (element != &null_element)
{
- delete_tree_element(tree,element->left);
- if (tree->free)
- (*tree->free)(ELEMENT_KEY(tree,element), free_free, tree->custom_arg);
- delete_tree_element(tree,element->right);
+ if ((first_error= delete_tree_element(tree, element->left, abort)))
+ abort= 1;
+ if (!abort && tree->free)
+ {
+ if ((error= (*tree->free)(ELEMENT_KEY(tree,element), free_free,
+ tree->custom_arg)))
+ {
+ first_error= first_error ? first_error : error;
+ abort= 1;
+ }
+ }
+ if ((error= delete_tree_element(tree, element->right, abort)))
+ first_error= first_error ? first_error : error;
if (tree->with_delete)
my_free(element);
}
+ return first_error;
}