~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/memory/root.cc

  • Committer: mordred
  • Date: 2010-04-20 00:04:22 UTC
  • mfrom: (1491 bad-staging)
  • mto: This revision was merged to the branch mainline in revision 1498.
  • Revision ID: mordred@orisndriz09-20100420000422-if6mil1596804mrj
Merged up with build.

Show diffs side-by-side

added added

removed removed

Lines of Context:
51
51
 *                      should be no less than memory::ROOT_MIN_BLOCK_SIZE)
52
52
 *
53
53
 */
54
 
void memory::init_alloc_root(memory::Root *mem_root, size_t block_size)
 
54
void memory::Root::init_alloc_root(size_t block_size_arg)
55
55
{
56
 
  mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
57
 
  mem_root->min_malloc= 32;
58
 
  mem_root->block_size= block_size - memory::ROOT_MIN_BLOCK_SIZE;
59
 
  mem_root->error_handler= 0;
60
 
  mem_root->block_num= 4;                       /* We shift this with >>2 */
61
 
  mem_root->first_block_usage= 0;
62
 
 
63
 
  return;
 
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;
64
62
}
65
63
 
66
64
 
79
77
 *                        must be equal to or greater than block size,
80
78
 *                        otherwise means 'no prealloc'.
81
79
 */
82
 
void memory::reset_root_defaults(memory::Root *mem_root, size_t block_size,
83
 
                                 size_t pre_alloc_size)
 
80
void memory::Root::reset_root_defaults(size_t block_size_arg, size_t pre_alloc_size)
84
81
{
85
 
  assert(alloc_root_inited(mem_root));
86
 
 
87
 
  mem_root->block_size= block_size - memory::ROOT_MIN_BLOCK_SIZE;
 
82
  block_size= block_size_arg - memory::ROOT_MIN_BLOCK_SIZE;
88
83
  if (pre_alloc_size)
89
84
  {
90
85
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
91
 
    if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
 
86
    if (not pre_alloc || pre_alloc->size != size)
92
87
    {
93
 
      memory::internal::UsedMemory *mem, **prev= &mem_root->free;
 
88
      memory::internal::UsedMemory *mem, **prev= &this->free;
94
89
      /*
95
90
        Free unused blocks, so that consequent calls
96
91
        to reset_root_defaults won't eat away memory.
101
96
        if (mem->size == size)
102
97
        {
103
98
          /* We found a suitable block, no need to do anything else */
104
 
          mem_root->pre_alloc= mem;
 
99
          pre_alloc= mem;
105
100
          return;
106
101
        }
107
102
        if (mem->left + ALIGN_SIZE(sizeof(memory::internal::UsedMemory)) == mem->size)
108
103
        {
109
104
          /* remove block from the list and free it */
110
105
          *prev= mem->next;
111
 
          free(mem);
 
106
          std::free(mem);
112
107
        }
113
108
        else
114
109
          prev= &mem->next;
119
114
        mem->size= size;
120
115
        mem->left= pre_alloc_size;
121
116
        mem->next= *prev;
122
 
        *prev= mem_root->pre_alloc= mem;
 
117
        *prev= pre_alloc= mem;
123
118
      }
124
119
      else
125
120
      {
126
 
        mem_root->pre_alloc= 0;
 
121
        pre_alloc= 0;
127
122
      }
128
123
    }
129
124
  }
130
125
  else
131
126
  {
132
 
    mem_root->pre_alloc= 0;
 
127
    pre_alloc= 0;
133
128
  }
134
129
}
135
130
 
147
142
 * @todo Would this be more suitable as a member function on the
148
143
 * Root class?
149
144
 */
150
 
void *memory::alloc_root(memory::Root *mem_root, size_t length)
 
