~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/memory/root.cc

Merge Revision revid:marko.makela@oracle.com-20100505101406-u4low2x26q6itck0 from MySQL InnoDB

Original revid:marko.makela@oracle.com-20100505101406-u4low2x26q6itck0

Original Authors: Marko Mäkelä <marko.makela@oracle.com>
Original commit message:
Merge from mysql-5.1-innodb:

  ------------------------------------------------------------
  revno: 3446
  revision-id: marko.makela@oracle.com-20100505100507-6kcd2hf32hruxbv7
  parent: marko.makela@oracle.com-20100505095328-vetnl0flhmhao7p5
  committer: Marko Mäkelä <marko.makela@oracle.com>
  branch nick: 5.1-innodb
  timestamp: Wed 2010-05-05 13:05:07 +0300
  message:
    Add Valgrind diagnostics to track down Bug #38999.
  ------------------------------------------------------------

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
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 */
15
 
 
16
 
/* Routines to handle mallocing of results which will be freed the same time */
17
 
 
18
 
#include <mystrings/m_string.h>
19
 
#include <my_sys.h>
20
 
#undef EXTRA_DEBUG
21
 
#define EXTRA_DEBUG
22
 
 
23
 
 
24
 
/*
25
 
  Initialize memory root
26
 
 
27
 
  SYNOPSIS
28
 
    init_alloc_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.
36
 
 
37
 
  DESCRIPTION
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.
43
 
*/
44
 
 
45
 
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
46
 
                     size_t pre_alloc_size __attribute__((unused)))
47
 
{
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;
54
 
 
55
 
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
56
 
  if (pre_alloc_size)
57
 
  {
58
 
    if ((mem_root->free= mem_root->pre_alloc=
59
 
         (USED_MEM*) my_malloc(pre_alloc_size+ ALIGN_SIZE(sizeof(USED_MEM)),
60
 
                               MYF(0))))
61
 
    {
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;
65
 
    }
66
 
  }
67
 
#endif
68
 
  return;
69
 
}
70
 
 
71
 
 
72
 
/*
73
 
  SYNOPSIS
74
 
    reset_root_defaults()
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'.
82
 
  DESCRIPTION
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
86
 
    before allocation.
87
 
*/
88
 
 
89
 
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
90
 
                         size_t pre_alloc_size __attribute__((unused)))
91
 
{
92
 
  assert(alloc_root_inited(mem_root));
93
 
 
94
 
  mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
95
 
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
96
 
  if (pre_alloc_size)
97
 
  {
98
 
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
99
 
    if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
100
 
    {
101
 
      USED_MEM *mem, **prev= &mem_root->free;
 
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
15
 
 
16
/**
 
17
 * @file
 
18
 * Routines to handle mallocing of results which will be freed the same time 
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include "drizzled/internal/my_sys.h"
 
24
#include "drizzled/internal/m_string.h"
 
25
 
 
26
#include <algorithm>
 
27
 
 
28
using namespace std;
 
29
 
 
30
namespace drizzled
 
31
{
 
32
 
 
33
static const unsigned int MAX_BLOCK_TO_DROP= 4096;
 
34
static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
 
35
 
 
36
/**
 
37
 * @brief
 
38
 * Initialize memory root
 
39
 *
 
40
 * @details
 
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.
 
46
 *
 
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)
 
52
 *
 
53
 */
 
54
void memory::Root::init_alloc_root(size_t block_size_arg)
 
55
{
 
56
  free= used= pre_alloc= 0;
 
57
  min_malloc= 32;
 
58
  block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
 
59
  error_handler= 0;
 
60
  block_num= 4;                 /* We shift this with >>2 */
 
61
  first_block_usage= 0;
 
62
}
 
63
 
 
64
memory::Root::~Root()
 
65
{
 
66
}
 
67
 
 
68
 
 
69
/**
 
70
 * @details
 
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
 
74
 * before allocation.
 
75
 *
 
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'.
 
83
 */
 
84
void memory::Root::reset_root_defaults(size_t block_size_arg, size_t pre_alloc_size)
 
85
{
 
86
  block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
 
87
  if (pre_alloc_size)
 
88
  {
 
89
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
 
90
    if (not pre_alloc || pre_alloc->size != size)
 
91
    {
 
92
      memory::internal::UsedMemory *mem, **prev= &this->free;
102
93
      /*
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)
110
101
        {
111
102
          /* We found a suitable block, no need to do anything else */
112
 
          mem_root->pre_alloc= mem;
 
103
          pre_alloc= mem;
113
104
          return;
114
105
        }
115
 
        if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
 
106
        if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
116
107
        {
117
108
          /* remove block from the list and free it */
118
109
          *prev= mem->next;
119
 
          free(mem);
 
110
          std::free(mem);
120
111
        }
121
112
        else
122
113
          prev= &mem->next;
123
114
      }
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))))
126
117
      {
127
 
        mem->size= size; 
 
118
        mem->size= 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;
131
122
      }
