16
16
/* Routines to handle mallocing of results which will be freed the same time */
18
#include "drizzled/internal/mysys_priv.h"
19
#include "drizzled/internal/m_string.h"
28
static const unsigned int MAX_BLOCK_TO_DROP= 4096;
29
static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
18
#include <mystrings/m_string.h>
32
25
Initialize memory root
35
memory::init_alloc_root()
36
29
mem_root - memory root to initialize
37
30
block_size - size of chunks (blocks) used for memory allocation
38
31
(It is external size of chunk i.e. it should include
39
32
memory required for internal structures, thus it
40
should be no less than memory::ROOT_MIN_BLOCK_SIZE)
33
should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
34
pre_alloc_size - if non-0, then size of block that should be
35
pre-allocated during memory root initialization.
43
38
This function prepares memory root for further use, sets initial size of
47
42
reported as error in first alloc_root() on this memory root.
50
void memory::init_alloc_root(memory::Root *mem_root, size_t block_size)
45
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
46
size_t pre_alloc_size __attribute__((unused)))
52
48
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
53
49
mem_root->min_malloc= 32;
54
mem_root->block_size= block_size - memory::ROOT_MIN_BLOCK_SIZE;
50
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
55
51
mem_root->error_handler= 0;
56
52
mem_root->block_num= 4; /* We shift this with >>2 */
57
53
mem_root->first_block_usage= 0;
55
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
58
if ((mem_root->free= mem_root->pre_alloc=
59
(USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
62
mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
63
mem_root->free->left= pre_alloc_size;
64
mem_root->free->next= 0;
80
void memory::reset_root_defaults(memory::Root *mem_root, size_t block_size,
81
size_t pre_alloc_size)
89
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
90
size_t pre_alloc_size __attribute__((unused)))
83
92
assert(alloc_root_inited(mem_root));
85
mem_root->block_size= block_size - memory::ROOT_MIN_BLOCK_SIZE;
94
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
95
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
86
96
if (pre_alloc_size)
88
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
98
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
89
99
if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
91
memory::internal::UsedMemory *mem, **prev= &mem_root->free;
101
USED_MEM *mem, **prev= &mem_root->free;
93
103
Free unused blocks, so that consequent calls
94
104
to reset_root_defaults won't eat away memory.
102
112
mem_root->pre_alloc= mem;
105
if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
115
if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
107
117
/* remove block from the list and free it */
108
118
*prev= mem->next;
119
my_free(mem, MYF(0));
112
122
prev= &mem->next;
114
124
/* Allocate new prealloc block and add it to the end of free list */
115
if ((mem= static_cast<memory::internal::UsedMemory *>(malloc(size))))
125
if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
118
128
mem->left= pre_alloc_size;
119
129
mem->next= *prev;
120
*prev= mem_root->pre_alloc= mem;
130
*prev= mem_root->pre_alloc= mem;
130
140
mem_root->pre_alloc= 0;
135
void *memory::alloc_root(memory::Root *mem_root, size_t length)
144
void *alloc_root(MEM_ROOT *mem_root, size_t length)
146
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
147
register USED_MEM *next;
149
assert(alloc_root_inited(mem_root));
151
length+=ALIGN_SIZE(sizeof(USED_MEM));
152
if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR))))
154
if (mem_root->error_handler)
155
(*mem_root->error_handler)();
156
return((uchar*) 0); /* purecov: inspected */
158
next->next= mem_root->used;
160
mem_root->used= next;
161
return((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
137
163
size_t get_size, block_size;
138
unsigned char* point;
139
memory::internal::UsedMemory *next= NULL;
140
memory::internal::UsedMemory **prev;
165
register USED_MEM *next= 0;
166
register USED_MEM **prev;
141
167
assert(alloc_root_inited(mem_root));
143
169
length= ALIGN_SIZE(length);
144
170
if ((*(prev= &mem_root->free)) != NULL)
146
172
if ((*prev)->left < length &&
147
mem_root->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
148
(*prev)->left < MAX_BLOCK_TO_DROP)
173
mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
174
(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
151
177
*prev= next->next; /* Remove block from list */
160
186
{ /* Time to alloc new block */
161
187
block_size= mem_root->block_size * (mem_root->block_num >> 2);
162
get_size= length+ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
188
get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
163
189
get_size= max(get_size, block_size);
165
if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
191
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
167
193
if (mem_root->error_handler)
168
194
(*mem_root->error_handler)();
195
return((void*) 0); /* purecov: inspected */
171
197
mem_root->block_num++;
172
198
next->next= *prev;
173
199
next->size= get_size;
174
next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
200
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
178
point= (unsigned char*) ((char*) next+ (next->size-next->left));
204
point= (uchar*) ((char*) next+ (next->size-next->left));
179
205
/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
180
206
if ((next->left-= length) < mem_root->min_malloc)
181
207
{ /* Full block */
207
234
in case of success or NULL if out of memory.
210
void *memory::multi_alloc_root(memory::Root *root, ...)
237
void *multi_alloc_root(MEM_ROOT *root, ...)
213
240
char **ptr, *start, *res;
242
269
/* Mark all data in blocks free for reusage */
244
static inline void mark_blocks_free(memory::Root* root)
271
static inline void mark_blocks_free(MEM_ROOT* root)
246
memory::internal::UsedMemory *next;
247
memory::internal::UsedMemory **last;
273
register USED_MEM *next;
274
register USED_MEM **last;
249
276
/* iterate through (partially) free blocks, mark them free */
250
277
last= &root->free;
251
278
for (next= root->free; next; next= *(last= &next->next))
253
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
280
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
260
287
/* now go through the used blocks and mark them free */
261
288
for (; next; next= next->next)
263
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
290
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
280
307
MyFlags Flags for what should be freed:
282
MARK_BLOCKS_FREED Don't free blocks, just mark them free
283
KEEP_PREALLOC If this is not set, then free also the
309
MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free
310
MY_KEEP_PREALLOC If this is not set, then free also the
284
311
preallocated block
289
316
It's also safe to call this multiple times with the same mem_root.
292
void memory::free_root(memory::Root *root, myf MyFlags)
319
void free_root(MEM_ROOT *root, myf MyFlags)
294
memory::internal::UsedMemory *next,*old;
321
register USED_MEM *next,*old;
296
if (MyFlags & memory::MARK_BLOCKS_FREE)
323
if (MyFlags & MY_MARK_BLOCKS_FREE)
298
325
mark_blocks_free(root);
301
if (!(MyFlags & memory::KEEP_PREALLOC))
328
if (!(MyFlags & MY_KEEP_PREALLOC))
302
329
root->pre_alloc=0;
304
331
for (next=root->used; next ;)
306
333
old=next; next= next->next ;
307
334
if (old != root->pre_alloc)
310
337
for (next=root->free ; next ;)
312
339
old=next; next= next->next;
313
340
if (old != root->pre_alloc)
316
343
root->used=root->free=0;
317
344
if (root->pre_alloc)
319
346
root->free=root->pre_alloc;
320
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
347
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
321
348
TRASH_MEM(root->pre_alloc);
322
349
root->free->next=0;
330
357
Find block that contains an object and set the pre_alloc to it
333
void memory::set_prealloc_root(memory::Root *root, char *ptr)
360
void set_prealloc_root(MEM_ROOT *root, char *ptr)
335
memory::internal::UsedMemory *next;
336
363
for (next=root->used; next ; next=next->next)
338
365
if ((char*) next <= ptr && (char*) next + next->size > ptr)
355
char *memory::strdup_root(memory::Root *root, const char *str)
382
char *strdup_root(MEM_ROOT *root, const char *str)
357
384
return strmake_root(root, str, strlen(str));
361
char *memory::strmake_root(memory::Root *root, const char *str, size_t len)
388
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
364
if ((pos=(char *)memory::alloc_root(root,len+1)))
391
if ((pos=alloc_root(root,len+1)))
366
393
memcpy(pos,str,len);
373
void *memory::memdup_root(memory::Root *root, const void *str, size_t len)
400
void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
376
if ((pos=memory::alloc_root(root,len)))
403
if ((pos=alloc_root(root,len)))
377
404
memcpy(pos,str,len);
381
} /* namespace drizzled */