145
void *memory::Root::alloc_root(size_t length)
151
146
{
152
 
  size_t get_size, block_size;
153
147
  unsigned char* point;
154
148
  memory::internal::UsedMemory *next= NULL;
155
149
  memory::internal::UsedMemory **prev;
156
 
  assert(alloc_root_inited(mem_root));
 
150
  assert(alloc_root_inited());
157
151
 
158
152
  length= ALIGN_SIZE(length);
159
 
  if ((*(prev= &mem_root->free)) != NULL)
 
153
  if ((*(prev= &this->free)) != NULL)
160
154
  {
161
155
    if ((*prev)->left < length &&
162
 
        mem_root->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
 
156
        this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
163
157
        (*prev)->left < MAX_BLOCK_TO_DROP)
164
158
    {
165
159
      next= *prev;
166
160
      *prev= next->next;                        /* Remove block from list */
167
 
      next->next= mem_root->used;
168
 
      mem_root->used= next;
169
 
      mem_root->first_block_usage= 0;
 
161
      next->next= this->used;
 
162
      this->used= next;
 
163
      this->first_block_usage= 0;
170
164
    }
171
165
    for (next= *prev ; next && next->left < length ; next= next->next)
172
166
      prev= &next->next;
173
167
  }
174
168
  if (! next)
175
169
  {                                             /* Time to alloc new block */
176
 
    block_size= mem_root->block_size * (mem_root->block_num >> 2);
 
170
    size_t get_size, tmp_block_size;
 
171
 
 
172
    tmp_block_size= this->block_size * (this->block_num >> 2);
177
173
    get_size= length+ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
178
 
    get_size= max(get_size, block_size);
 
174
    get_size= max(get_size, tmp_block_size);
179
175
 
180
176
    if (!(next = static_cast<memory::internal::UsedMemory *>(malloc(get_size))))
181
177
    {
182
 
      if (mem_root->error_handler)
183
 
        (*mem_root->error_handler)();
 
178
      if (this->error_handler)
 
179
        (*this->error_handler)();
184
180
      return NULL;
185
181
    }
186
 
    mem_root->block_num++;
 
182
    this->block_num++;
187
183
    next->next= *prev;
188
184
    next->size= get_size;
189
185
    next->left= get_size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
191
187
  }
192
188
 
193
189
  point= (unsigned char*) ((char*) next+ (next->size-next->left));
194
 
  /** @todo next part may be unneeded due to mem_root->first_block_usage counter*/
195
 
  if ((next->left-= length) < mem_root->min_malloc)
 
190
  /** @todo next part may be unneeded due to this->first_block_usage counter*/
 
191
  if ((next->left-= length) < this->min_malloc)
196
192
  {                                             /* Full block */
197
193
    *prev= next->next;                          /* Remove block from list */
198
 
    next->next= mem_root->used;
199
 
    mem_root->used= next;
200
 
    mem_root->first_block_usage= 0;
 
194
    next->next= this->used;
 
195
    this->used= next;
 
196
    this->first_block_usage= 0;
201
197
  }
202
198
 
203
199
  return point;
241
237
  }
242
238
  va_end(args);
243
239
 
244
 
  if (!(start= (char*) memory::alloc_root(root, tot_length)))
 
240
  if (!(start= (char*) root->alloc_root(tot_length)))
245
241
    return(0);
246
242
 
247
243
  va_start(args, root);
262
258
 * @brief
263
259
 * Mark all data in blocks free for reusage 
264
260
 */
265
 
static inline void mark_blocks_free(memory::Root* root)
 
261
void memory::Root::mark_blocks_free()
266
262
{
267
263
  memory::internal::UsedMemory *next;
268
264
  memory::internal::UsedMemory **last;
269
265
 
270
266
  /* iterate through (partially) free blocks, mark them free */
271
 
  last= &root->free;
272
 
  for (next= root->free; next; next= *(last= &next->next))
 
267
  last= &free;
 
268
  for (next= free; next; next= *(last= &next->next))
273
269
  {
274
270
    next->left= next->size - ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
275
271
    TRASH_MEM(next);
276
272
  }
277
273
 
278
274
  /* Combine the free and the used list */
279
 
  *last= next=root->used;
 
275
  *last= next= used;
280
276
 
281
277
  /* now go through the used blocks and mark them free */
282
278
  for (; next; next= next->next)
286
282
  }
287
283
 
288
284
  /* Now everything is set; Indicate that nothing is used anymore */
289
 
  root->used= 0;
290
 
  root->first_block_usage= 0;
 
285
  used= 0;
 
286
  first_block_usage= 0;
291
287
}
292
288
 
293
289
/**
306
302
 *   @li   KEEP_PREALLOC        If this is not set, then free also the
307
303
 *                              preallocated block
308
304
 */
309
 
void memory::free_root(memory::Root *root, myf MyFlags)
 
