Drizzled Public API Documentation

hp_create.cc
1 /* Copyright (C) 2000-2006 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 
16 #include "heap_priv.h"
17 #include <drizzled/internal/my_sys.h>
18 #include <drizzled/common.h>
19 #include <drizzled/error.h>
20 
21 #include <string.h>
22 #include <algorithm>
23 
24 using namespace std;
25 using namespace drizzled;
26 
27 static void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
28  uint32_t max_records);
29 
30 static const int FIXED_REC_OVERHEAD = (sizeof(unsigned char));
31 static const int VARIABLE_REC_OVERHEAD = (sizeof(unsigned char**) + ALIGN_SIZE(sizeof(unsigned char)));
32 
33 /* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
34 static const int VARIABLE_MIN_CHUNK_SIZE =
35  ((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1));
36 
37 
38 /* Create a heap table */
39 
40 int heap_create(const char *name, uint32_t keys, HP_KEYDEF *keydef,
41  uint32_t columns,
42  uint32_t key_part_size,
43  uint32_t reclength, uint32_t keys_memory_size,
44  uint32_t max_records, uint32_t min_records,
45  HP_CREATE_INFO *create_info, HP_SHARE **res)
46 {
47  uint32_t i, key_segs, max_length, length;
48  uint32_t max_rows_for_stated_memory;
49  HP_SHARE *share= 0;
50  HA_KEYSEG *keyseg;
51 
52  if (not create_info->internal_table)
53  {
54  THR_LOCK_heap.lock();
55  if ((share= hp_find_named_heap(name)) && share->open_count == 0)
56  {
57  hp_free(share);
58  share= 0;
59  }
60  }
61 
62  if (!share)
63  {
64  size_t chunk_dataspace_length;
65  uint32_t chunk_length;
66  uint32_t fixed_data_length, fixed_column_count;
67  HP_KEYDEF *keyinfo;
68 
69  if (create_info->max_chunk_size)
70  {
71  uint32_t configured_chunk_size= create_info->max_chunk_size;
72 
73  /* User requested variable-size records, let's see if they're possible */
74 
75  if (configured_chunk_size < key_part_size)
76  {
77  /* Eventual chunk_size cannot be smaller than key data,
78  which allows all keys to fit into the first chunk */
79  my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
80  THR_LOCK_heap.unlock();
81  return(ER_CANT_USE_OPTION_HERE);
82  }
83 
84  /* max_chunk_size is near the full reclength, let's use fixed size */
85  chunk_dataspace_length= reclength;
86  }
87  else
88  {
89  /* if max_chunk_size is not specified, put the whole record in one chunk */
90  chunk_dataspace_length= reclength;
91  }
92 
93  {
94  fixed_data_length= reclength;
95  fixed_column_count= columns;
96  }
97 
98  /*
99  We store unsigned char* del_link inside the data area of deleted records,
100  so the data length should be at least sizeof(unsigned char*)
101  */
102  set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
103 
104  {
105  chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
106  }
107 
108  /* Align chunk length to the next pointer */
109  chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
110 
111 
112 
113  for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
114  {
115  memset(&keyinfo->block, 0, sizeof(keyinfo->block));
116  for (uint32_t j= length= 0; j < keyinfo->keysegs; j++)
117  {
118  length+= keyinfo->seg[j].length;
119  if (keyinfo->seg[j].null_bit)
120  {
121  length++;
122  if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
123  keyinfo->flag|= HA_NULL_PART_KEY;
124  }
125  switch (keyinfo->seg[j].type) {
126  case HA_KEYTYPE_LONG_INT:
127  case HA_KEYTYPE_DOUBLE:
128  case HA_KEYTYPE_ULONG_INT:
129  case HA_KEYTYPE_LONGLONG:
130  case HA_KEYTYPE_ULONGLONG:
131  keyinfo->seg[j].flag|= HA_SWAP_KEY;
132  break;
133  case HA_KEYTYPE_VARBINARY1:
134  /* Case-insensitiveness is handled in coll->hash_sort */
135  keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
136  /* fall_through */
137  case HA_KEYTYPE_VARTEXT1:
138  keyinfo->flag|= HA_VAR_LENGTH_KEY;
139  length+= 2;
140  /* Save number of bytes used to store length */
141  keyinfo->seg[j].bit_start= 1;
142  break;
143  case HA_KEYTYPE_VARBINARY2:
144  /* Case-insensitiveness is handled in coll->hash_sort */
145  /* fall_through */
146  case HA_KEYTYPE_VARTEXT2:
147  keyinfo->flag|= HA_VAR_LENGTH_KEY;
148  length+= 2;
149  /* Save number of bytes used to store length */
150  keyinfo->seg[j].bit_start= 2;
151  /*
152  Make future comparison simpler by only having to check for
153  one type
154  */
155  keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
156  break;
157  default:
158  break;
159  }
160  }
161  keyinfo->length= length;
162  if (length > max_length)
163  max_length= length;
164  key_segs+= keyinfo->keysegs;
165  }
166  share= new HP_SHARE;
167 
168  if (keys && !(share->keydef= new HP_KEYDEF[keys]))
169  goto err;
170  if (keys && !(share->keydef->seg= new HA_KEYSEG[key_segs]))
171  goto err;
172 
173  /*
174  Max_records is used for estimating block sizes and for enforcement.
175  Calculate the very maximum number of rows (if everything was one chunk) and
176  then take either that value or configured max_records (pick smallest one)
177  */
178  max_rows_for_stated_memory= (uint32_t)(create_info->max_table_size /
179  (keys_memory_size + chunk_length));
180  max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
181  max_records : max_rows_for_stated_memory);
182 
183  share->key_stat_version= 1;
184  keyseg= keys ? share->keydef->seg : NULL;
185 
186  init_block(&share->recordspace.block, chunk_length, min_records, max_records);
187  /* Fix keys */
188  memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
189  for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
190  {
191  keyinfo->seg= keyseg;
192  memcpy(keyseg, keydef[i].seg,
193  (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194  keyseg+= keydef[i].keysegs;
195  {
196  init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
197  max_records);
198  keyinfo->hash_buckets= 0;
199  }
200  if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
201  share->auto_key= i + 1;
202  }
203  share->min_records= min_records;
204  share->max_records= max_records;
205  share->max_table_size= create_info->max_table_size;
206  share->index_length= 0;
207  share->blength= 1;
208  share->keys= keys;
209  share->max_key_length= max_length;
210  share->column_count= columns;
211  share->changed= 0;
212  share->auto_key= create_info->auto_key;
213  share->auto_key_type= create_info->auto_key_type;
214  share->auto_increment= create_info->auto_increment;
215 
216  share->fixed_data_length= fixed_data_length;
217  share->fixed_column_count= fixed_column_count;
218 
219  share->recordspace.chunk_length= chunk_length;
220  share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
221  share->recordspace.total_data_length= 0;
222 
223  {
224  share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
225  share->recordspace.offset_status= chunk_dataspace_length;
226  }
227 
228  /* Must be allocated separately for rename to work */
229  share->name.append(name);
230  if (!create_info->internal_table)
231  {
232  heap_share_list.push_front(share);
233  }
234  else
235  share->delete_on_close= 1;
236  }
237  if (!create_info->internal_table)
238  THR_LOCK_heap.unlock();
239 
240  *res= share;
241  return(0);
242 
243 err:
244  if (share && share->keydef)
245  delete[] share->keydef->seg;
246  if (share)
247  delete[] share->keydef;
248  delete share;
249  if (not create_info->internal_table)
250  THR_LOCK_heap.unlock();
251  return(1);
252 } /* heap_create */
253 
254 
255 static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
256  uint32_t max_records)
257 {
258  uint32_t recbuffer,records_in_block;
259 
260  max_records= max(min_records,max_records);
261  if (!max_records)
262  max_records= 1000; /* As good as quess as anything */
263 
264  /* we want to start each chunk at 8 bytes boundary, round recbuffer to the next 8 */
265  recbuffer= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
266  records_in_block= max_records / 10;
267  if (records_in_block < 10 && max_records)
268  records_in_block= 10;
269  if (!records_in_block || records_in_block*recbuffer >
270  (internal::my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
271  records_in_block= (internal::my_default_record_cache_size - sizeof(HP_PTRS) *
272  HP_MAX_LEVELS) / recbuffer + 1;
273  block->records_in_block= records_in_block;
274  block->recbuffer= recbuffer;
275  block->last_allocated= 0L;
276 
277  for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
278  {
279  block->level_info[i].records_under_level=
280  (!i ? 1 : i == 1 ? records_in_block :
281  HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
282  }
283 }
284 
285 
286 static inline void heap_try_free(HP_SHARE *share)
287 {
288  if (share->open_count == 0)
289  hp_free(share);
290  else
291  share->delete_on_close= 1;
292 }
293 
294 
295 int heap_delete_table(const char *name)
296 {
297  int result;
298  register HP_SHARE *share;
299 
300  THR_LOCK_heap.lock();
301  if ((share= hp_find_named_heap(name)))
302  {
303  heap_try_free(share);
304  result= 0;
305  }
306  else
307  {
308  result= errno=ENOENT;
309  }
310  THR_LOCK_heap.unlock();
311  return(result);
312 }
313 
314 
315 void hp_free(HP_SHARE *share)
316 {
317  heap_share_list.remove(share); /* If not internal table */
318  hp_clear(share); /* Remove blocks from memory */
319  if (share->keydef)
320  delete[] share->keydef->seg;
321  delete[] share->keydef;
322  delete share;
323 }