my_alloc.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:10k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* Routines to handle mallocing of results which will be freed the same time */
  14. #include <my_global.h>
  15. #include <my_sys.h>
  16. #include <m_string.h>
  17. #undef EXTRA_DEBUG
  18. #define EXTRA_DEBUG
  19. /*
  20.   Initialize memory root
  21.   SYNOPSIS
  22.     init_alloc_root()
  23.       mem_root       - memory root to initialize
  24.       block_size     - size of chunks (blocks) used for memory allocation
  25.                        (It is external size of chunk i.e. it should include
  26.                         memory required for internal structures, thus it
  27.                         should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
  28.       pre_alloc_size - if non-0, then size of block that should be
  29.                        pre-allocated during memory root initialization.
  30.   DESCRIPTION
  31.     This function prepares memory root for further use, sets initial size of
  32.     chunk for memory allocation and pre-allocates first block if specified.
  33.     Altough error can happen during execution of this function if pre_alloc_size
  34.     is non-0 it won't be reported. Instead it will be reported as error in first
  35.     alloc_root() on this memory root.
  36. */
  37. void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
  38.      uint pre_alloc_size __attribute__((unused)))
  39. {
  40.   DBUG_ENTER("init_alloc_root");
  41.   DBUG_PRINT("enter",("root: 0x%lx", mem_root));
  42.   mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
  43.   mem_root->min_malloc= 32;
  44.   mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
  45.   mem_root->error_handler= 0;
  46.   mem_root->block_num= 4; /* We shift this with >>2 */
  47.   mem_root->first_block_usage= 0;
  48. #if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
  49.   if (pre_alloc_size)
  50.   {
  51.     if ((mem_root->free= mem_root->pre_alloc=
  52.  (USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
  53.        MYF(0))))
  54.     {
  55.       mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
  56.       mem_root->free->left= pre_alloc_size;
  57.       mem_root->free->next= 0;
  58.     }
  59.   }
  60. #endif
  61.   DBUG_VOID_RETURN;
  62. }
  63. /*
  64.   SYNOPSIS
  65.     reset_root_defaults()
  66.     mem_root        memory root to change defaults of
  67.     block_size      new value of block size. Must be greater or equal
  68.                     than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
  69.                     68 bytes and depends on platform and compilation flags)
  70.     pre_alloc_size  new size of preallocated block. If not zero,
  71.                     must be equal to or greater than block size,
  72.                     otherwise means 'no prealloc'.
  73.   DESCRIPTION
  74.     Function aligns and assigns new value to block size; then it tries to
  75.     reuse one of existing blocks as prealloc block, or malloc new one of
  76.     requested size. If no blocks can be reused, all unused blocks are freed
  77.     before allocation.
  78.  */
  79. void reset_root_defaults(MEM_ROOT *mem_root, uint block_size,
  80.                          uint pre_alloc_size __attribute__((unused)))
  81. {
  82.   DBUG_ASSERT(alloc_root_inited(mem_root));
  83.   mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
  84. #if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
  85.   if (pre_alloc_size)
  86.   {
  87.     uint size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
  88.     if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
  89.     {
  90.       USED_MEM *mem, **prev= &mem_root->free;
  91.       /*
  92.         Free unused blocks, so that consequent calls
  93.         to reset_root_defaults won't eat away memory.
  94.       */
  95.       while (*prev)
  96.       {
  97.         mem= *prev;
  98.         if (mem->size == size)
  99.         {
  100.           /* We found a suitable block, no need to do anything else */
  101.           mem_root->pre_alloc= mem;
  102.           return;
  103.         }
  104.         if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
  105.         {
  106.           /* remove block from the list and free it */
  107.           *prev= mem->next;
  108.           my_free((gptr) mem, MYF(0));
  109.         }
  110.         else
  111.           prev= &mem->next;
  112.       }
  113.       /* Allocate new prealloc block and add it to the end of free list */
  114.       if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
  115.       {
  116.         mem->size= size; 
  117.         mem->left= pre_alloc_size;
  118.         mem->next= *prev;
  119.         *prev= mem_root->pre_alloc= mem; 
  120.       }
  121.     }
  122.   }
  123.   else
  124. #endif
  125.     mem_root->pre_alloc= 0;
  126. }
  127. gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
  128. {
  129. #if defined(HAVE_purify) && defined(EXTRA_DEBUG)
  130.   reg1 USED_MEM *next;
  131.   DBUG_ENTER("alloc_root");
  132.   DBUG_PRINT("enter",("root: 0x%lx", mem_root));
  133.   DBUG_ASSERT(alloc_root_inited(mem_root));
  134.   Size+=ALIGN_SIZE(sizeof(USED_MEM));
  135.   if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME))))
  136.   {
  137.     if (mem_root->error_handler)
  138.       (*mem_root->error_handler)();
  139.     DBUG_RETURN((gptr) 0); /* purecov: inspected */
  140.   }
  141.   next->next= mem_root->used;
  142.   next->size= Size;
  143.   mem_root->used= next;
  144.   DBUG_PRINT("exit",("ptr: 0x%lx", (((char*) next)+
  145.                                     ALIGN_SIZE(sizeof(USED_MEM)))));
  146.   DBUG_RETURN((gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
  147. #else
  148.   uint get_size, block_size;
  149.   gptr point;
  150.   reg1 USED_MEM *next= 0;
  151.   reg2 USED_MEM **prev;
  152.   DBUG_ASSERT(alloc_root_inited(mem_root));
  153.   Size= ALIGN_SIZE(Size);
  154.   if ((*(prev= &mem_root->free)) != NULL)
  155.   {
  156.     if ((*prev)->left < Size &&
  157. mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
  158. (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
  159.     {
  160.       next= *prev;
  161.       *prev= next->next; /* Remove block from list */
  162.       next->next= mem_root->used;
  163.       mem_root->used= next;
  164.       mem_root->first_block_usage= 0;
  165.     }
  166.     for (next= *prev ; next && next->left < Size ; next= next->next)
  167.       prev= &next->next;
  168.   }
  169.   if (! next)
  170.   { /* Time to alloc new block */
  171.     block_size= mem_root->block_size * (mem_root->block_num >> 2);
  172.     get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
  173.     get_size= max(get_size, block_size);
  174.     if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
  175.     {
  176.       if (mem_root->error_handler)
  177. (*mem_root->error_handler)();
  178.       return((gptr) 0); /* purecov: inspected */
  179.     }
  180.     mem_root->block_num++;
  181.     next->next= *prev;
  182.     next->size= get_size;
  183.     next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
  184.     *prev=next;
  185.   }
  186.   point= (gptr) ((char*) next+ (next->size-next->left));
  187.   /*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
  188.   if ((next->left-= Size) < mem_root->min_malloc)
  189.   { /* Full block */
  190.     *prev= next->next; /* Remove block from list */
  191.     next->next= mem_root->used;
  192.     mem_root->used= next;
  193.     mem_root->first_block_usage= 0;
  194.   }
  195.   return(point);
  196. #endif
  197. }
  198. #ifdef SAFEMALLOC
  199. #define TRASH(X) bfill(((char*)(X) + ((X)->size-(X)->left)), (X)->left, 0xa5)
  200. #else
  201. #define TRASH /* no-op */
  202. #endif
  203. /* Mark all data in blocks free for reusage */
  204. static inline void mark_blocks_free(MEM_ROOT* root)
  205. {
  206.   reg1 USED_MEM *next;
  207.   reg2 USED_MEM **last;
  208.   /* iterate through (partially) free blocks, mark them free */
  209.   last= &root->free;
  210.   for (next= root->free; next; next= *(last= &next->next))
  211.   {
  212.     next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
  213.     TRASH(next);
  214.   }
  215.   /* Combine the free and the used list */
  216.   *last= next=root->used;
  217.   /* now go through the used blocks and mark them free */
  218.   for (; next; next= next->next)
  219.   {
  220.     next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
  221.     TRASH(next);
  222.   }
  223.   /* Now everything is set; Indicate that nothing is used anymore */
  224.   root->used= 0;
  225.   root->first_block_usage= 0;
  226. }
  227. /*
  228.   Deallocate everything used by alloc_root or just move
  229.   used blocks to free list if called with MY_USED_TO_FREE
  230. */
  231. void free_root(MEM_ROOT *root, myf MyFlags)
  232. {
  233.   reg1 USED_MEM *next,*old;
  234.   DBUG_ENTER("free_root");
  235.   DBUG_PRINT("enter",("root: 0x%lx  flags: %u", root, (uint) MyFlags));
  236.   if (!root) /* QQ: Should be deleted */
  237.     DBUG_VOID_RETURN; /* purecov: inspected */
  238.   if (MyFlags & MY_MARK_BLOCKS_FREE)
  239.   {
  240.     mark_blocks_free(root);
  241.     DBUG_VOID_RETURN;
  242.   }
  243.   if (!(MyFlags & MY_KEEP_PREALLOC))
  244.     root->pre_alloc=0;
  245.   for (next=root->used; next ;)
  246.   {
  247.     old=next; next= next->next ;
  248.     if (old != root->pre_alloc)
  249.       my_free((gptr) old,MYF(0));
  250.   }
  251.   for (next=root->free ; next ;)
  252.   {
  253.     old=next; next= next->next;
  254.     if (old != root->pre_alloc)
  255.       my_free((gptr) old,MYF(0));
  256.   }
  257.   root->used=root->free=0;
  258.   if (root->pre_alloc)
  259.   {
  260.     root->free=root->pre_alloc;
  261.     root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
  262.     TRASH(root->pre_alloc);
  263.     root->free->next=0;
  264.   }
  265.   root->block_num= 4;
  266.   root->first_block_usage= 0;
  267.   DBUG_VOID_RETURN;
  268. }
  269. /*
  270.   Find block that contains an object and set the pre_alloc to it
  271. */
  272. void set_prealloc_root(MEM_ROOT *root, char *ptr)
  273. {
  274.   USED_MEM *next;
  275.   for (next=root->used; next ; next=next->next)
  276.   {
  277.     if ((char*) next <= ptr && (char*) next + next->size > ptr)
  278.     {
  279.       root->pre_alloc=next;
  280.       return;
  281.     }
  282.   }
  283.   for (next=root->free ; next ; next=next->next)
  284.   {
  285.     if ((char*) next <= ptr && (char*) next + next->size > ptr)
  286.     {
  287.       root->pre_alloc=next;
  288.       return;
  289.     }
  290.   }
  291. }
  292. char *strdup_root(MEM_ROOT *root,const char *str)
  293. {
  294.   return strmake_root(root, str, strlen(str));
  295. }
  296. char *strmake_root(MEM_ROOT *root,const char *str, uint len)
  297. {
  298.   char *pos;
  299.   if ((pos=alloc_root(root,len+1)))
  300.   {
  301.     memcpy(pos,str,len);
  302.     pos[len]=0;
  303.   }
  304.   return pos;
  305. }
  306. char *memdup_root(MEM_ROOT *root,const char *str,uint len)
  307. {
  308.   char *pos;
  309.   if ((pos=alloc_root(root,len)))
  310.     memcpy(pos,str,len);
  311.   return pos;
  312. }