MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
hp_create.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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 "heapdef.h"
17 
18 static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2);
19 static void init_block(HP_BLOCK *block,uint reclength,ulong min_records,
20  ulong max_records);
21 
22 /* Create a heap table */
23 
24 int heap_create(const char *name, HP_CREATE_INFO *create_info,
25  HP_SHARE **res, my_bool *created_new_share)
26 {
27  uint i, j, key_segs, max_length, length;
28  HP_SHARE *share= 0;
29  HA_KEYSEG *keyseg;
30  HP_KEYDEF *keydef= create_info->keydef;
31  uint reclength= create_info->reclength;
32  uint keys= create_info->keys;
33  ulong min_records= create_info->min_records;
34  ulong max_records= create_info->max_records;
35  DBUG_ENTER("heap_create");
36 
37  if (!create_info->internal_table)
38  {
39  mysql_mutex_lock(&THR_LOCK_heap);
40  share= hp_find_named_heap(name);
41  if (share && share->open_count == 0)
42  {
43  hp_free(share);
44  share= 0;
45  }
46  }
47  *created_new_share= (share == NULL);
48 
49  if (!share)
50  {
51  HP_KEYDEF *keyinfo;
52  DBUG_PRINT("info",("Initializing new table"));
53 
54  /*
55  We have to store sometimes uchar* del_link in records,
56  so the record length should be at least sizeof(uchar*)
57  */
58  set_if_bigger(reclength, sizeof (uchar*));
59 
60  for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
61  {
62  memset(&keyinfo->block, 0, sizeof(keyinfo->block));
63  memset(&keyinfo->rb_tree, 0, sizeof(keyinfo->rb_tree));
64  for (j= length= 0; j < keyinfo->keysegs; j++)
65  {
66  length+= keyinfo->seg[j].length;
67  if (keyinfo->seg[j].null_bit)
68  {
69  length++;
70  if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
71  keyinfo->flag|= HA_NULL_PART_KEY;
72  if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
73  keyinfo->rb_tree.size_of_element++;
74  }
75  switch (keyinfo->seg[j].type) {
76  case HA_KEYTYPE_SHORT_INT:
77  case HA_KEYTYPE_LONG_INT:
78  case HA_KEYTYPE_FLOAT:
79  case HA_KEYTYPE_DOUBLE:
80  case HA_KEYTYPE_USHORT_INT:
81  case HA_KEYTYPE_ULONG_INT:
82  case HA_KEYTYPE_LONGLONG:
83  case HA_KEYTYPE_ULONGLONG:
84  case HA_KEYTYPE_INT24:
85  case HA_KEYTYPE_UINT24:
86  case HA_KEYTYPE_INT8:
87  keyinfo->seg[j].flag|= HA_SWAP_KEY;
88  break;
89  case HA_KEYTYPE_VARBINARY1:
90  /* Case-insensitiveness is handled in coll->hash_sort */
91  keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
92  /* fall_through */
93  case HA_KEYTYPE_VARTEXT1:
94  keyinfo->flag|= HA_VAR_LENGTH_KEY;
95  length+= 2;
96  /* Save number of bytes used to store length */
97  keyinfo->seg[j].bit_start= 1;
98  break;
99  case HA_KEYTYPE_VARBINARY2:
100  /* Case-insensitiveness is handled in coll->hash_sort */
101  /* fall_through */
102  case HA_KEYTYPE_VARTEXT2:
103  keyinfo->flag|= HA_VAR_LENGTH_KEY;
104  length+= 2;
105  /* Save number of bytes used to store length */
106  keyinfo->seg[j].bit_start= 2;
107  /*
108  Make future comparison simpler by only having to check for
109  one type
110  */
111  keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
112  break;
113  default:
114  break;
115  }
116  }
117  keyinfo->length= length;
118  length+= keyinfo->rb_tree.size_of_element +
119  ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(uchar*) : 0);
120  if (length > max_length)
121  max_length= length;
122  key_segs+= keyinfo->keysegs;
123  if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
124  {
125  key_segs++; /* additional HA_KEYTYPE_END segment */
126  if (keyinfo->flag & HA_VAR_LENGTH_KEY)
127  keyinfo->get_key_length= hp_rb_var_key_length;
128  else if (keyinfo->flag & HA_NULL_PART_KEY)
129  keyinfo->get_key_length= hp_rb_null_key_length;
130  else
131  keyinfo->get_key_length= hp_rb_key_length;
132  }
133  }
134  if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
135  keys*sizeof(HP_KEYDEF)+
136  key_segs*sizeof(HA_KEYSEG),
137  MYF(MY_ZEROFILL))))
138  goto err;
139  share->keydef= (HP_KEYDEF*) (share + 1);
140  share->key_stat_version= 1;
141  keyseg= (HA_KEYSEG*) (share->keydef + keys);
142  init_block(&share->block, reclength + 1, min_records, max_records);
143  /* Fix keys */
144  memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
145  for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
146  {
147  keyinfo->seg= keyseg;
148  memcpy(keyseg, keydef[i].seg,
149  (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
150  keyseg+= keydef[i].keysegs;
151 
152  if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
153  {
154  /* additional HA_KEYTYPE_END keyseg */
155  keyseg->type= HA_KEYTYPE_END;
156  keyseg->length= sizeof(uchar*);
157  keyseg->flag= 0;
158  keyseg->null_bit= 0;
159  keyseg++;
160 
161  init_tree(&keyinfo->rb_tree, 0, 0, sizeof(uchar*),
162  (qsort_cmp2)keys_compare, 1, NULL, NULL);
163  keyinfo->delete_key= hp_rb_delete_key;
164  keyinfo->write_key= hp_rb_write_key;
165  }
166  else
167  {
168  init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
169  max_records);
170  keyinfo->delete_key= hp_delete_key;
171  keyinfo->write_key= hp_write_key;
172  keyinfo->hash_buckets= 0;
173  }
174  if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
175  share->auto_key= i + 1;
176  }
177  share->min_records= min_records;
178  share->max_records= max_records;
179  share->max_table_size= create_info->max_table_size;
180  share->data_length= share->index_length= 0;
181  share->reclength= reclength;
182  share->blength= 1;
183  share->keys= keys;
184  share->max_key_length= max_length;
185  share->changed= 0;
186  share->auto_key= create_info->auto_key;
187  share->auto_key_type= create_info->auto_key_type;
188  share->auto_increment= create_info->auto_increment;
189  share->create_time= (long) time((time_t*) 0);
190  /* Must be allocated separately for rename to work */
191  if (!(share->name= my_strdup(name,MYF(0))))
192  {
193  my_free(share);
194  goto err;
195  }
196  thr_lock_init(&share->lock);
197  mysql_mutex_init(hp_key_mutex_HP_SHARE_intern_lock,
198  &share->intern_lock, MY_MUTEX_INIT_FAST);
199  if (!create_info->internal_table)
200  {
201  share->open_list.data= (void*) share;
202  heap_share_list= list_add(heap_share_list,&share->open_list);
203  }
204  else
205  share->delete_on_close= 1;
206  }
207  if (!create_info->internal_table)
208  {
209  if (create_info->pin_share)
210  ++share->open_count;
211  mysql_mutex_unlock(&THR_LOCK_heap);
212  }
213 
214  *res= share;
215  DBUG_RETURN(0);
216 
217 err:
218  if (!create_info->internal_table)
219  mysql_mutex_unlock(&THR_LOCK_heap);
220  DBUG_RETURN(1);
221 } /* heap_create */
222 
223 
224 static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
225 {
226  uint not_used[2];
227  return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
228  param->search_flag, not_used);
229 }
230 
231 static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
232  ulong max_records)
233 {
234  uint i,recbuffer,records_in_block;
235 
236  max_records= MY_MAX(min_records, max_records);
237  if (!max_records)
238  max_records= 1000; /* As good as quess as anything */
239  recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
240  records_in_block= max_records / 10;
241  if (records_in_block < 10 && max_records)
242  records_in_block= 10;
243  if (!records_in_block || records_in_block*recbuffer >
244  (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
245  records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
246  HP_MAX_LEVELS) / recbuffer + 1;
247  block->records_in_block= records_in_block;
248  block->recbuffer= recbuffer;
249  block->last_allocated= 0L;
250 
251  for (i= 0; i <= HP_MAX_LEVELS; i++)
252  block->level_info[i].records_under_level=
253  (!i ? 1 : i == 1 ? records_in_block :
254  HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
255 }
256 
257 
258 static inline void heap_try_free(HP_SHARE *share)
259 {
260  if (share->open_count == 0)
261  hp_free(share);
262  else
263  share->delete_on_close= 1;
264 }
265 
266 
267 int heap_delete_table(const char *name)
268 {
269  int result;
270  reg1 HP_SHARE *share;
271  DBUG_ENTER("heap_delete_table");
272 
273  mysql_mutex_lock(&THR_LOCK_heap);
274  if ((share= hp_find_named_heap(name)))
275  {
276  heap_try_free(share);
277  result= 0;
278  }
279  else
280  {
281  result= my_errno=ENOENT;
282  }
283  mysql_mutex_unlock(&THR_LOCK_heap);
284  DBUG_RETURN(result);
285 }
286 
287 
288 void heap_drop_table(HP_INFO *info)
289 {
290  DBUG_ENTER("heap_drop_table");
291  mysql_mutex_lock(&THR_LOCK_heap);
292  heap_try_free(info->s);
293  mysql_mutex_unlock(&THR_LOCK_heap);
294  DBUG_VOID_RETURN;
295 }
296 
297 
298 void hp_free(HP_SHARE *share)
299 {
300  if (share->open_list.data) /* If not internal table */
301  heap_share_list= list_delete(heap_share_list, &share->open_list);
302  hp_clear(share); /* Remove blocks from memory */
303  thr_lock_delete(&share->lock);
304  mysql_mutex_destroy(&share->intern_lock);
305  my_free(share->name);
306  my_free(share);
307  return;
308 }