Drizzled Public API Documentation

root.cc

Go to the documentation of this file.
00001 /* Copyright (C) 2000 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00021 #include <config.h>
00022 
00023 #include <drizzled/internal/my_sys.h>
00024 #include <drizzled/internal/m_string.h>
00025 
00026 #include <algorithm>
00027 
00028 using namespace std;
00029 
00030 namespace drizzled
00031 {
00032 
00033 static const unsigned int MAX_BLOCK_TO_DROP= 4096;
00034 static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
00035 
00054 void memory::Root::init_alloc_root(size_t block_size_arg)
00055 {
00056   free= used= pre_alloc= 0;
00057   min_malloc= 32;
00058   block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
00059   error_handler= 0;
00060   block_num= 4;     /* We shift this with >>2 */
00061   first_block_usage= 0;
00062 }
00063 
00064 memory::Root::~Root()
00065 {
00066 }
00067 
00068 
00084 void memory::Root::reset_root_defaults(size_t block_size_arg, size_t pre_alloc_size)
00085 {
00086   block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
00087   if (pre_alloc_size)
00088   {
00089     size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
00090     if (not pre_alloc || pre_alloc->size != size)
00091     {
00092       memory::internal::UsedMemory *mem, **prev= &this->free;
00093       /*
00094         Free unused blocks, so that consequent calls
00095         to reset_root_defaults won't eat away memory.
00096       */
00097       while (*prev)
00098       {
00099         mem= *prev;
00100         if (mem->size == size)
00101         {
00102           /* We found a suitable block, no need to do anything else */
00103           pre_alloc= mem;
00104           return;
00105         }
00106         if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
00107         {
00108           /* remove block from the list and free it */
00109           *prev= mem->next;
00110           std::free(mem);
00111         }
00112         else
00113           prev= &mem->next;
00114       }
00115       /* Allocate new prealloc block and add it to the end of free list */
00116       if ((mem= static_cast<memory::internal::UsedMemory *>(malloc(size))))
00117       {
00118         mem->size= size;
00119         mem->left= pre_alloc_size;
00120         mem->next= *prev;
00121         *prev= pre_alloc= mem;
00122       }
00123       else
00124       {
00125         pre_alloc= 0;
00126       }
00127     }
00128   }
00129   else
00130   {
00131     pre_alloc= 0;
00132   }
00133 }
00134 
00149 void *memory::Root::alloc_root(size_t length)
00150 {
00151   unsigned char* point;
00152   memory::internal::UsedMemory *next= NULL;
00153   memory::internal::UsedMemory **prev;
00154   assert(alloc_root_inited());
00155 
00156   length= ALIGN_SIZE(length);
00157   if ((*(prev= &this->free)) != NULL)
00158   {
00159     if ((*prev)->left < length &&
00160   this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
00161   (*prev)->left < MAX_BLOCK_TO_DROP)
00162     {
00163       next= *prev;
00164       *prev= next->next;      /* Remove block from list */
00165       next->next= this->used;
00166       this->used= next;
00167       this->first_block_usage= 0;
00168     }
00169     for (next= *prev ; next && next->left < length ; next= next->next)
00170       prev= &next->next;
00171   }
00172   if (! next)
00173   {           /* Time to alloc new block */
00174     size_t get_size, tmp_block_size;
00175 
00176     tmp_block_size= this->block_size * (this->block_num >> 2);
00177     get_size= length+ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
00178     get_size= max(get_size, tmp_block_size);
00179 
00180     if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
00181     {
00182       if (this->error_handler)
00183   (*this->error_handler)();
00184       return NULL;
00185     }
00186     this->block_num++;
00187     next->next= *prev;
00188     next->size= get_size;
00189     next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
00190     *prev=next;
00191   }
00192 
00193   point= (unsigned char*) ((char*) next+ (next->size-next->left));
00195   if ((next->left-= length) < this->min_malloc)
00196   {           /* Full block */
00197     *prev= next->next;        /* Remove block from list */
00198     next->next= this->used;
00199     this->used= next;
00200     this->first_block_usage= 0;
00201   }
00202 
00203   return point;
00204 }
00205 
00206 
00229 void *memory::Root::multi_alloc_root(int unused, ...)
00230 {
00231   va_list args;
00232   char **ptr, *start, *res;
00233   size_t tot_length, length;
00234 
00235   (void)unused; // For some reason Sun Studio registers unused as not used.
00236   va_start(args, unused);
00237   tot_length= 0;
00238   while ((ptr= va_arg(args, char **)))
00239   {
00240     length= va_arg(args, uint);
00241     tot_length+= ALIGN_SIZE(length);
00242   }
00243   va_end(args);
00244 
00245   if (!(start= (char*) this->alloc_root(tot_length)))
00246     return(0);
00247 
00248   va_start(args, unused);
00249   res= start;
00250   while ((ptr= va_arg(args, char **)))
00251   {
00252     *ptr= res;
00253     length= va_arg(args, uint);
00254     res+= ALIGN_SIZE(length);
00255   }
00256   va_end(args);
00257   return((void*) start);
00258 }
00259 
00260 static void trash_mem(memory::internal::UsedMemory *)
00261 {
00262   TRASH(((char*)(x) + (x->size - x->left)), x->left);
00263 }
00264 
00269 void memory::Root::mark_blocks_free()
00270 {
00271   memory::internal::UsedMemory *next;
00272   memory::internal::UsedMemory **last;
00273 
00274   /* iterate through (partially) free blocks, mark them free */
00275   last= &free;
00276   for (next= free; next; next= *(last= &next->next))
00277   {
00278     next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
00279     trash_mem(next);
00280   }
00281 
00282   /* Combine the free and the used list */
00283   *last= next= used;
00284 
00285   /* now go through the used blocks and mark them free */
00286   for (; next; next= next->next)
00287   {
00288     next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
00289     trash_mem(next);
00290   }
00291 
00292   /* Now everything is set; Indicate that nothing is used anymore */
00293   used= 0;
00294   first_block_usage= 0;
00295 }
00296 
00313 void memory::Root::free_root(myf MyFlags)
00314 {
00315   memory::internal::UsedMemory *next,*old;
00316 
00317   if (MyFlags & memory::MARK_BLOCKS_FREE)
00318   {
00319     this->mark_blocks_free();
00320     return;
00321   }
00322   if (!(MyFlags & memory::KEEP_PREALLOC))
00323     this->pre_alloc=0;
00324 
00325   for (next=this->used; next ;)
00326   {
00327     old=next; next= next->next ;
00328     if (old != this->pre_alloc)
00329       std::free(old);
00330   }
00331   for (next=this->free ; next ;)
00332   {
00333     old=next; next= next->next;
00334     if (old != this->pre_alloc)
00335       std::free(old);
00336   }
00337   this->used=this->free=0;
00338   if (this->pre_alloc)
00339   {
00340     this->free=this->pre_alloc;
00341     this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
00342     trash_mem(this->pre_alloc);
00343     this->free->next=0;
00344   }
00345   this->block_num= 4;
00346   this->first_block_usage= 0;
00347 }
00348 
00354 char *memory::Root::strdup_root(const char *str)
00355 {
00356   return strmake_root(str, strlen(str));
00357 }
00358 
00370 char *memory::Root::strmake_root(const char *str, size_t len)
00371 {
00372   char *pos;
00373   if ((pos= (char *)alloc_root(len+1)))
00374   {
00375     memcpy(pos,str,len);
00376     pos[len]=0;
00377   }
00378   return pos;
00379 }
00380 
00390 void *memory::Root::memdup_root(const void *str, size_t len)
00391 {
00392   void *pos;
00393 
00394   if ((pos= this->alloc_root(len)))
00395     memcpy(pos,str,len);
00396 
00397   return pos;
00398 }
00399 
00400 } /* namespace drizzled */