diff options
Diffstat (limited to 'mysys/my_alloc.c')
-rw-r--r-- | mysys/my_alloc.c | 176 |
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; } |