~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
994.2.4 by Monty Taylor
Blast. Fixed some make distcheck issues.
18
#include "mysys/mysys_priv.h"
212.5.39 by Monty Taylor
Phew. Moved my_base and my_global.
19
#include <mystrings/m_string.h>
1 by brian
clean slate
20
1067.4.10 by Nathan Williams
Converted all cmin/cmax usages in the mysys directory to std::min/max.
21
#include <algorithm>
22
23
using namespace std;
1 by brian
clean slate
24
25
/*
26
  Initialize memory root
27
28
  SYNOPSIS
29
    init_alloc_root()
30
      mem_root       - memory root to initialize
31
      block_size     - size of chunks (blocks) used for memory allocation
32
                       (It is external size of chunk i.e. it should include
33
                        memory required for internal structures, thus it
34
                        should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
35
      pre_alloc_size - if non-0, then size of block that should be
36
                       pre-allocated during memory root initialization.
37
38
  DESCRIPTION
39
    This function prepares memory root for further use, sets initial size of
40
    chunk for memory allocation and pre-allocates first block if specified.
41
    Altough error can happen during execution of this function if
42
    pre_alloc_size is non-0 it won't be reported. Instead it will be
43
    reported as error in first alloc_root() on this memory root.
44
*/
45
46
void init_alloc_root(MEM_ROOT *mem_root, size_t block_size,
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
47
		     size_t )
1 by brian
clean slate
48
{
49
  mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
50
  mem_root->min_malloc= 32;
51
  mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
52
  mem_root->error_handler= 0;
53
  mem_root->block_num= 4;			/* We shift this with >>2 */
54
  mem_root->first_block_usage= 0;
55
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
56
  return;
1 by brian
clean slate
57
}
58
59
60
/*
61
  SYNOPSIS
62
    reset_root_defaults()
63
    mem_root        memory root to change defaults of
64
    block_size      new value of block size. Must be greater or equal
65
                    than ALLOC_ROOT_MIN_BLOCK_SIZE (this value is about
66
                    68 bytes and depends on platform and compilation flags)
67
    pre_alloc_size  new size of preallocated block. If not zero,
68
                    must be equal to or greater than block size,
69
                    otherwise means 'no prealloc'.
70
  DESCRIPTION
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
77
void reset_root_defaults(MEM_ROOT *mem_root, size_t block_size,
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
78
                         size_t pre_alloc_size)
1 by brian
clean slate
79
{
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
80
  assert(alloc_root_inited(mem_root));
1 by brian
clean slate
81
82
  mem_root->block_size= block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
83
  if (pre_alloc_size)
84
  {
85
    size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM));
86
    if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size)
87
    {
88
      USED_MEM *mem, **prev= &mem_root->free;
89
      /*
90
        Free unused blocks, so that consequent calls
91
        to reset_root_defaults won't eat away memory.
92
      */
93
      while (*prev)
94
      {
95
        mem= *prev;
96
        if (mem->size == size)
97
        {
98
          /* We found a suitable block, no need to do anything else */
99
          mem_root->pre_alloc= mem;
100
          return;
101
        }
102
        if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size)
103
        {
104
          /* remove block from the list and free it */
105
          *prev= mem->next;
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
106
          free(mem);
1 by brian
clean slate
107
        }
108
        else
109
          prev= &mem->next;
110
      }
111
      /* Allocate new prealloc block and add it to the end of free list */
656.3.1 by Monty Taylor
Got rid of my_once_alloc.
112
      if ((mem= (USED_MEM *) malloc(size)))
1 by brian
clean slate
113
      {
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
114
        mem->size= size;
1 by brian
clean slate
115
        mem->left= pre_alloc_size;
116
        mem->next= *prev;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
117
        *prev= mem_root->pre_alloc= mem;
1 by brian
clean slate
118
      }
119
      else
120
      {
121
        mem_root->pre_alloc= 0;
122
      }
123
    }
124
  }
125
  else
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
126
  {
1 by brian
clean slate
127
    mem_root->pre_alloc= 0;
779.1.27 by Monty Taylor
Got rid of __attribute__((unused)) and the like from the .cc files.
128
  }
