summaryrefslogtreecommitdiff
path: root/mysys/my_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/my_alloc.c')
-rw-r--r--mysys/my_alloc.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index db482454e69..b82ff965dfb 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -100,7 +100,41 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
#endif
}
- /* deallocate everything used by alloc_root */
+static inline void mark_blocks_free(MEM_ROOT* root)
+{
+ reg1 USED_MEM *next,*last = 0;
+
+ /* iterate through (partially) free blocks, mark them fully free */
+ for(next = root->free; next; next = next->next )
+ {
+ last = next;
+ next->left = next->size - ALIGN_SIZE(sizeof(USED_MEM));
+ }
+ /* if free block list was not empty, point the next of the
+ last free block to the beginning of the used list */
+ next = root->used; /* a little optimization to avoid dereferencing root
+ twice - we will shortly start iterating through used
+ list */
+ if(last)
+ last->next = next;
+ else /* if free list is empty, just point it to the current used*/
+ root->free = next;
+
+ /* now go through the current used list, and mark each block
+ as fully free. Note that because of our optimization, we do not
+ need to initialize next here - see above
+ */
+ for(;next; next = next->next)
+ next->left = next->size - ALIGN_SIZE(sizeof(USED_MEM));
+
+ /* Now everything is set - we just need to indicate that nothing is used
+ anymore
+ */
+ root->used = 0;
+}
+
+ /* deallocate everything used by alloc_root or just move
+ used blocks to free list if called with MY_USED_TO_FREE */
void free_root(MEM_ROOT *root, myf MyFlags)
{
@@ -109,6 +143,11 @@ void free_root(MEM_ROOT *root, myf MyFlags)
if (!root)
DBUG_VOID_RETURN; /* purecov: inspected */
+ if(MyFlags & MY_MARK_BLOCKS_FREE)
+ {
+ mark_blocks_free(root);
+ DBUG_VOID_RETURN;
+ }
if (!(MyFlags & MY_KEEP_PREALLOC))
root->pre_alloc=0;