Drizzled Public API Documentation

root.cc
Go to the documentation of this file.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
21 #include <config.h>
22 
23 #include <drizzled/definitions.h>
24 #include <drizzled/memory/root.h>
25 #include <drizzled/internal/my_sys.h>
26 #include <drizzled/internal/m_string.h>
27 #include <drizzled/sql_string.h>
28 
29 #include <algorithm>
30 
31 using namespace std;
32 
33 namespace drizzled {
34 namespace memory {
35 
36 static const unsigned int MAX_BLOCK_TO_DROP= 4096;
37 static const unsigned int MAX_BLOCK_USAGE_BEFORE_DROP= 10;
38 
57 void Root::init(size_t block_size_arg)
58 {
59  free= used= pre_alloc= 0;
60  min_malloc= 32;
61  block_size= block_size_arg - ROOT_MIN_BLOCK_SIZE;
62  block_num= 4; /* We shift this with >>2 */
63  first_block_usage= 0;
64 }
65 
81 void Root::reset_defaults(size_t block_size_arg, size_t pre_alloc_size)
82 {
83  block_size= block_size_arg - ROOT_MIN_BLOCK_SIZE;
84  if (pre_alloc_size)
85  {
86  size_t size= pre_alloc_size + ALIGN_SIZE(sizeof(internal::UsedMemory));
87  if (not pre_alloc || pre_alloc->size != size)
88  {
89  internal::UsedMemory *mem, **prev= &this->free;
90  /*
91  Free unused blocks, so that consequent calls
92  to reset_root_defaults won't eat away memory.
93  */
94  while (*prev)
95  {
96  mem= *prev;
97  if (mem->size == size)
98  {
99  /* We found a suitable block, no need to do anything else */
100  pre_alloc= mem;
101  return;
102  }
103  if (mem->left + ALIGN_SIZE(sizeof(internal::UsedMemory)) == mem->size)
104  {
105  /* remove block from the list and free it */
106  *prev= mem->next;
107  std::free(mem);
108  }
109  else
110  prev= &mem->next;
111  }
112  /* Allocate new prealloc block and add it to the end of free list */
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;
118  }
119  }
120  else
121  {
122  pre_alloc= 0;
123  }
124 }
125 
140 unsigned char* Root::alloc(size_t length)
141 {
142  internal::UsedMemory *next= NULL;
143  assert(alloc_root_inited());
144 
145  length= ALIGN_SIZE(length);
146  internal::UsedMemory **prev= &this->free;
147  if (*prev)
148  {
149  if ((*prev)->left < length &&
150  this->first_block_usage++ >= MAX_BLOCK_USAGE_BEFORE_DROP &&
151  (*prev)->left < MAX_BLOCK_TO_DROP)
152  {
153  next= *prev;
154  *prev= next->next; /* Remove block from list */
155  next->next= this->used;
156  this->used= next;
157  this->first_block_usage= 0;
158  }
159  for (next= *prev; next && next->left < length; next= next->next)
160  prev= &next->next;
161  }
162  if (! next)
163  { /* Time to alloc new block */
164  size_t tmp_block_size= this->block_size * (this->block_num >> 2);
165  size_t get_size= length+ALIGN_SIZE(sizeof(internal::UsedMemory));
166  get_size= max(get_size, tmp_block_size);
167 
168  next = static_cast<internal::UsedMemory *>(malloc(get_size));
169  this->block_num++;
170  next->next= *prev;
171  next->size= get_size;
172  next->left= get_size-ALIGN_SIZE(sizeof(internal::UsedMemory));
173  *prev=next;
174  }
175 
176  unsigned char* point= (unsigned char*) ((char*) next+ (next->size-next->left));
178  if ((next->left-= length) < this->min_malloc)
179  { /* Full block */
180  *prev= next->next; /* Remove block from list */
181  next->next= this->used;
182  this->used= next;
183  this->first_block_usage= 0;
184  }
185 
186  return point;
187 }
188 
189 
212 void* Root::multi_alloc(int unused, ...)
213 {
214  va_list args;
215  char* *ptr, *start, *res;
216  size_t tot_length, length;
217 
218  (void)unused; // For some reason Sun Studio registers unused as not used.
219  va_start(args, unused);
220  tot_length= 0;
221  while ((ptr= va_arg(args, char* *)))
222  {
223  length= va_arg(args, uint);
224  tot_length+= ALIGN_SIZE(length);
225  }
226  va_end(args);
227 
228  start= (char*) this->alloc(tot_length);
229 
230  va_start(args, unused);
231  res= start;
232  while ((ptr= va_arg(args, char* *)))
233  {
234  *ptr= res;
235  length= va_arg(args, uint);
236  res+= ALIGN_SIZE(length);
237  }
238  va_end(args);
239  return((void*) start);
240 }
241 
246 void Root::mark_blocks_free()
247 {
248  internal::UsedMemory *next;
249  internal::UsedMemory **last;
250 
251  /* iterate through (partially) free blocks, mark them free */
252  last= &free;
253  for (next= free; next; next= *(last= &next->next))
254  {
255  next->left= next->size - ALIGN_SIZE(sizeof(internal::UsedMemory));
256  }
257 
258  /* Combine the free and the used list */
259  *last= next= used;
260 
261  /* now go through the used blocks and mark them free */
262  for (; next; next= next->next)
263  {
264  next->left= next->size - ALIGN_SIZE(sizeof(internal::UsedMemory));
265  }
266 
267  /* Now everything is set; Indicate that nothing is used anymore */
268  used= 0;
269  first_block_usage= 0;
270 }
271 
288 void Root::free_root(myf MyFlags)
289 {
290  if (MyFlags & MARK_BLOCKS_FREE)
291  {
292  this->mark_blocks_free();
293  return;
294  }
295  if (!(MyFlags & KEEP_PREALLOC))
296  this->pre_alloc=0;
297 
298  for (internal::UsedMemory* next= this->used; next;)
299  {
300  internal::UsedMemory* old =next;
301  next= next->next;
302  if (old != this->pre_alloc)
303  std::free(old);
304  }
305  for (internal::UsedMemory* next=this->free; next;)
306  {
307  internal::UsedMemory* old= next;
308  next= next->next;
309  if (old != this->pre_alloc)
310  std::free(old);
311  }
312  this->used=this->free=0;
313  if (this->pre_alloc)
314  {
315  this->free=this->pre_alloc;
316  this->free->left=this->pre_alloc->size-ALIGN_SIZE(sizeof(internal::UsedMemory));
317  this->free->next=0;
318  }
319  this->block_num= 4;
320  this->first_block_usage= 0;
321 }
322 
328 char* Root::strdup(const char* str)
329 {
330  return strdup(str, strlen(str));
331 }
332 
344 char* Root::strdup(const char* str, size_t len)
345 {
346  char* pos= (char*)alloc(len + 1);
347  memcpy(pos, str, len);
348  pos[len]= 0;
349  return pos;
350 }
351 
352 char* Root::strdup(str_ref v)
353 {
354  return strdup(v.data(), v.size());
355 }
356 
366 void* Root::memdup(const void* str, size_t len)
367 {
368  void* pos= alloc(len);
369  memcpy(pos, str, len);
370  return pos;
371 }
372 
373 }
374 } /* namespace drizzled */
Memory root declarations.