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;
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 "mysys/mysys_priv.h"
19
#include <mystrings/m_string.h>
23
Initialize memory root
27
mem_root - memory root to initialize
28
block_size - size of chunks (blocks) used for memory allocation
29
(It is external size of chunk i.e. it should include
30
memory required for internal structures, thus it
31
should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
32
pre_alloc_size - if non-0, then size of block that should be
33
pre-allocated during memory root initialization.
36
This function prepares memory root for further use, sets initial size of
37
chunk for memory allocation and pre-allocates first block if specified.
38
Altough error can happen during execution of this function if
39
pre_alloc_size is non-0 it won't be reported. Instead it will be
40
reported as error in first alloc_root() on this memory root.
43
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
46
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
47
mem_root->min_malloc= 32;
48
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
49
mem_root->error_handler= 0;
50
mem_root->block_num= 4; /* We shift this with >>2 */
51
mem_root->first_block_usage= 0;
60
mem_root memory root to change defaults of
61
block_size new value of block size. Must be greater or equal
62
than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
63
68 bytes and depends on platform and compilation flags)
64
pre_alloc_size new size of preallocated block. If not zero,
65
must be equal to or greater than block size,
66
otherwise means 'no prealloc'.
68
Function aligns and assigns new value to block size; then it tries to
69
reuse one of existing blocks as prealloc block, or malloc new one of
70
requested size. If no blocks can be reused, all unused blocks are freed
74
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
75
size_t pre_alloc_size)
77
assert(alloc_root_inited(mem_root));
79
mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
87
80
if (pre_alloc_size)
89
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
90
if (not pre_alloc || pre_alloc->size != size)
82
size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
83
if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
92
memory::internal::UsedMemory *mem, **prev= &this->free;
85
USED_MEM *mem, **prev= &mem_root->free;
94
87
Free unused blocks, so that consequent calls
95
88
to reset_root_defaults won't eat away memory.
100
93
if (mem->size == size)
102
95
/* We found a suitable block, no need to do anything else */
96
mem_root->pre_alloc= mem;
106
if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
99
if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
108
101
/* remove block from the list and free it */
109
102
*prev= mem->next;
113
106
prev= &mem->next;
115
108
/* Allocate new prealloc block and add it to the end of free list */
116
if ((mem= static_cast<memory::internal::UsedMemory *>(malloc(size))))
109
if ((mem= (USED_MEM *) malloc(size)))
119
112
mem->left= pre_alloc_size;
120
113
mem->next= *prev;
121
*prev= pre_alloc= mem;
114
*prev= mem_root->pre_alloc= mem;
118
mem_root->pre_alloc= 0;
124
mem_root->pre_alloc= 0;
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)
129
void *alloc_root(MEM_ROOT *mem_root, size_t length)
131
size_t get_size, block_size;
151
132
unsigned char* point;
152
memory::internal::UsedMemory *next= NULL;
153
memory::internal::UsedMemory **prev;
154
assert(alloc_root_inited());
133
register USED_MEM *next= 0;
134
register USED_MEM **prev;
135
assert(alloc_root_inited(mem_root));
156
137
length= ALIGN_SIZE(length);
157
if ((*(prev= &this->free)) != NULL)
138
if ((*(prev= &mem_root->free)) != NULL)
159
140
if ((*prev)->left < length &&
160
this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
161
(*prev)->left < MAX_BLOCK_TO_DROP)
141
mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
142
(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
164
145
*prev= next->next; /* Remove block from list */
165
next->next= this->used;
167
this->first_block_usage= 0;
146
next->next= mem_root->used;
147
mem_root->used= next;
148
mem_root->first_block_usage= 0;
169
150
for (next= *prev ; next && next->left < length ; next= next->next)
170
151
prev= &next->next;
173
154
{ /* 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))))
155
block_size= mem_root->block_size * (mem_root->block_num >> 2);
156
get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
157
get_size= cmax(get_size, block_size);
159
if (!(next = (USED_MEM*) malloc(get_size)))
182
if (this->error_handler)
183
(*this->error_handler)();
161
if (mem_root->error_handler)
162
(*mem_root->error_handler)();
163
return((void*) 0); /* purecov: inspected */
165
mem_root->block_num++;
187
166
next->next= *prev;
188
167
next->size= get_size;
189
next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
168
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
193
172
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)
173
/*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
174
if ((next->left-= length) < mem_root->min_malloc)
196
175
{ /* Full block */
197
176
*prev= next->next; /* Remove block from list */
198
next->next= this->used;
200
this->first_block_usage= 0;
177
next->next= mem_root->used;
178
mem_root->used= next;
179
mem_root->first_block_usage= 0;
181
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, ...)
186
Allocate many pointers at the same time.
189
ptr1, ptr2, etc all point into big allocated memory area.
194
ptr1, length1 Multiple arguments terminated by a NULL pointer
200
A pointer to the beginning of the allocated memory block
201
in case of success or NULL if out of memory.
204
void *multi_alloc_root(MEM_ROOT *root, ...)
232
207
char **ptr, *start, *res;
233
208
size_t tot_length, length;
235
(void)unused; // For some reason Sun Studio registers unused as not used.
236
va_start(args, unused);
210
va_start(args, root);
238
212
while ((ptr= va_arg(args, char **)))
257
231
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;
234
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
236
/* Mark all data in blocks free for reusage */
238
static inline void mark_blocks_free(MEM_ROOT* root)
240
register USED_MEM *next;
241
register USED_MEM **last;
274
243
/* iterate through (partially) free blocks, mark them free */
276
for (next= free; next; next= *(last= &next->next))
245
for (next= root->free; next; next= *(last= &next->next))
278
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
247
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
282
251
/* Combine the free and the used list */
252
*last= next=root->used;
285
254
/* now go through the used blocks and mark them free */
286
255
for (; next; next= next->next)
288
next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
257
next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
292
261
/* Now everything is set; Indicate that nothing is used anymore */
294
first_block_usage= 0;
263
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)
268
Deallocate everything used by alloc_root or just move
269
used blocks to free list if called with MY_USED_TO_FREE
274
MyFlags Flags for what should be freed:
276
MY_MARK_BLOCKS_FREED Don't free blocks, just mark them free
277
MY_KEEP_PREALLOC If this is not set, then free also the
281
One can call this function either with root block initialised with
282
init_alloc_root() or with a zero:ed block.
283
It's also safe to call this multiple times with the same mem_root.
286
void free_root(MEM_ROOT *root, myf MyFlags)
315
memory::internal::UsedMemory *next,*old;
288
register USED_MEM *next,*old;
317
if (MyFlags & memory::MARK_BLOCKS_FREE)
290
if (MyFlags & MY_MARK_BLOCKS_FREE)
319
this->mark_blocks_free();
292
mark_blocks_free(root);
322
if (!(MyFlags & memory::KEEP_PREALLOC))
295
if (!(MyFlags & MY_KEEP_PREALLOC))
325
for (next=this->used; next ;)
298
for (next=root->used; next ;)
327
300
old=next; next= next->next ;
328
if (old != this->pre_alloc)
301
if (old != root->pre_alloc)
331
for (next=this->free ; next ;)
304
for (next=root->free ; next ;)
333
306
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)
307
if (old != root->pre_alloc)
310
root->used=root->free=0;
313
root->free=root->pre_alloc;
314
root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
315
TRASH_MEM(root->pre_alloc);
319
root->first_block_usage= 0;
324
Find block that contains an object and set the pre_alloc to it
327
void set_prealloc_root(MEM_ROOT *root, char *ptr)
330
for (next=root->used; next ; next=next->next)
332
if ((char*) next <= ptr && (char*) next + next->size > ptr)
334
root->pre_alloc=next;
338
for (next=root->free ; next ; next=next->next)
340
if ((char*) next <= ptr && (char*) next + next->size > ptr)
342
root->pre_alloc=next;
349
char *strdup_root(MEM_ROOT *root, const char *str)
351
return strmake_root(root, str, strlen(str));
355
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
373
if ((pos= (char *)alloc_root(len+1)))
358
if ((pos=(char *)alloc_root(root,len+1)))
375
360
memcpy(pos,str,len);