~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
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
212.5.39 by Monty Taylor
Phew. Moved my_base and my_global.
18
#include <mystrings/m_string.h>
1 by brian
clean slate
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
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
68
  return;
1 by brian
clean slate
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
{
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
92
  assert(alloc_root_inited(mem_root));
1 by brian
clean slate
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;
102
      /*
103
        Free unused blocks, so that consequent calls
104
        to reset_root_defaults won't eat away memory.
105
      */
106
      while (*prev)
107
      {
108
        mem= *prev;
109
        if (mem->size == size)
110
        {
111
          /* We found a suitable block, no need to do anything else */
112
          mem_root->pre_alloc= mem;
113
          return;
114
        }
115
        if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
116
        {
117
          /* remove block from the list and free it */
118
          *prev= mem->next;
119
          my_free(mem, MYF(0));
120
        }
121
        else
122
          prev= &mem->next;
123
      }
124
      /* Allocate new prealloc block and add it to the end of free list */
125
      if ((mem= (USED_MEM *) my_malloc(size, MYF(0))))
126
      {
127
        mem->size= size; 
128
        mem->left= pre_alloc_size;
129
        mem->next= *prev;
130
        *prev= mem_root->pre_alloc= mem; 
131
      }
132
      else
133
      {
134
        mem_root->pre_alloc= 0;
135
      }
136
    }
137
  }
138
  else
139
#endif
140
    mem_root->pre_alloc= 0;
141
}
142
143
144
void *alloc_root(MEM_ROOT *mem_root, size_t length)
145
{
146
#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
147
  register USED_MEM *next;
148
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
149
  assert(alloc_root_inited(mem_root));
1 by brian
clean slate
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)();
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
156
    return((uchar*) 0);			/* purecov: inspected */
1 by brian
clean slate
157
  }
158
  next->next= mem_root->used;
159
  next->size= length;
160
  mem_root->used= next;
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
161
  return((uchar*) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM))));
1 by brian
clean slate
162
#else
163
  size_t get_size, block_size;
164
  uchar* point;
165
  register USED_MEM *next= 0;
166
  register USED_MEM **prev;
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
167
  assert(alloc_root_inited(mem_root));
1 by brian
clean slate
168
169
  length= ALIGN_SIZE(length);
170
  if ((*(prev= &mem_root->free)) != NULL)
171
  {
172
    if ((*prev)->left < length &&
173
	mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
174
	(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
175
    {
176
      next= *prev;
177
      *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;
181
    }
182
    for (next= *prev ; next && next->left < length ; next= next->next)
183
      prev= &next->next;
184
  }
185
  if (! next)
186
  {						/* 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= max(get_size, block_size);
190
191
    if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | ME_FATALERROR))))
192
    {
193
      if (mem_root->error_handler)
194
	(*mem_root->error_handler)();
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
195
      return((void*) 0);                      /* purecov: inspected */
1 by brian
clean slate
196
    }
197
    mem_root->block_num++;
198
    next->next= *prev;
199
    next->size= get_size;
200
    next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
201
    *prev=next;
202
  }
203
204
  point= (uchar*) ((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)
207
  {						/* Full block */
208
    *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;
212
  }
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
213
  return((void*) point);
1 by brian
clean slate
214
#endif
215
}
216
217
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, ...)
238
{
239
  va_list args;
240
  char **ptr, *start, *res;
241
  size_t tot_length, length;
242
243
  va_start(args, root);
244
  tot_length= 0;
245
  while ((ptr= va_arg(args, char **)))
246
  {
247
    length= va_arg(args, uint);
248
    tot_length+= ALIGN_SIZE(length);
249
  }
250
  va_end(args);
251
252
  if (!(start= (char*) alloc_root(root, tot_length)))
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
253
    return(0);                            /* purecov: inspected */
1 by brian
clean slate
254
255
  va_start(args, root);
256
  res= start;
257
  while ((ptr= va_arg(args, char **)))
258
  {
259
    *ptr= res;
260
    length= va_arg(args, uint);
261
    res+= ALIGN_SIZE(length);
262
  }
263
  va_end(args);
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
264
  return((void*) start);
1 by brian
clean slate
265
}
266
267
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
268
269
/* Mark all data in blocks free for reusage */
270
271
static inline void mark_blocks_free(MEM_ROOT* root)
272
{
273
  register USED_MEM *next;
274
  register USED_MEM **last;
275
276
  /* iterate through (partially) free blocks, mark them free */
277
  last= &root->free;
278
  for (next= root->free; next; next= *(last= &next->next))
279
  {
280
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
281
    TRASH_MEM(next);
282
  }
283
284
  /* Combine the free and the used list */
285
  *last= next=root->used;
286
287
  /* now go through the used blocks and mark them free */
288
  for (; next; next= next->next)
289
  {
290
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
291
    TRASH_MEM(next);
292
  }
293
294
  /* Now everything is set; Indicate that nothing is used anymore */
295
  root->used= 0;
296
  root->first_block_usage= 0;
297
}
298
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
212.6.1 by Mats Kindahl
Replacing all bzero() calls with memset() calls and removing the bzero.c file.
315
    init_alloc_root() or with a zero:ed block.
1 by brian
clean slate
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)
320
{
321
  register USED_MEM *next,*old;
322
323
  if (MyFlags & MY_MARK_BLOCKS_FREE)
324
  {
325
    mark_blocks_free(root);
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
326
    return;
1 by brian
clean slate
327
  }
328
  if (!(MyFlags & MY_KEEP_PREALLOC))
329
    root->pre_alloc=0;
330
331
  for (next=root->used; next ;)
332
  {
333
    old=next; next= next->next ;
334
    if (old != root->pre_alloc)
335
      my_free(old,MYF(0));
336
  }
337
  for (next=root->free ; next ;)
338
  {
339
    old=next; next= next->next;
340
    if (old != root->pre_alloc)
341
      my_free(old,MYF(0));
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;
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
353
  return;
1 by brian
clean slate
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)
389
{
390
  char *pos;
391
  if ((pos=alloc_root(root,len+1)))
392
  {
393
    memcpy(pos,str,len);
394
    pos[len]=0;
395
  }
396
  return pos;
397
}
398
399
400
void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
401
{
402
  char *pos;
403
  if ((pos=alloc_root(root,len)))
404
    memcpy(pos,str,len);
405
  return pos;
406
}