12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* Routines to handle mallocing of results which will be freed the same time */
18
#include <mystrings/m_string.h>
25
Initialize memory root
29
mem_root - memory root to initialize
30
block_size - size of chunks (blocks) used for memory allocation
31
(It is external size of chunk i.e. it should include
32
memory required for internal structures, thus it
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.
38
This function prepares memory root for further use, sets initial size of
39
chunk for memory allocation and pre-allocates first block if specified.
40
Altough error can happen during execution of this function if
41
pre_alloc_size is non-0 it won't be reported. Instead it will be
42
reported as error in first alloc_root() on this memory root.
45
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
46
size_t pre_alloc_size __attribute__((unused)))
48
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
49
mem_root->min_malloc= 32;
50
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
51
mem_root->error_handler= 0;
52
mem_root->block_num= 4; /* We shift this with >>2 */
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;
75
mem_root memory root to change defaults of
76
block_size new value of block size. Must be greater or equal
77
than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
78
68 bytes and depends on platform and compilation flags)
79
pre_alloc_size new size of preallocated block. If not zero,
80
must be equal to or greater than block size,
81
otherwise means 'no prealloc'.
83
Function aligns and assigns new value to block size; then it tries to
84
reuse one of existing blocks as prealloc block, or malloc new one of
85
requested size. If no blocks can be reused, all unused blocks are freed
89
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
90
size_t pre_alloc_size __attribute__((unused)))
92
assert(alloc_root_inited(mem_root));
94
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
95
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
98
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
99
if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
101
USED_MEM *mem, **prev= &mem_root->free;
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
18
* Routines to handle mallocing of results which will be freed the same time
23
#include "drizzled/internal/my_sys.h"
24
#include "drizzled/internal/m_string.h"
33
static const unsigned int MAX_BLOCK_TO_DROP= 4096;
34
static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
38
* Initialize memory root
41
* This function prepares memory root for further use, sets initial size of
42
* chunk for memory allocation and pre-allocates first block if specified.
43
* Altough error can happen during execution of this function if
44
* pre_alloc_size is non-0 it won't be reported. Instead it will be
45
* reported as error in first alloc_root() on this memory root.
47
* @param mem_root memory root to initialize
48
* @param block_size size of chunks (blocks) used for memory allocation
49
* (It is external size of chunk i.e. it should include
50
* memory required for internal structures, thus it
51
* should be no less than memory::ROOT_MIN_BLOCK_SIZE)
54
void memory::Root::init_alloc_root(size_t block_size_arg)
56
free= used= pre_alloc= 0;
58
block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
60
block_num= 4; /* We shift this with >>2 */
71
* Function aligns and assigns new value to block size; then it tries to
72
* reuse one of existing blocks as prealloc block, or malloc new one of
73
* requested size. If no blocks can be reused, all unused blocks are freed
76
* @param mem_root memory root to change defaults of
77
* @param block_size new value of block size. Must be greater or equal
78
* than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
79
* 68 bytes and depends on platform and compilation flags)
80
* @param pre_alloc_size new size of preallocated block. If not zero,
81
* must be equal to or greater than block size,
82
* otherwise means 'no prealloc'.
84
void memory::Root::reset_root_defaults(size_t block_size_arg, size_t pre_alloc_size)
86
block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
89
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
90
if (not pre_alloc || pre_alloc->size != size)
92
memory::internal::UsedMemory *mem, **prev= &this->free;
103
94
Free unused blocks, so that consequent calls
104
95
to reset_root_defaults won't eat away memory.
109
100
if (mem->size == size)
111
102
/* We found a suitable block, no need to do anything else */
112
mem_root->pre_alloc= mem;
115
if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
106
if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
117
108
/* remove block from the list and free it */
118
109
*prev= mem->next;
122
113
prev= &mem->next;
124
115
/* Allocate new prealloc block and add it to the end of free list */
125
if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
116
if ((mem= static_cast<memory::internal::UsedMemory *>(malloc(size))))
128
119
mem->left= pre_alloc_size;
129
120
mem->next= *prev;
130
*prev= mem_root->pre_alloc= mem;
121
*prev= pre_alloc= mem;
134
mem_root->pre_alloc= 0;
140
mem_root->pre_alloc= 0;
144
void *alloc_root(MEM_ROOT *mem_root, size_t length)
137
* Allocate a chunk of memory from the Root structure provided,
138
* obtaining more memory from the heap if necessary
141
* mem_root must have been initialised via init_alloc_root()
143
* @param mem_root The memory Root to allocate from
144
* @param length The size of the block to allocate
146
* @todo Would this be more suitable as a member function on the
149
void *memory::Root::alloc_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((unsigned char*) 0); /* purecov: inspected */
158
next->next= mem_root->used;
160
mem_root->used= next;
161
return((unsigned char*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
163
size_t get_size, block_size;
164
151
unsigned char* point;
165
register USED_MEM *next= 0;
166
register USED_MEM **prev;
167
assert(alloc_root_inited(mem_root));
152
memory::internal::UsedMemory *next= NULL;
153
memory::internal::UsedMemory **prev;
154
assert(alloc_root_inited());
169
156
length= ALIGN_SIZE(length);
170
if ((*(prev= &mem_root->free)) != NULL)
157
if ((*(prev= &this->free)) != NULL)
172
159
if ((*prev)->left < length &&
173
mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
174
(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
160
this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
161
(*prev)->left < MAX_BLOCK_TO_DROP)
177
164
*prev= next->next; /* Remove block from list */
178
next->next= mem_root->used;
179
mem_root->used= next;
180
mem_root->first_block_usage= 0;
165
next->next= this->used;
167
this->first_block_usage= 0;
182
169
for (next= *prev ; next && next->left < length ; next= next->next)
183
170
prev= &next->next;
186
173
{ /* Time to alloc new block */
187
block_size= mem_root->block_size * (mem_root->block_num >> 2);
188
get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
189
get_size= cmax(get_size, block_size);
191
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
174
size_t get_size, tmp_block_size;
176
tmp_block_size= this->block_size * (this->block_num >> 2);
177
get_size= length+ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
178
get_size= max(get_size, tmp_block_size);
180
if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
193
if (mem_root->error_handler)
194
(*mem_root->error_handler)();
195
return((void*) 0); /* purecov: inspected */
182
if (this->error_handler)
183
(*this->error_handler)();
197
mem_root->block_num++;
198
187
next->next= *prev;
199
188
next->size= get_size;
200
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
189
next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
204
193
point= (unsigned char*) ((char*) next+ (next->size-next->left));
205
/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
206
if ((next->left-= length) < mem_root->min_malloc)
194
/** @todo next part may be unneeded due to this->first_block_usage counter*/
195
if ((next->left-= length) < this->min_malloc)
207
196
{ /* Full block */
208
197
*prev= next->next; /* Remove block from list */
209
next->next= mem_root->used;
210
mem_root->used= next;
211
mem_root->first_block_usage= 0;
198
next->next= this->used;
200
this->first_block_usage= 0;
213
return((void*) point);
219
Allocate many pointers at the same time.
222
ptr1, ptr2, etc all point into big allocated memory area.
227
ptr1, length1 Multiple arguments terminated by a NULL pointer
233
A pointer to the beginning of the allocated memory block
234
in case of success or NULL if out of memory.
237
void *multi_alloc_root(MEM_ROOT *root, ...)
209
* Allocate many pointers at the same time.
212
* The variable arguments are a list of alternating pointers and lengths,
213
* terminated by a null pointer:
214
* @li <tt>char ** pointer1</tt>
215
* @li <tt>uint length1</tt>
216
* @li <tt>char ** pointer2</tt>
217
* @li <tt>uint length2</tt>
221
* @c pointer1, @c pointer2 etc. all point into big allocated memory area
223
* @param root Memory root
226
* A pointer to the beginning of the allocated memory block in case of
227
* success or NULL if out of memory
229
void *memory::Root::multi_alloc_root(int unused, ...)
240
232
char **ptr, *start, *res;
241
233
size_t tot_length, length;
243
va_start(args, root);
235
(void)unused; // For some reason Sun Studio registers unused as not used.
236
va_start(args, unused);
245
238
while ((ptr= va_arg(args, char **)))
267
260
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
269
/* Mark all data in blocks free for reusage */
271
static inline void mark_blocks_free(MEM_ROOT* root)
264
* Mark all data in blocks free for reusage
266
void memory::Root::mark_blocks_free()
273
register USED_MEM *next;
274
register USED_MEM **last;
268
memory::internal::UsedMemory *next;
269
memory::internal::UsedMemory **last;
276
271
/* iterate through (partially) free blocks, mark them free */
278
for (next= root->free; next; next= *(last= &next->next))
273
for (next= free; next; next= *(last= &next->next))
280
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
275
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
284
279
/* Combine the free and the used list */
285
*last= next=root->used;
287
282
/* now go through the used blocks and mark them free */
288
283
for (; next; next= next->next)
290
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
285
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
294
289
/* Now everything is set; Indicate that nothing is used anymore */
296
root->first_block_usage= 0;
291
first_block_usage= 0;
301
Deallocate everything used by alloc_root or just move
302
used blocks to free list if called with MY_USED_TO_FREE
307
MyFlags Flags for what should be freed:
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
314
One can call this function either with root block initialised with
315
init_alloc_root() or with a zero:ed block.
316
It's also safe to call this multiple times with the same mem_root.
319
void free_root(MEM_ROOT *root, myf MyFlags)
296
* Deallocate everything used by memory::alloc_root or just move
297
* used blocks to free list if called with MY_USED_TO_FREE
300
* One can call this function either with root block initialised with
301
* init_alloc_root() or with a zero:ed block.
302
* It's also safe to call this multiple times with the same mem_root.
304
* @param root Memory root
305
* @param MyFlags Flags for what should be freed:
306
* @li MARK_BLOCKS_FREED Don't free blocks, just mark them free
307
* @li KEEP_PREALLOC If this is not set, then free also the
310
void memory::Root::free_root(myf MyFlags)
321
register USED_MEM *next,*old;
312
memory::internal::UsedMemory *next,*old;
323
if (MyFlags & MY_MARK_BLOCKS_FREE)
314
if (MyFlags & memory::MARK_BLOCKS_FREE)
325
mark_blocks_free(root);
316
this->mark_blocks_free();
328
if (!(MyFlags & MY_KEEP_PREALLOC))
319
if (!(MyFlags & memory::KEEP_PREALLOC))
331
for (next=root->used; next ;)
322
for (next=this->used; next ;)
333
324
old=next; next= next->next ;
334
if (old != root->pre_alloc)
325
if (old != this->pre_alloc)
337
for (next=root->free ; next ;)
328
for (next=this->free ; next ;)
339
330
old=next; next= next->next;
340
if (old != root->pre_alloc)
343
root->used=root->free=0;
346
root->free=root->pre_alloc;
347
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
348
TRASH_MEM(root->pre_alloc);
352
root->first_block_usage= 0;
357
Find block that contains an object and set the pre_alloc to it
360
void set_prealloc_root(MEM_ROOT *root, char *ptr)
363
for (next=root->used; next ; next=next->next)
365
if ((char*) next <= ptr && (char*) next + next->size > ptr)
367
root->pre_alloc=next;
371
for (next=root->free ; next ; next=next->next)
373
if ((char*) next <= ptr && (char*) next + next->size > ptr)
375
root->pre_alloc=next;
382
char *strdup_root(MEM_ROOT *root, const char *str)
384
return strmake_root(root, str, strlen(str));
388
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
331
if (old != this->pre_alloc)
334
this->used=this->free=0;
337
this->free=this->pre_alloc;
338
this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
339
TRASH_MEM(this->pre_alloc);
343
this->first_block_usage= 0;
348
* Duplicate a null-terminated string into memory allocated from within the
351
char *memory::Root::strdup_root(const char *str)
353
return strmake_root(str, strlen(str));
358
* Copy the (not necessarily null-terminated) string into memory allocated
359
* from within the specified Root
362
* Note that the string is copied according to the length specified, so
363
* null-termination is ignored. The duplicated string will be null-terminated,
364
* even if the original string wasn't (one additional byte is allocated for
367
char *memory::Root::strmake_root(const char *str, size_t len)
391
if ((pos=(char *)alloc_root(root,len+1)))
370
if ((pos= (char *)alloc_root(len+1)))
393
372
memcpy(pos,str,len);