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.c176
1 files changed, 130 insertions, 46 deletions
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
index db482454e69..4d3b0604984 100644
--- a/mysys/my_alloc.c
+++ b/mysys/my_alloc.c
@@ -1,42 +1,47 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA */
+ 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 General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Routines to handle mallocing of results which will be freed the same time */
-#include <global.h>
+#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
+#undef EXTRA_DEBUG
+#define EXTRA_DEBUG
-void init_alloc_root(MEM_ROOT *mem_root, uint block_size, uint pre_alloc_size)
+void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
+ uint pre_alloc_size __attribute__((unused)))
{
- mem_root->free=mem_root->used=0;
- mem_root->min_malloc=32;
- mem_root->block_size=block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8;
- mem_root->error_handler=0;
+ mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
+ mem_root->min_malloc= 32;
+ mem_root->block_size= block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8;
+ mem_root->error_handler= 0;
+ mem_root->block_num= 4; /* We shift this with >>2 */
+ mem_root->first_block_usage= 0;
+
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
if (pre_alloc_size)
{
- if ((mem_root->free = mem_root->pre_alloc=
+ if ((mem_root->free= mem_root->pre_alloc=
(USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
MYF(0))))
{
- mem_root->free->size=pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
- mem_root->free->left=pre_alloc_size;
- mem_root->free->next=0;
+ mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
+ mem_root->free->left= pre_alloc_size;
+ mem_root->free->next= 0;
}
}
#endif
@@ -54,29 +59,37 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
(*mem_root->error_handler)();
return((gptr) 0); /* purecov: inspected */
}
- next->next=mem_root->used;
- mem_root->used=next;
+ next->next= mem_root->used;
+ next->size= Size;
+ mem_root->used= next;
return (gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM)));
#else
- uint get_size,max_left;
+ uint get_size, block_size;
gptr point;
- reg1 USED_MEM *next;
+ reg1 USED_MEM *next= 0;
reg2 USED_MEM **prev;
Size= ALIGN_SIZE(Size);
- prev= &mem_root->free;
- max_left=0;
- for (next= *prev ; next && next->left < Size ; next= next->next)
+ if ((*(prev= &mem_root->free)) != NULL)
{
- if (next->left > max_left)
- max_left=next->left;
- prev= &next->next;
+ if ((*prev)->left < Size &&
+ mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
+ (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
+ {
+ next= *prev;
+ *prev= next->next; /* Remove block from list */
+ next->next= mem_root->used;
+ mem_root->used= next;
+ mem_root->first_block_usage= 0;
+ }
+ for (next= *prev ; next && next->left < Size ; next= next->next)
+ prev= &next->next;
}
if (! next)
{ /* Time to alloc new block */
+ block_size= mem_root->block_size * (mem_root->block_num >> 2);
get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
- if (max_left*4 < mem_root->block_size && get_size < mem_root->block_size)
- get_size=mem_root->block_size; /* Normal alloc */
+ get_size= max(get_size, block_size);
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
{
@@ -84,23 +97,55 @@ gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
(*mem_root->error_handler)();
return((gptr) 0); /* purecov: inspected */
}
+ mem_root->block_num++;
next->next= *prev;
next->size= get_size;
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
*prev=next;
}
+
point= (gptr) ((char*) next+ (next->size-next->left));
+ /*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
if ((next->left-= Size) < mem_root->min_malloc)
{ /* Full block */
- *prev=next->next; /* Remove block from list */
- next->next=mem_root->used;
- mem_root->used=next;
+ *prev= next->next; /* Remove block from list */
+ next->next= mem_root->used;
+ mem_root->used= next;
+ mem_root->first_block_usage= 0;
}
return(point);
#endif
}
- /* deallocate everything used by alloc_root */
+/* Mark all data in blocks free for reusage */
+
+static inline void mark_blocks_free(MEM_ROOT* root)
+{
+ reg1 USED_MEM *next;
+ reg2 USED_MEM **last;
+
+ /* iterate through (partially) free blocks, mark them free */
+ last= &root->free;
+ for (next= root->free; next; next= *(last= &next->next))
+ next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
+
+ /* Combine the free and the used list */
+ *last= next=root->used;
+
+ /* now go through the used blocks and mark them free */
+ for (; next; next= next->next)
+ next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
+
+ /* Now everything is set; Indicate that nothing is used anymore */
+ root->used= 0;
+ root->first_block_usage= 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,18 +154,23 @@ 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;
- for ( next=root->used; next ;)
+ for (next=root->used; next ;)
{
old=next; next= next->next ;
if (old != root->pre_alloc)
my_free((gptr) old,MYF(0));
}
- for (next= root->free ; next ; )
+ for (next=root->free ; next ;)
{
- old=next; next= next->next ;
+ old=next; next= next->next;
if (old != root->pre_alloc)
my_free((gptr) old,MYF(0));
}
@@ -131,16 +181,50 @@ void free_root(MEM_ROOT *root, myf MyFlags)
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
root->free->next=0;
}
+ root->block_num= 4;
+ root->first_block_usage= 0;
DBUG_VOID_RETURN;
}
+/*
+ Find block that contains an object and set the pre_alloc to it
+*/
+
+void set_prealloc_root(MEM_ROOT *root, char *ptr)
+{
+ USED_MEM *next;
+ for (next=root->used; next ; next=next->next)
+ {
+ if ((char*) next <= ptr && (char*) next + next->size > ptr)
+ {
+ root->pre_alloc=next;
+ return;
+ }
+ }
+ for (next=root->free ; next ; next=next->next)
+ {
+ if ((char*) next <= ptr && (char*) next + next->size > ptr)
+ {
+ root->pre_alloc=next;
+ return;
+ }
+ }
+}
+
char *strdup_root(MEM_ROOT *root,const char *str)
{
- uint len= (uint) strlen(str)+1;
+ return strmake_root(root, str, strlen(str));
+}
+
+char *strmake_root(MEM_ROOT *root,const char *str, uint len)
+{
char *pos;
- if ((pos=alloc_root(root,len)))
+ if ((pos=alloc_root(root,len+1)))
+ {
memcpy(pos,str,len);
+ pos[len]=0;
+ }
return pos;
}