132
123
      else
133
124
      {
134
 
        mem_root->pre_alloc= 0;
 
125
        pre_alloc= 0;
135
126
      }
136
127
    }
137
128
  }
138
129
  else
139
 
#endif
140
 
    mem_root->pre_alloc= 0;
 
130
  {
 
131
    pre_alloc= 0;
 
132
  }
141
133
}
142
134
 
143
 
 
144
 
void *alloc_root(MEM_ROOT *mem_root, size_t length)
 
135
/**
 
136
 * @brief 
 
137
 * Allocate a chunk of memory from the Root structure provided, 
 
138
 * obtaining more memory from the heap if necessary
 
139
 *
 
140
 * @pre
 
141
 * mem_root must have been initialised via init_alloc_root()
 
142
 *
 
143
 * @param  mem_root  The memory Root to allocate from
 
144
 * @param  length    The size of the block to allocate
 
145
 *
 
146
 * @todo Would this be more suitable as a member function on the
 
147
 * Root class?
 
148
 */
 
149
void *memory::Root::alloc_root(size_t length)
145
150
{
146
 
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
147
 
  register USED_MEM *next;
148
 
 
149
 
  assert(alloc_root_inited(mem_root));
150
 
 
151
 
  length+=ALIGN_SIZE(sizeof(USED_MEM));
152
 
  if (!(next = (USED_MEM*) my_malloc(length,MYF(MY_WME | ME_FATALERROR))))
153
 
  {
154
 
    if (mem_root->error_handler)
155
 
      (*mem_root->error_handler)();
156
 
    return((unsigned char*) 0);                 /* purecov: inspected */
157
 
  }
158
 
  next->next= mem_root->used;
159
 
  next->size= length;
160
 
  mem_root->used= next;
161
 
  return((unsigned char*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
162
 
#else
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());
168
155
 
169
156
  length= ALIGN_SIZE(length);
170
 
  if ((*(prev= &mem_root->free)) != NULL)
 
157
  if ((*(prev= &this->free)) != NULL)
171
158
  {
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)
175
162
    {
176
163
      next= *prev;
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;
 
166
      this->used= next;
 
167
      this->first_block_usage= 0;
181
168
    }
182
169
    for (next= *prev ; next && next->left < length ; next= next->next)
183
170
      prev= &next->next;
184
171
  }
185
172
  if (! 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);
190
 
 
191
 
    if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
 
174
    size_t get_size, tmp_block_size;
 
175
 
 
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);
 
179
 
 
180
    if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
192
181
    {
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)();
 
184
      return NULL;
196
185
    }
197
 
    mem_root->block_num++;
 
186
    this->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));
201
190
    *prev=next;
202
191
  }
203
192
 
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;
 
199
    this->used= next;
 
200
    this->first_block_usage= 0;
212
201
  }
213
 
  return((void*) point);
214
 
#endif
 
202
 
 
203
  return point;
215
204
}
216
205
 
217
206
 
218
 
/*
219
 
  Allocate many pointers at the same time.
220
 
 
221
 
  DESCRIPTION
222
 
    ptr1, ptr2, etc all point into big allocated memory area.
223
 
 
224
 
  SYNOPSIS
225
 
    multi_alloc_root()
226
 
      root               Memory root
227
 
      ptr1, length1      Multiple arguments terminated by a NULL pointer
228
 
      ptr2, length2      ...
229
 
      ...
230
 
      NULL
231
 
 
232
 
  RETURN VALUE
233
 
    A pointer to the beginning of the allocated memory block
234
 
    in case of success or NULL if out of memory.
235
 
*/
236
 
 
237
 
