~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/memory/root.cc

  • Committer: Mark Atwood
  • Date: 2011-06-22 20:04:22 UTC
  • mfrom: (2318.6.39 rf)
  • Revision ID: me@mark.atwood.name-20110622200422-609npl456o0e5p32
mergeĀ lp:~olafvdspek/drizzle/refactor13

Show diffs side-by-side

added added

removed removed

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