1 by brian
clean slate
129
}
130
131
132
void *alloc_root(MEM_ROOT *mem_root, size_t length)
133
{
134
  size_t get_size, block_size;
481 by Brian Aker
Remove all of uchar.
135
  unsigned char* point;
1 by brian
clean slate
136
  register USED_MEM *next= 0;
137
  register USED_MEM **prev;
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
138
  assert(alloc_root_inited(mem_root));
1 by brian
clean slate
139
140
  length= ALIGN_SIZE(length);
141
  if ((*(prev= &mem_root->free)) != NULL)
142
  {
143
    if ((*prev)->left < length &&
144
	mem_root->first_block_usage++ >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP &&
145
	(*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
146
    {
147
      next= *prev;
148
      *prev= next->next;			/* Remove block from list */
149
      next->next= mem_root->used;
150
      mem_root->used= next;
151
      mem_root->first_block_usage= 0;
152
    }
153
    for (next= *prev ; next && next->left < length ; next= next->next)
154
      prev= &next->next;
155
  }
156
  if (! next)
157
  {						/* Time to alloc new block */
158
    block_size= mem_root->block_size * (mem_root->block_num >> 2);
159
    get_size= length+ALIGN_SIZE(sizeof(USED_MEM));
1067.4.10 by Nathan Williams
Converted all cmin/cmax usages in the mysys directory to std::min/max.
160
    get_size= max(get_size, block_size);
1 by brian
clean slate
161
656.3.1 by Monty Taylor
Got rid of my_once_alloc.
162
    if (!(next = (USED_MEM*) malloc(get_size)))
1 by brian
clean slate
163
    {
164
      if (mem_root->error_handler)
165
	(*mem_root->error_handler)();
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
166
      return((void*) 0);                      /* purecov: inspected */
1 by brian
clean slate
167
    }
168
    mem_root->block_num++;
169
    next->next= *prev;
170
    next->size= get_size;
171
    next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
172
    *prev=next;
173
  }
174
481 by Brian Aker
Remove all of uchar.
175
  point= (unsigned char*) ((char*) next+ (next->size-next->left));
1 by brian
clean slate
176
  /*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
177
  if ((next->left-= length) < mem_root->min_malloc)
178
  {						/* Full block */
179
    *prev= next->next;				/* Remove block from list */
180
    next->next= mem_root->used;
181
    mem_root->used= next;
182
    mem_root->first_block_usage= 0;
183
  }
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
184
  return((void*) point);
1 by brian
clean slate
185
}
186
187
188
/*
189
  Allocate many pointers at the same time.
190
191
  DESCRIPTION
192
    ptr1, ptr2, etc all point into big allocated memory area.
193
194
  SYNOPSIS
195
    multi_alloc_root()
196
      root               Memory root
197
      ptr1, length1      Multiple arguments terminated by a NULL pointer
198
      ptr2, length2      ...
199
      ...
200
      NULL
201
202
  RETURN VALUE
203
    A pointer to the beginning of the allocated memory block
204
    in case of success or NULL if out of memory.
205
*/
206
207
void *multi_alloc_root(MEM_ROOT *root, ...)
208
{
209
  va_list args;
210
  char **ptr, *start, *res;
211
  size_t tot_length, length;
212
213
  va_start(args, root);
214
  tot_length= 0;
215
  while ((ptr= va_arg(args, char **)))
216
  {
217
    length= va_arg(args, uint);
218
    tot_length+= ALIGN_SIZE(length);
219
  }
220
  va_end(args);
221
222
  if (!(start= (char*) alloc_root(root, tot_length)))
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
223
    return(0);                            /* purecov: inspected */
1 by brian
clean slate
224
225
  va_start(args, root);
226
  res= start;
227
  while ((ptr= va_arg(args, char **)))
228
  {
229
    *ptr= res;
230
    length= va_arg(args, uint);
231
    res+= ALIGN_SIZE(length);
232
  }
233
  va_end(args);
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
234
  return((void*) start);
1 by brian
clean slate
235
}
236
237
#define TRASH_MEM(X) TRASH(((char*)(X) + ((X)->size-(X)->left)), (X)->left)
238
239
/* Mark all data in blocks free for reusage */
240
241
static inline void mark_blocks_free(MEM_ROOT* root)
242
{
243
  register USED_MEM *next;
244
  register USED_MEM **last;
245
246
  /* iterate through (partially) free blocks, mark them free */
247
  last= &root->free;
248
  for (next= root->free; next; next= *(last= &next->next))
249
  {
250
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
251
    TRASH_MEM(next);
252
  }
253
254
  /* Combine the free and the used list */
255
  *last= next=root->used;
256
257
  /* now go through the used blocks and mark them free */
258
  for (; next; next= next->next)
259
  {
260
    next->left= next->size - ALIGN_SIZE(sizeof(USED_MEM));
261
    TRASH_MEM(next);
262
  }
263
264
  /* Now everything is set; Indicate that nothing is used anymore */
265
  root->used= 0;
266
  root->first_block_usage= 0;
267
}
268
269
270
/*
271
  Deallocate everything used by alloc_root or just move
272
  used blocks to free list if called with MY_USED_TO_FREE
273
274
  SYNOPSIS
275
    free_root()
276
      root		Memory root
277
      MyFlags		Flags for what should be freed:
278
279
        MY_MARK_BLOCKS_FREED	Don't free blocks, just mark them free
280
        MY_KEEP_PREALLOC	If this is not set, then free also the
281
        		        preallocated block
282
283
  NOTES
284
    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.
285
    init_alloc_root() or with a zero:ed block.
1 by brian
clean slate
286
    It's also safe to call this multiple times with the same mem_root.
287
*/
288
289
void free_root(MEM_ROOT *root, myf MyFlags)
290
{
291
  register USED_MEM *next,*old;
292
293
  if (MyFlags & MY_MARK_BLOCKS_FREE)
294
  {
295
    mark_blocks_free(root);
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
296
    return;
1 by brian
clean slate
297
  }
298
  if (!(MyFlags & MY_KEEP_PREALLOC))
299
    root->pre_alloc=0;
300
301
  for (next=root->used; next ;)
302
  {
303
    old=next; next= next->next ;
304
    if (old != root->pre_alloc)
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
305
      free(old);
1 by brian
clean slate
306
  }
307
  for (next=root->free ; next ;)
308
  {
309
    old=next; next= next->next;
310
    if (old != root->pre_alloc)
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
311
      free(old);
1 by brian
clean slate
312
  }
313
  root->used=root->free=0;
314
  if (root->pre_alloc)
315
  {
316
    root->free=root->pre_alloc;
317
    root->free->left=root->pre_alloc->size-ALIGN_SIZE(sizeof(USED_MEM));
318
    TRASH_MEM(root->pre_alloc);
319
    root->free->next=0;
320
  }
321
  root->block_num= 4;
322
  root->first_block_usage= 0;
51.3.20 by Jay Pipes
Phase 6 - Remove DBUG from mysys
323
  return;
1 by brian
clean slate
324
}
325
326
/*
327
  Find block that contains an object and set the pre_alloc to it
328
*/
329
330
void set_prealloc_root(MEM_ROOT *root, char *ptr)
331
{
332
  USED_MEM *next;
333
  for (next=root->used; next ; next=next->next)
334
  {
335
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
336
    {
337
      root->pre_alloc=next;
338
      return;
339
    }
340
  }
341
  for (next=root->free ; next ; next=next->next)
342
  {
343
    if ((char*) next <= ptr && (char*) next + next->size > ptr)
344
    {
345
      root->pre_alloc=next;
346
      return;
347
    }
348
  }
349
}
350
351
352
char *strdup_root(MEM_ROOT *root, const char *str)
353
{
354
  return strmake_root(root, str, strlen(str));
355
}
356
357
358
char *strmake_root(MEM_ROOT *root, const char *str, size_t len)
359
{
360
  char *pos;
575.3.1 by Monty Taylor
Made mysys and mystrings c++. Fixed the resulting bugs the compiler found.
361
  if ((pos=(char *)alloc_root(root,len+1)))
1 by brian
clean slate
362
  {
363
    memcpy(pos,str,len);
364
    pos[len]=0;
365
  }
366
  return pos;
367
}
368
369
370
void *memdup_root(MEM_ROOT *root, const void *str, size_t len)
371
{
575.3.1 by Monty Taylor
Made mysys and mystrings c++. Fixed the resulting bugs the compiler found.
372
  void *pos;
1 by brian
clean slate
373
  if ((pos=alloc_root(root,len)))
374
    memcpy(pos,str,len);
375
  return pos;
376
}