void *multi_alloc_root(MEM_ROOT *root, ...)
 
207
/**
 
208
 * @brief
 
209
 * Allocate many pointers at the same time.
 
210
 *
 
211
 * @details
 
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>
 
218
 * @li <tt>...</tt>
 
219
 * @li <tt>NULL</tt>
 
220
 *
 
221
 * @c pointer1, @c pointer2 etc. all point into big allocated memory area
 
222
 *
 
223
 * @param root  Memory root
 
224
 *
 
225
 * @return
 
226
 * A pointer to the beginning of the allocated memory block in case of 
 
227
 * success or NULL if out of memory
 
228
 */
 
229
void *memory::Root::multi_alloc_root(int unused, ...)
238
230
{
239
231
  va_list args;
240
232
  char **ptr, *start, *res;
241
233
  size_t tot_length, length;
242
234
 
243
 
  va_start(args, root);
 
235
  (void)unused; // For some reason Sun Studio registers unused as not used.
 
236
  va_start(args, unused);
244
237
  tot_length= 0;
245
238
  while ((ptr= va_arg(args, char **)))
246
239
  {
249
242
  }
250
243
  va_end(args);
251
244
 
252
 
  if (!(start= (char*) alloc_root(root, tot_length)))
253
 
    return(0);                            /* purecov: inspected */
 
245
  if (!(start= (char*) this->alloc_root(tot_length)))
 
246
    return(0);
254
247
 
255
 
  va_start(args, root);
 
248
  va_start(args, unused);
256
249
  res= start;
257
250
  while ((ptr= va_arg(args, char **)))
258
251
  {
266
259
 
267
260
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
268
261
 
269
 
/* Mark all data in blocks free for reusage */
270
 
 
271
 
static inline void mark_blocks_free(MEM_ROOT* root)
 
262
/**
 
263
 * @brief
 
264
 * Mark all data in blocks free for reusage 
 
265
 */
 
266
void memory::Root::mark_blocks_free()
272
267
{
273
 
  register USED_MEM *next;
274
 
  register USED_MEM **last;
 
268
  memory::internal::UsedMemory *next;
 
269
  memory::internal::UsedMemory **last;
275
270
 
276
271
  /* iterate through (partially) free blocks, mark them free */
277
 
  last= &root->free;
278
 
  for (next= root->free; next; next= *(last= &next->next))
 
272
  last= &free;
 
273
  for (next= free; next; next= *(last= &next->next))
279
274
  {
280
 
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
 
275
    next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
281
276
    TRASH_MEM(next);
282
277
  }
283
278
 
284
279
  /* Combine the free and the used list */
285
 
  *last= next=root->used;
 
280
  *last= next= used;
286
281
 
287
282
  /* now go through the used blocks and mark them free */
288
283
  for (; next; next= next->next)
289
284
  {
290
 
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
 
285
    next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
291
286
    TRASH_MEM(next);
292
287
  }
293
288
 
294
289
  /* Now everything is set; Indicate that nothing is used anymore */
295
 
  root->used= 0;
296
 
  root->first_block_usage= 0;
 
290
  used= 0;
 
291
  first_block_usage= 0;
297
292
}
298
293
 
299
 
 
300
 
/*
301
 
  Deallocate everything used by alloc_root or just move
302
 
  used blocks to free list if called with MY_USED_TO_FREE
303
 
 
304
 
  SYNOPSIS
305
 
    free_root()
306
 
      root              Memory root
307
 
      MyFlags           Flags for what should be freed:
308
 
 
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
311
 
                                preallocated block
312
 
 
313
 
  NOTES
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.
317
 
*/
318
 
 
319
 
void free_root(MEM_ROOT *root, myf MyFlags)
 
294
/**
 
295
 * @brief
 
296
 * Deallocate everything used by memory::alloc_root or just move
 
297
 * used blocks to free list if called with MY_USED_TO_FREE
 
298
 *
 
299
 * @note
 
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.
 
303
 *
 
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
 
308
 *                              preallocated block
 
309
 */
 
310
void memory::Root::free_root(myf MyFlags)
320
311
{
321
 
  register USED_MEM *next,*old;
 
312
  memory::internal::UsedMemory *next,*old;
322
313
 
323
 
  if (MyFlags & MY_MARK_BLOCKS_FREE)
 
314
  if (MyFlags & memory::MARK_BLOCKS_FREE)
324
315
  {
325
 
    mark_blocks_free(root);
 
316
    this->mark_blocks_free();
326
317
    return;
327
318
  }
328
 
  if (!(MyFlags & MY_KEEP_PREALLOC))
329
 
    root->pre_alloc=0;
 
319
  if (!(MyFlags & memory::KEEP_PREALLOC))
 
320
    this->pre_alloc=0;
330
321
 
331
 
  for (next=root->used; next ;)
 
322
  for (next=this->used; next ;)
332
323
  {
333
324
    old=next; next= next->next ;
334
 
    if (old != root->pre_alloc)
335
 
      free(old);
 
325
    if (old != this->pre_alloc)
 
326
      std::free(old);
336
327
  }
337
 
  for (next=root->free ; next ;)
 
328
  for (next=this->free ; next ;)
338
329
  {
339
330
    old=next; next= next->next;
340
 
    if (old != root->pre_alloc)
341
 
      free(old);
342
 
  }
343
 
  root->used=root->free=0;
344
 
  if (root->pre_alloc)
345
 
  {
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);
349
 
    root->free->next=0;
350
 
  }
351
 
  root->block_num= 4;
352
 
  root->first_block_usage= 0;
353
 
  return;
354
 
}
355
 
 
356
 
/*
357
 
  Find block that contains an object and set the pre_alloc to it
358
 
*/
359
 
 
360
 
void set_prealloc_root(MEM_ROOT *root, char *ptr)
361
 
{
362
 
  USED_MEM *next;
363
 
  for (next=root->used; next ; next=next->next)
364
 
  {
365
 
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
366
 
    {
367
 
      root->pre_alloc=next;
368
 
      return;
369
 
    }
370
 
  }
371
 
  for (next=root->free ; next ; next=next->next)
372
 
  {
373
 
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
374
 
    {
375
 
      root->pre_alloc=next;
376
 
      return;
377
 
    }
378
 
  }
379
 
}
380
 
 
381
 
 
382
 
char *strdup_root(MEM_ROOT *root, const char *str)
383
 
{
384
 
  return strmake_root(root, str, strlen(str));
385
 
}
386
 
 
387
 
 
388
 
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
 
331
    if (old != this->pre_alloc)
 
332
      std::free(old);
 
333
  }
 
