~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to drizzled/memory/root.cc

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2012-06-19 10:46:49 UTC
  • mfrom: (1.1.6)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20120619104649-e2l0ggd4oz3um0f4
Tags: upstream-7.1.36-stable
ImportĀ upstreamĀ versionĀ 7.1.36-stable

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
#include <config.h>
22
22
 
 
23
#include <drizzled/definitions.h>
 
24
#include <drizzled/memory/root.h>
23
25
#include <drizzled/internal/my_sys.h>
24
26
#include <drizzled/internal/m_string.h>
 
27
#include <drizzled/sql_string.h>
25
28
 
26
29
#include <algorithm>
27
30
 
28
31
using namespace std;
29
32
 
30
 
namespace drizzled
31
 
{
 
33
namespace drizzled {
 
34
namespace memory {
32
35
 
33
36
static const unsigned int MAX_BLOCK_TO_DROP= 4096;
34
37
static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
42
45
 * chunk for memory allocation and pre-allocates first block if specified.
43
46
 * Altough error can happen during execution of this function if
44
47
 * 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.
 
48
 * reported as error in first alloc() on this memory root.
46
49
 *
47
50
 * @param  mem_root       memory root to initialize
48
51
 * @param  block_size     size of chunks (blocks) used for memory allocation
49
52
 *                       (It is external size of chunk i.e. it should include
50
53
 *                      memory required for internal structures, thus it
51
 
 *                      should be no less than memory::ROOT_MIN_BLOCK_SIZE)
 
54
 *                      should be no less than ROOT_MIN_BLOCK_SIZE)
52
55
 *
53
56
 */
54
 
void memory::Root::init_alloc_root(size_t block_size_arg)
 
57
void Root::init(size_t block_size_arg)
55
58
{
56
59
  free= used= pre_alloc= 0;
57
60
  min_malloc= 32;
58
 
  block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
59
 
  error_handler= 0;
 
61
  block_size= block_size_arg - ROOT_MIN_BLOCK_SIZE;
60
62
  block_num= 4;                 /* We shift this with >>2 */
61
63
  first_block_usage= 0;
62
64
}
63
65
 
64
 
memory::Root::~Root()
65
 
{
66
 
}
67
 
 
68
 
 
69
66
/**
70
67
 * @details
71
68
 * Function aligns and assigns new value to block size; then it tries to
81
78
 *                        must be equal to or greater than block size,
82
79
 *                        otherwise means 'no prealloc'.
83
80
 */
84
 
void memory::Root::reset_root_defaults(size_t block_size_arg, size_t pre_alloc_size)
 
81
void Root::reset_defaults(size_t block_size_arg, size_t pre_alloc_size)
85
82
{
86
 
  block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
 
83
  block_size= block_size_arg - ROOT_MIN_BLOCK_SIZE;
87
84
  if (pre_alloc_size)
88
85
  {
89
 
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
 
86
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(internal::UsedMemory));
90
87
    if (not pre_alloc || pre_alloc->size != size)
91
88
    {
92
 
      memory::internal::UsedMemory *mem, **prev= &this->free;
 
89
      internal::UsedMemory *mem, **prev= &this->free;
93
90
      /*
94
91
        Free unused blocks, so that consequent calls
95
92
        to reset_root_defaults won't eat away memory.
103
100
          pre_alloc= mem;
104
101
          return;
105
102
        }
106
 
        if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
 
103
        if (mem->left + ALIGN_SIZE(sizeof(internal::UsedMemory)) == mem->size)
107
104
        {
108
105
          /* remove block from the list and free it */
109
106
          *prev= mem->next;
113
110
          prev= &mem->next;
114
111
      }
115
112
      /* Allocate new prealloc block and add it to the end of free list */
116
 
      if ((mem= static_cast<memory::internal::UsedMemory *>(malloc(size))))
117
 
      {
118
 
        mem->size= size;
119
 
        mem->left= pre_alloc_size;
120
 
        mem->next= *prev;
121
 
        *prev= pre_alloc= mem;
122
 
      }
123
 
      else
124
 
      {
125
 
        pre_alloc= 0;
126
 
      }
 
113
      mem= static_cast<internal::UsedMemory *>(malloc(size));
 
114
      mem->size= size;
 
115
      mem->left= pre_alloc_size;
 
116
      mem->next= *prev;
 
117
      *prev= pre_alloc= mem;
127
118
    }
128
119
  }
129
120
  else
138
129
 * obtaining more memory from the heap if necessary
139
130
 *
140
131
 * @pre
141
 
 * mem_root must have been initialised via init_alloc_root()
 
132
 * mem_root must have been initialised via init()
142
133
 *
143
134
 * @param  mem_root  The memory Root to allocate from
144
135
 * @param  length    The size of the block to allocate
146
137
 * @todo Would this be more suitable as a member function on the
147
138
 * Root class?
148
139
 */
149
 
void *memory::Root::alloc_root(size_t length)
 
140
unsigned char* Root::alloc(size_t length)
150
141
{
151
 
  unsigned char* point;
152
 
  memory::internal::UsedMemory *next= NULL;
153
 
  memory::internal::UsedMemory **prev;
 
142
  internal::UsedMemory *next= NULL;
154
143
  assert(alloc_root_inited());
155
144
 
156
145
  length= ALIGN_SIZE(length);
157
 
  if ((*(prev= &this->free)) != NULL)
 
146
  internal::UsedMemory **prev= &this->free;
 
147
  if (*prev)
158
148
  {
159
149
    if ((*prev)->left < length &&
160
150
        this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
166
156
      this->used= next;
167
157
      this->first_block_usage= 0;
168
158
    }
169
 
    for (next= *prev ; next && next->left < length ; next= next->next)
 
159
    for (next= *prev; next && next->left < length; next= next->next)
170
160
      prev= &next->next;
171
161
  }
172
162
  if (! next)
173
163
  {                                             /* Time to alloc new block */
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));
 
164
    size_t tmp_block_size= this->block_size * (this->block_num >> 2);
 
165
    size_t get_size= length+ALIGN_SIZE(sizeof(internal::UsedMemory));
178
166
    get_size= max(get_size, tmp_block_size);
179
167
 
180
 
    if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
181
 
    {
182
 
      if (this->error_handler)
183
 
        (*this->error_handler)();
184
 
      return NULL;
185
 
    }
 
168
    next = static_cast<internal::UsedMemory *>(malloc(get_size));
186
169
    this->block_num++;
187
170
    next->next= *prev;
188
171
    next->size= get_size;
189
 
    next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
 
172
    next->left= get_size-ALIGN_SIZE(sizeof(internal::UsedMemory));
190
173
    *prev=next;
191
174
  }