305
void memory::Root::free_root(myf MyFlags)
310
306
{
311
307
  memory::internal::UsedMemory *next,*old;
312
308
 
313
309
  if (MyFlags & memory::MARK_BLOCKS_FREE)
314
310
  {
315
 
    mark_blocks_free(root);
 
311
    this->mark_blocks_free();
316
312
    return;
317
313
  }
318
314
  if (!(MyFlags & memory::KEEP_PREALLOC))
319
 
    root->pre_alloc=0;
 
315
    this->pre_alloc=0;
320
316
 
321
 
  for (next=root->used; next ;)
 
317
  for (next=this->used; next ;)
322
318
  {
323
319
    old=next; next= next->next ;
324
 
    if (old != root->pre_alloc)
325
 
      free(old);
 
320
    if (old != this->pre_alloc)
 
321
      std::free(old);
326
322
  }
327
 
  for (next=root->free ; next ;)
 
323
  for (next=this->free ; next ;)
328
324
  {
329
325
    old=next; next= next->next;
330
 
    if (old != root->pre_alloc)
331
 
      free(old);
332
 
  }
333
 
  root->used=root->free=0;
334
 
  if (root->pre_alloc)
335
 
  {
336
 
    root->free=root->pre_alloc;
337
 
    root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
338
 
    TRASH_MEM(root->pre_alloc);
339
 
    root->free->next=0;
340
 
  }
341
 
  root->block_num= 4;
342
 
  root->first_block_usage= 0;
343
 
  return;
344
 
}
345
 
 
346
 
/**
347
 
 * @brief
348
 
 * Find block that contains an object and set the pre_alloc to it
349
 
 */
350
 
void memory::set_prealloc_root(memory::Root *root, char *ptr)
351
 
{
352
 
  memory::internal::UsedMemory *next;
353
 
  for (next=root->used; next ; next=next->next)
354
 
  {
355
 
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
356
 
    {
357
 
      root->pre_alloc=next;
358
 
      return;
359
 
    }
360
 
  }
361
 
  for (next=root->free ; next ; next=next->next)
362
 
  {
363
 
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
364
 
    {
365
 
      root->pre_alloc=next;
366
 
      return;
367
 
    }
368
 
  }
 
326
    if (old != this->pre_alloc)
 
327
      std::free(old);
 
328
  }
 
329
  this->used=this->free=0;
 
330
  if (this->pre_alloc)
 
331
  {
 
332
    this->free=this->pre_alloc;
 
333
    this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(memory::internal::UsedMemory));
 
334
    TRASH_MEM(this->pre_alloc);
 
335
    this->free->next=0;
 
336
  }
 
337
  this->block_num= 4;
 
338
  this->first_block_usage= 0;
369
339
}
370
340
 
371
341
/**
373
343
 * Duplicate a null-terminated string into memory allocated from within the
374
344
 * specified Root
375
345
 */
376
 
char *memory::strdup_root(memory::Root *root, const char *str)
 
346
char *memory::Root::strdup_root(const char *str)
377
347
{
378
 
  return strmake_root(root, str, strlen(str));
 
348
  return strmake_root(str, strlen(str));
379
349
}
380
350
 
381
351
/**
389
359
 * even if the original string wasn't (one additional byte is allocated for
390
360
 * this purpose).
391
361
 */
392
 
char *memory::strmake_root(memory::Root *root, const char *str, size_t len)
 
362
char *memory::Root::strmake_root(const char *str, size_t len)
393
363
{
394
364
  char *pos;
395
 
  if ((pos=(char *)memory::alloc_root(root,len+1)))
 
365
  if ((pos= (char *)alloc_root(len+1)))
396
366
  {
397
367
    memcpy(pos,str,len);
398
368
    pos[len]=0;
409
379
 * non-NULL pointer to a copy of the data if memory could be allocated, otherwise
410
380
 * NULL
411
381
 */
412
 
void *memory::memdup_root(memory::Root *root, const void *str, size_t len)
 
382
void *memory::Root::memdup_root(const void *str, size_t len)
413
383
{
414
384
  void *pos;
415
 
  if ((pos=memory::alloc_root(root,len)))
 
385
 
 
386
  if ((pos= this->alloc_root(len)))
416
387
    memcpy(pos,str,len);
 
388
 
417
389
  return pos;
418
390
}
419
391