334
  this->used=this->free=0;
 
335
  if (this->pre_alloc)
 
336
  {
 
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);
 
340
    this->free->next=0;
 
341
  }
 
342
  this->block_num= 4;
 
343
  this->first_block_usage= 0;
 
344
}
 
345
 
 
346
/**
 
347
 * @brief
 
348
 * Duplicate a null-terminated string into memory allocated from within the
 
349
 * specified Root
 
350
 */
 
351
char *memory::Root::strdup_root(const char *str)
 
352
{
 
353
  return strmake_root(str, strlen(str));
 
354
}
 
355
 
 
356
/**
 
357
 * @brief
 
358
 * Copy the (not necessarily null-terminated) string into memory allocated
 
359
 * from within the specified Root
 
360
 *
 
361
 * @details
 
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
 
365
 * this purpose).
 
366
 */
 
367
char *memory::Root::strmake_root(const char *str, size_t len)
389
368
{
390
369
  char *pos;
391
 
  if ((pos=(char *)alloc_root(root,len+1)))
 
370
  if ((pos= (char *)alloc_root(len+1)))
392
371
  {
393
372
    memcpy(pos,str,len);
394
373
    pos[len]=0;
396
375
  return pos;
397
376
}
398
377
 
399
 
 
400
 
void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
 
378
/**
 
379
 * @brief
 
380
 * Duplicate the provided block into memory allocated from within the specified
 
381
 * Root
 
382
 *
 
383
 * @return
 
384
 * non-NULL pointer to a copy of the data if memory could be allocated, otherwise
 
385
 * NULL
 
386
 */
 
387
void *memory::Root::memdup_root(const void *str, size_t len)
401
388
{
402
389
  void *pos;
403
 
  if ((pos=alloc_root(root,len)))
 
390
 
 
391
  if ((pos= this->alloc_root(len)))
404
392
    memcpy(pos,str,len);
 
393
 
405
394
  return pos;
406
395
}
 
396
 
 
397
} /* namespace drizzled */