192
175
 
193
 
  point= (unsigned char*) ((char*) next+ (next->size-next->left));
 
176
  unsigned char* point= (unsigned char*) ((char*) next+ (next->size-next->left));
194
177
  /** @todo next part may be unneeded due to this->first_block_usage counter*/
195
178
  if ((next->left-= length) < this->min_malloc)
196
179
  {                                             /* Full block */
211
194
 * @details
212
195
 * The variable arguments are a list of alternating pointers and lengths,
213
196
 * terminated by a null pointer:
214
 
 * @li <tt>char ** pointer1</tt>
 
197
 * @li <tt>char* * pointer1</tt>
215
198
 * @li <tt>uint length1</tt>
216
 
 * @li <tt>char ** pointer2</tt>
 
199
 * @li <tt>char* * pointer2</tt>
217
200
 * @li <tt>uint length2</tt>
218
201
 * @li <tt>...</tt>
219
202
 * @li <tt>NULL</tt>
226
209
 * A pointer to the beginning of the allocated memory block in case of 
227
210
 * success or NULL if out of memory
228
211
 */
229
 
void *memory::Root::multi_alloc_root(int unused, ...)
 
212
void* Root::multi_alloc(int unused, ...)
230
213
{
231
214
  va_list args;
232
 
  char **ptr, *start, *res;
 
215
  char* *ptr, *start, *res;
233
216
  size_t tot_length, length;
234
217
 
235
218
  (void)unused; // For some reason Sun Studio registers unused as not used.
236
219
  va_start(args, unused);
237
220
  tot_length= 0;
238
 
  while ((ptr= va_arg(args, char **)))
 
221
  while ((ptr= va_arg(args, char* *)))
239
222
  {
240
223
    length= va_arg(args, uint);
241
224
    tot_length+= ALIGN_SIZE(length);
242
225
  }
243
226
  va_end(args);
244
227
 
245
 
  if (!(start= (char*) this->alloc_root(tot_length)))
246
 
    return(0);
 
228
  start= (char*) this->alloc(tot_length);
247
229
 
248
230
  va_start(args, unused);
249
231
  res= start;
250
 
  while ((ptr= va_arg(args, char **)))
 
232
  while ((ptr= va_arg(args, char* *)))
251
233
  {
252
234
    *ptr= res;
253
235
    length= va_arg(args, uint);
257
239
  return((void*) start);
258
240
}
259
241
 
260
 
static void trash_mem(memory::internal::UsedMemory *)
261
 
{
262
 
  TRASH(((char*)(x) + (x->size - x->left)), x->left);
263
 
}
264
 
 
265
242
/**
266
243
 * @brief
267
244
 * Mark all data in blocks free for reusage 
268
245
 */
269
 
void memory::Root::mark_blocks_free()
 
246
void Root::mark_blocks_free()
270
247
{
271
 
  memory::internal::UsedMemory *next;
272
 
  memory::internal::UsedMemory **last;
 
248
  internal::UsedMemory *next;
 
249
  internal::UsedMemory **last;
273
250
 
274
251
  /* iterate through (partially) free blocks, mark them free */
275
252
  last= &free;
276
253
  for (next= free; next; next= *(last= &next->next))
277
254
  {
278
 
    next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
279
 
    trash_mem(next);
 
255
    next->left= next->size - ALIGN_SIZE(sizeof(internal::UsedMemory));
280
256
  }
281
257
 
282
258
  /* Combine the free and the used list */
285
261
  /* now go through the used blocks and mark them free */
286
262
  for (; next; next= next->next)
287
263
  {
288
 
    next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
289
 
    trash_mem(next);
 
264
    next->left= next->size - ALIGN_SIZE(sizeof(internal::UsedMemory));
290
265
  }
291
266
 
292
267
  /* Now everything is set; Indicate that nothing is used anymore */
296
271
 
297
272
/**
298
273
 * @brief
299
 
 * Deallocate everything used by memory::alloc_root or just move
 
274
 * Deallocate everything used by alloc_root or just move
300
275
 * used blocks to free list if called with MY_USED_TO_FREE
301
276
 *
302
277
 * @note
303
278
 * One can call this function either with root block initialised with
304
 
 * init_alloc_root() or with a zero:ed block.
 
279
 * init() or with a zero:ed block.
305
280
 * It's also safe to call this multiple times with the same mem_root.
306
281
 *
307
282
 * @param   root     Memory root
310
285
 *   @li   KEEP_PREALLOC        If this is not set, then free also the
311
286
 *                              preallocated block
312
287
 */
313
 
void memory::Root::free_root(myf MyFlags)
 
288
void Root::free_root(myf MyFlags)
314
289
{
315
 
  memory::internal::UsedMemory *next,*old;
316
 
 
317
 
  if (MyFlags & memory::MARK_BLOCKS_FREE)
 
290
  if (MyFlags & MARK_BLOCKS_FREE)
318
291
  {
319
292
    this->mark_blocks_free();
320
293
    return;
321
294
  }
322
 
  if (!(MyFlags & memory::KEEP_PREALLOC))
 
295
  if (!(MyFlags & KEEP_PREALLOC))
323
296
    this->pre_alloc=0;
324
297
 
325
 
  for (next=this->used; next ;)
 
298
  for (internal::UsedMemory* next= this->used; next;)
326
299
  {
327
 
    old=next; next= next->next ;
 
300
    internal::UsedMemory* old =next; 
 
301
    next= next->next;
328
302
    if (old != this->pre_alloc)
329
303
      std::free(old);
330
304
  }
331
 
  for (next=this->free ; next ;)
 
305
  for (internal::UsedMemory* next=this->free; next;)
332
306
  {
333
 
    old=next; next= next->next;
 
307
    internal::UsedMemory* old= next; 
 
308
    next= next->next;
334
309
    if (old != this->pre_alloc)
335
310
      std::free(old);
336
311
  }
338
313
  if (this->pre_alloc)
339
314
  {
340
315
    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);
 
316
    this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(internal::UsedMemory));
343
317
    this->free->next=0;
344
318
  }
345
319
  this->block_num= 4;
351
325
 * Duplicate a null-terminated string into memory allocated from within the
352
326
 * specified Root
353
327
 */
354
 
char *memory::Root::strdup_root(const char *str)
 
328
char* Root::strdup(const char* str)
355
329
{
356
 
  return strmake_root(str, strlen(str));
 
330
  return strdup(str, strlen(str));
357
331
}
358
332
 
359
333
/**
367
341
 * even if the original string wasn't (one additional byte is allocated for
368
342
 * this purpose).
369
343
 */
370
 
char *memory::Root::strmake_root(const char *str, size_t len)
 
344
char* Root::strdup(const char* str, size_t len)
371
345
{
372
 
  char *pos;
373
 
  if ((pos= (char *)alloc_root(len+1)))
374
 
  {
375
 
    memcpy(pos,str,len);
376
 
    pos[len]=0;
377
 
  }
 
346
  char* pos= (char*)alloc(len + 1);
 
347
  memcpy(pos, str, len);
 
348
  pos[len]= 0;
378
349
  return pos;
379
350
}
380
351
 
 
352
char* Root::strdup(str_ref v)
 
353
{
 
354
  return strdup(v.data(), v.size());
 
355
}
 
356
 
381
357
/**
382
358
 * @brief
383
359
 * Duplicate the provided block into memory allocated from within the specified
387
363
 * non-NULL pointer to a copy of the data if memory could be allocated, otherwise
388
364
 * NULL
389
365
 */
390
 
void *memory::Root::memdup_root(const void *str, size_t len)
 
366
void* Root::memdup(const void* str, size_t len)
391
367
{
392
 
  void *pos;
393
 
 
394
 
  if ((pos= this->alloc_root(len)))
395
 
    memcpy(pos,str,len);
396
 
 
 
368
  void* pos= alloc(len);
 
369
  memcpy(pos, str, len);
397
370
  return pos;
398
371
}
399
372
 
 
373
}
400
374
} /* namespace drizzled */