Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00021 #include <config.h>
00022
00023 #include <drizzled/definitions.h>
00024 #include <drizzled/memory/root.h>
00025 #include <drizzled/internal/my_sys.h>
00026 #include <drizzled/internal/m_string.h>
00027 #include <drizzled/sql_string.h>
00028
00029 #include <algorithm>
00030
00031 using namespace std;
00032
00033 namespace drizzled {
00034 namespace memory {
00035
00036 static const unsigned int MAX_BLOCK_TO_DROP= 4096;
00037 static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
00038
00057 void Root::init(size_t block_size_arg)
00058 {
00059 free= used= pre_alloc= 0;
00060 min_malloc= 32;
00061 block_size= block_size_arg - ROOT_MIN_BLOCK_SIZE;
00062 block_num= 4;
00063 first_block_usage= 0;
00064 }
00065
00081 void Root::reset_defaults(size_t block_size_arg, size_t pre_alloc_size)
00082 {
00083 block_size= block_size_arg - ROOT_MIN_BLOCK_SIZE;
00084 if (pre_alloc_size)
00085 {
00086 size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(internal::UsedMemory));
00087 if (not pre_alloc || pre_alloc->size != size)
00088 {
00089 internal::UsedMemory *mem, **prev= &this->free;
00090
00091
00092
00093
00094 while (*prev)
00095 {
00096 mem= *prev;
00097 if (mem->size == size)
00098 {
00099
00100 pre_alloc= mem;
00101 return;
00102 }
00103 if (mem->left + ALIGN_SIZE(sizeof(internal::UsedMemory)) == mem->size)
00104 {
00105
00106 *prev= mem->next;
00107 std::free(mem);
00108 }
00109 else
00110 prev= &mem->next;
00111 }
00112
00113 mem= static_cast<internal::UsedMemory *>(malloc(size));
00114 mem->size= size;
00115 mem->left= pre_alloc_size;
00116 mem->next= *prev;
00117 *prev= pre_alloc= mem;
00118 }
00119 }
00120 else
00121 {
00122 pre_alloc= 0;
00123 }
00124 }
00125
00140 unsigned char* Root::alloc(size_t length)
00141 {
00142 internal::UsedMemory *next= NULL;
00143 assert(alloc_root_inited());
00144
00145 length= ALIGN_SIZE(length);
00146 internal::UsedMemory **prev= &this->free;
00147 if (*prev)
00148 {
00149 if ((*prev)->left < length &&
00150 this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
00151 (*prev)->left < MAX_BLOCK_TO_DROP)
00152 {
00153 next= *prev;
00154 *prev= next->next;
00155 next->next= this->used;
00156 this->used= next;
00157 this->first_block_usage= 0;
00158 }
00159 for (next= *prev; next && next->left < length; next= next->next)
00160 prev= &next->next;
00161 }
00162 if (! next)
00163 {
00164 size_t tmp_block_size= this->block_size * (this->block_num >> 2);
00165 size_t get_size= length+ALIGN_SIZE(sizeof(internal::UsedMemory));
00166 get_size= max(get_size, tmp_block_size);
00167
00168 next = static_cast<internal::UsedMemory *>(malloc(get_size));
00169 this->block_num++;
00170 next->next= *prev;
00171 next->size= get_size;
00172 next->left= get_size-ALIGN_SIZE(sizeof(internal::UsedMemory));
00173 *prev=next;
00174 }
00175
00176 unsigned char* point= (unsigned char*) ((char*) next+ (next->size-next->left));
00178 if ((next->left-= length) < this->min_malloc)
00179 {
00180 *prev= next->next;
00181 next->next= this->used;
00182 this->used= next;
00183 this->first_block_usage= 0;
00184 }
00185
00186 return point;
00187 }
00188
00189
00212 void* Root::multi_alloc(int unused, ...)
00213 {
00214 va_list args;
00215 char* *ptr, *start, *res;
00216 size_t tot_length, length;
00217
00218 (void)unused;
00219 va_start(args, unused);
00220 tot_length= 0;
00221 while ((ptr= va_arg(args, char* *)))
00222 {
00223 length= va_arg(args, uint);
00224 tot_length+= ALIGN_SIZE(length);
00225 }
00226 va_end(args);
00227
00228 start= (char*) this->alloc(tot_length);
00229
00230 va_start(args, unused);
00231 res= start;
00232 while ((ptr= va_arg(args, char* *)))
00233 {
00234 *ptr= res;
00235 length= va_arg(args, uint);
00236 res+= ALIGN_SIZE(length);
00237 }
00238 va_end(args);
00239 return((void*) start);
00240 }
00241
00246 void Root::mark_blocks_free()
00247 {
00248 internal::UsedMemory *next;
00249 internal::UsedMemory **last;
00250
00251
00252 last= &free;
00253 for (next= free; next; next= *(last= &next->next))
00254 {
00255 next->left= next->size - ALIGN_SIZE(sizeof(internal::UsedMemory));
00256 }
00257
00258
00259 *last= next= used;
00260
00261
00262 for (; next; next= next->next)
00263 {
00264 next->left= next->size - ALIGN_SIZE(sizeof(internal::UsedMemory));
00265 }
00266
00267
00268 used= 0;
00269 first_block_usage= 0;
00270 }
00271
00288 void Root::free_root(myf MyFlags)
00289 {
00290 if (MyFlags & MARK_BLOCKS_FREE)
00291 {
00292 this->mark_blocks_free();
00293 return;
00294 }
00295 if (!(MyFlags & KEEP_PREALLOC))
00296 this->pre_alloc=0;
00297
00298 for (internal::UsedMemory* next= this->used; next;)
00299 {
00300 internal::UsedMemory* old =next;
00301 next= next->next;
00302 if (old != this->pre_alloc)
00303 std::free(old);
00304 }
00305 for (internal::UsedMemory* next=this->free; next;)
00306 {
00307 internal::UsedMemory* old= next;
00308 next= next->next;
00309 if (old != this->pre_alloc)
00310 std::free(old);
00311 }
00312 this->used=this->free=0;
00313 if (this->pre_alloc)
00314 {
00315 this->free=this->pre_alloc;
00316 this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(internal::UsedMemory));
00317 this->free->next=0;
00318 }
00319 this->block_num= 4;
00320 this->first_block_usage= 0;
00321 }
00322
00328 char* Root::strdup(const char* str)
00329 {
00330 return strdup(str, strlen(str));
00331 }
00332
00344 char* Root::strdup(const char* str, size_t len)
00345 {
00346 char* pos= (char*)alloc(len + 1);
00347 memcpy(pos, str, len);
00348 pos[len]= 0;
00349 return pos;
00350 }
00351
00352 char* Root::strdup(str_ref v)
00353 {
00354 return strdup(v.data(), v.size());
00355 }
00356
00366 void* Root::memdup(const void* str, size_t len)
00367 {
00368 void* pos= alloc(len);
00369 memcpy(pos, str, len);
00370 return pos;
00371 }
00372
00373 }
00374 }