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., 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;
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 <my_global.h>
20
#include <mystrings/m_string.h>
26
Initialize memory root
30
mem_root - memory root to initialize
31
block_size - size of chunks (blocks) used for memory allocation
32
(It is external size of chunk i.e. it should include
33
memory required for internal structures, thus it
34
should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
35
pre_alloc_size - if non-0, then size of block that should be
36
pre-allocated during memory root initialization.
39
This function prepares memory root for further use, sets initial size of
40
chunk for memory allocation and pre-allocates first block if specified.
41
Altough error can happen during execution of this function if
42
pre_alloc_size is non-0 it won't be reported. Instead it will be
43
reported as error in first alloc_root() on this memory root.
46
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
47
size_t pre_alloc_size __attribute__((unused)))
49
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
50
mem_root->min_malloc= 32;
51
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
52
mem_root->error_handler= 0;
53
mem_root->block_num= 4; /* We shift this with >>2 */
54
mem_root->first_block_usage= 0;
56
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
59
if ((mem_root->free= mem_root->pre_alloc=
60
(USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
63
mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
64
mem_root->free->left= pre_alloc_size;
65
mem_root->free->next= 0;
76
mem_root memory root to change defaults of
77
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
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
Function aligns and assigns new value to block size; then it tries to
85
reuse one of existing blocks as prealloc block, or malloc new one of
86
requested size. If no blocks can be reused, all unused blocks are freed
90
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
91
size_t pre_alloc_size __attribute__((unused)))
93
assert(alloc_root_inited(mem_root));
95
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
96
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
99
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
100
if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
102
USED_MEM *mem, **prev= &mem_root->free;
94
104
Free unused blocks, so that consequent calls
95
105
to reset_root_defaults won't eat away memory.
100
110
if (mem->size == size)
102
112
/* We found a suitable block, no need to do anything else */
113
mem_root->pre_alloc= mem;
106
if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
116
if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
108
118
/* remove block from the list and free it */
109
119
*prev= mem->next;
120
my_free(mem, MYF(0));
113
123
prev= &mem->next;
115
125
/* Allocate new prealloc block and add it to the end of free list */
116
if ((mem= static_cast<memory::internal::UsedMemory *>(malloc(size))))
126
if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
119
129
mem->left= pre_alloc_size;
120
130
mem->next= *prev;
121
*prev= pre_alloc= mem;
131
*prev= mem_root->pre_alloc= mem;
135
mem_root->pre_alloc= 0;
141
mem_root->pre_alloc= 0;
145
void *alloc_root(MEM_ROOT *mem_root, size_t length)
147
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
148
register USED_MEM *next;
150
assert(alloc_root_inited(mem_root));
152
length+=ALIGN_SIZE(sizeof(USED_MEM));
153
if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR))))
155
if (mem_root->error_handler)
156
(*mem_root->error_handler)();
157
return((uchar*) 0); /* purecov: inspected */
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)
151
unsigned char* point;
152
memory::internal::UsedMemory *next= NULL;
153
memory::internal::UsedMemory **prev;
154
assert(alloc_root_inited());
159
next->next= mem_root->used;
161
mem_root->used= next;
162
return((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
164
size_t get_size, block_size;
166
register USED_MEM *next= 0;
167
register USED_MEM **prev;
168
assert(alloc_root_inited(mem_root));
156
170
length= ALIGN_SIZE(length);
157
if ((*(prev= &this->free)) != NULL)
171
if ((*(prev= &mem_root->free)) != NULL)
159
173
if ((*prev)->left < length &&
160
this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
161
(*prev)->left < MAX_BLOCK_TO_DROP)
174
mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
175
(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
164
178
*prev= next->next; /* Remove block from list */
165
next->next= this->used;
167
this->first_block_usage= 0;
179
next->next= mem_root->used;
180
mem_root->used= next;
181
mem_root->first_block_usage= 0;
169
183
for (next= *prev ; next && next->left < length ; next= next->next)
170
184
prev= &next->next;
173
187
{ /* Time to alloc new block */
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))))
188
block_size= mem_root->block_size * (mem_root->block_num >> 2);
189
get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
190
get_size= max(get_size, block_size);
192
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
182
if (this->error_handler)
183
(*this->error_handler)();
194
if (mem_root->error_handler)
195
(*mem_root->error_handler)();
196
return((void*) 0); /* purecov: inspected */
198
mem_root->block_num++;
187
199
next->next= *prev;
188
200
next->size= get_size;
189
next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
201
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
193
point= (unsigned char*) ((char*) next+ (next->size-next->left));
194
/** @todo next part may be unneeded due to this->first_block_usage counter*/
195
if ((next->left-= length) < this->min_malloc)
205
point= (uchar*) ((char*) next+ (next->size-next->left));
206
/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
207
if ((next->left-= length) < mem_root->min_malloc)
196
208
{ /* Full block */
197
209
*prev= next->next; /* Remove block from list */
198
next->next= this->used;
200
this->first_block_usage= 0;
210
next->next= mem_root->used;
211
mem_root->used= next;
212
mem_root->first_block_usage= 0;
214
return((void*) point);
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, ...)
220
Allocate many pointers at the same time.
223
ptr1, ptr2, etc all point into big allocated memory area.
228
ptr1, length1 Multiple arguments terminated by a NULL pointer
234
A pointer to the beginning of the allocated memory block
235
in case of success or NULL if out of memory.
238
void *multi_alloc_root(MEM_ROOT *root, ...)
232
241
char **ptr, *start, *res;
233
242
size_t tot_length, length;
235
(void)unused; // For some reason Sun Studio registers unused as not used.
236
va_start(args, unused);
244
va_start(args, root);
238
246
while ((ptr= va_arg(args, char **)))
257
265
return((void*) start);
260
static void trash_mem(memory::internal::UsedMemory *)
262
TRASH(((char*)(x) + (x->size - x->left)), x->left);
267
* Mark all data in blocks free for reusage
269
void memory::Root::mark_blocks_free()
271
memory::internal::UsedMemory *next;
272
memory::internal::UsedMemory **last;
268
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
270
/* Mark all data in blocks free for reusage */
272
static inline void mark_blocks_free(MEM_ROOT* root)
274
register USED_MEM *next;
275
register USED_MEM **last;
274
277
/* iterate through (partially) free blocks, mark them free */
276
for (next= free; next; next= *(last= &next->next))
279
for (next= root->free; next; next= *(last= &next->next))
278
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
281
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
282
285
/* Combine the free and the used list */
286
*last= next=root->used;
285
288
/* now go through the used blocks and mark them free */
286
289
for (; next; next= next->next)
288
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
291
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
292
295
/* Now everything is set; Indicate that nothing is used anymore */
294
first_block_usage= 0;
297
root->first_block_usage= 0;
299
* Deallocate everything used by memory::alloc_root or just move
300
* used blocks to free list if called with MY_USED_TO_FREE
303
* One can call this function either with root block initialised with
304
* init_alloc_root() or with a zero:ed block.
305
* It's also safe to call this multiple times with the same mem_root.
307
* @param root Memory root
308
* @param MyFlags Flags for what should be freed:
309
* @li MARK_BLOCKS_FREED Don't free blocks, just mark them free
310
* @li KEEP_PREALLOC If this is not set, then free also the
313
void memory::Root::free_root(myf MyFlags)
302
Deallocate everything used by alloc_root or just move
303
used blocks to free list if called with MY_USED_TO_FREE
308
MyFlags Flags for what should be freed:
310
MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free
311
MY_KEEP_PREALLOC If this is not set, then free also the
315
One can call this function either with root block initialised with
316
init_alloc_root() or with a bzero()-ed block.
317
It's also safe to call this multiple times with the same mem_root.
320
void free_root(MEM_ROOT *root, myf MyFlags)
315
memory::internal::UsedMemory *next,*old;
322
register USED_MEM *next,*old;
317
if (MyFlags & memory::MARK_BLOCKS_FREE)
324
if (MyFlags & MY_MARK_BLOCKS_FREE)
319
this->mark_blocks_free();
326
mark_blocks_free(root);
322
if (!(MyFlags & memory::KEEP_PREALLOC))
329
if (!(MyFlags & MY_KEEP_PREALLOC))
325
for (next=this->used; next ;)
332
for (next=root->used; next ;)
327
334
old=next; next= next->next ;
328
if (old != this->pre_alloc)
335
if (old != root->pre_alloc)
331
for (next=this->free ; next ;)
338
for (next=root->free ; next ;)
333
340
old=next; next= next->next;
334
if (old != this->pre_alloc)
337
this->used=this->free=0;
340
this->free=this->pre_alloc;
341
this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
342
trash_mem(this->pre_alloc);
346
this->first_block_usage= 0;
351
* Duplicate a null-terminated string into memory allocated from within the
354
char *memory::Root::strdup_root(const char *str)
356
return strmake_root(str, strlen(str));
361
* Copy the (not necessarily null-terminated) string into memory allocated
362
* from within the specified Root
365
* Note that the string is copied according to the length specified, so
366
* null-termination is ignored. The duplicated string will be null-terminated,
367
* even if the original string wasn't (one additional byte is allocated for
370
char *memory::Root::strmake_root(const char *str, size_t len)
341
if (old != root->pre_alloc)
344
root->used=root->free=0;
347
root->free=root->pre_alloc;
348
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
349
TRASH_MEM(root->pre_alloc);
353
root->first_block_usage= 0;
358
Find block that contains an object and set the pre_alloc to it
361
void set_prealloc_root(MEM_ROOT *root, char *ptr)
364
for (next=root->used; next ; next=next->next)
366
if ((char*) next <= ptr && (char*) next + next->size > ptr)
368
root->pre_alloc=next;
372
for (next=root->free ; next ; next=next->next)
374
if ((char*) next <= ptr && (char*) next + next->size > ptr)
376
root->pre_alloc=next;
383
char *strdup_root(MEM_ROOT *root, const char *str)
385
return strmake_root(root, str, strlen(str));
389
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
373
if ((pos= (char *)alloc_root(len+1)))
392
if ((pos=alloc_root(root,len+1)))
375
394
memcpy(pos,str,len);