1 /* Copyright (c) 2000, 2018, 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, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include "heapdef.h"
24 
25 static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2);
26 static void init_block(HP_BLOCK *block,uint reclength,ulong min_records,
27 		       ulong max_records);
28 
29 /* Create a heap table */
30 
heap_create(const char * name,HP_CREATE_INFO * create_info,HP_SHARE ** res,my_bool * created_new_share)31 int heap_create(const char *name, HP_CREATE_INFO *create_info,
32                 HP_SHARE **res, my_bool *created_new_share)
33 {
34   uint i, j, key_segs, max_length, length;
35   HP_SHARE *share= 0;
36   HA_KEYSEG *keyseg;
37   HP_KEYDEF *keydef= create_info->keydef;
38   uint reclength= create_info->reclength;
39   uint keys= create_info->keys;
40   ulong min_records= create_info->min_records;
41   ulong max_records= create_info->max_records;
42   DBUG_ENTER("heap_create");
43 
44   if (!create_info->internal_table)
45   {
46     mysql_mutex_lock(&THR_LOCK_heap);
47     share= hp_find_named_heap(name);
48     if (share && share->open_count == 0)
49     {
50       hp_free(share);
51       share= 0;
52     }
53   }
54   *created_new_share= (share == NULL);
55 
56   if (!share)
57   {
58     HP_KEYDEF *keyinfo;
59     DBUG_PRINT("info",("Initializing new table"));
60 
61     /*
62       We have to store sometimes uchar* del_link in records,
63       so the record length should be at least sizeof(uchar*)
64     */
65     set_if_bigger(reclength, sizeof (uchar*));
66 
67     for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
68     {
69       memset(&keyinfo->block, 0, sizeof(keyinfo->block));
70       memset(&keyinfo->rb_tree, 0, sizeof(keyinfo->rb_tree));
71       for (j= length= 0; j < keyinfo->keysegs; j++)
72       {
73 	length+= keyinfo->seg[j].length;
74 	if (keyinfo->seg[j].null_bit)
75 	{
76 	  length++;
77 	  if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
78 	    keyinfo->flag|= HA_NULL_PART_KEY;
79 	  if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
80 	    keyinfo->rb_tree.size_of_element++;
81 	}
82 	switch (keyinfo->seg[j].type) {
83 	case HA_KEYTYPE_SHORT_INT:
84 	case HA_KEYTYPE_LONG_INT:
85 	case HA_KEYTYPE_FLOAT:
86 	case HA_KEYTYPE_DOUBLE:
87 	case HA_KEYTYPE_USHORT_INT:
88 	case HA_KEYTYPE_ULONG_INT:
89 	case HA_KEYTYPE_LONGLONG:
90 	case HA_KEYTYPE_ULONGLONG:
91 	case HA_KEYTYPE_INT24:
92 	case HA_KEYTYPE_UINT24:
93 	case HA_KEYTYPE_INT8:
94 	  keyinfo->seg[j].flag|= HA_SWAP_KEY;
95           break;
96         case HA_KEYTYPE_VARBINARY1:
97           /* Case-insensitiveness is handled in coll->hash_sort */
98           keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
99           /* fall_through */
100         case HA_KEYTYPE_VARTEXT1:
101           keyinfo->flag|= HA_VAR_LENGTH_KEY;
102           /*
103             For BTREE algorithm, key length, greater than or equal
104             to 255, is packed on 3 bytes.
105           */
106           if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
107             length+= size_to_store_key_length(keyinfo->seg[j].length);
108           else
109             length+= 2;
110           /* Save number of bytes used to store length */
111           keyinfo->seg[j].bit_start= 1;
112           break;
113         case HA_KEYTYPE_VARBINARY2:
114           /* Case-insensitiveness is handled in coll->hash_sort */
115           /* fall_through */
116         case HA_KEYTYPE_VARTEXT2:
117           keyinfo->flag|= HA_VAR_LENGTH_KEY;
118           /*
119             For BTREE algorithm, key length, greater than or equal
120             to 255, is packed on 3 bytes.
121           */
122           if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
123             length+= size_to_store_key_length(keyinfo->seg[j].length);
124           else
125             length+= 2;
126           /* Save number of bytes used to store length */
127           keyinfo->seg[j].bit_start= 2;
128           /*
129             Make future comparison simpler by only having to check for
130             one type
131           */
132           keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
133           break;
134 	default:
135 	  break;
136 	}
137       }
138       keyinfo->length= length;
139       length+= keyinfo->rb_tree.size_of_element +
140 	       ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(uchar*) : 0);
141       if (length > max_length)
142 	max_length= length;
143       key_segs+= keyinfo->keysegs;
144       if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
145       {
146         key_segs++; /* additional HA_KEYTYPE_END segment */
147         if (keyinfo->flag & HA_VAR_LENGTH_KEY)
148           keyinfo->get_key_length= hp_rb_var_key_length;
149         else if (keyinfo->flag & HA_NULL_PART_KEY)
150           keyinfo->get_key_length= hp_rb_null_key_length;
151         else
152           keyinfo->get_key_length= hp_rb_key_length;
153       }
154     }
155     if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
156 				       keys*sizeof(HP_KEYDEF)+
157 				       key_segs*sizeof(HA_KEYSEG),
158 				       MYF(MY_ZEROFILL))))
159       goto err;
160     share->keydef= (HP_KEYDEF*) (share + 1);
161     share->key_stat_version= 1;
162     keyseg= (HA_KEYSEG*) (share->keydef + keys);
163     init_block(&share->block, reclength + 1, min_records, max_records);
164 	/* Fix keys */
165     memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
166     for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
167     {
168       keyinfo->seg= keyseg;
169       memcpy(keyseg, keydef[i].seg,
170 	     (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
171       keyseg+= keydef[i].keysegs;
172 
173       if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
174       {
175 	/* additional HA_KEYTYPE_END keyseg */
176 	keyseg->type=     HA_KEYTYPE_END;
177 	keyseg->length=   sizeof(uchar*);
178 	keyseg->flag=     0;
179 	keyseg->null_bit= 0;
180 	keyseg++;
181 
182 	init_tree(&keyinfo->rb_tree, 0, 0, sizeof(uchar*),
183 		  (qsort_cmp2)keys_compare, 1, NULL, NULL);
184 	keyinfo->delete_key= hp_rb_delete_key;
185 	keyinfo->write_key= hp_rb_write_key;
186       }
187       else
188       {
189 	init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
190 		   max_records);
191 	keyinfo->delete_key= hp_delete_key;
192 	keyinfo->write_key= hp_write_key;
193         keyinfo->hash_buckets= 0;
194       }
195       if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
196         share->auto_key= i + 1;
197     }
198     share->min_records= min_records;
199     share->max_records= max_records;
200     share->max_table_size= create_info->max_table_size;
201     share->data_length= share->index_length= 0;
202     share->reclength= reclength;
203     share->blength= 1;
204     share->keys= keys;
205     share->max_key_length= max_length;
206     share->changed= 0;
207     share->auto_key= create_info->auto_key;
208     share->auto_key_type= create_info->auto_key_type;
209     share->auto_increment= create_info->auto_increment;
210     share->create_time= (long) time((time_t*) 0);
211     /* Must be allocated separately for rename to work */
212     if (!(share->name= my_strdup(name,MYF(0))))
213     {
214       my_free(share);
215       goto err;
216     }
217     thr_lock_init(&share->lock);
218     mysql_mutex_init(hp_key_mutex_HP_SHARE_intern_lock,
219                      &share->intern_lock, MY_MUTEX_INIT_FAST);
220     if (!create_info->internal_table)
221     {
222       share->open_list.data= (void*) share;
223       heap_share_list= list_add(heap_share_list,&share->open_list);
224     }
225     else
226       share->delete_on_close= 1;
227   }
228   if (!create_info->internal_table)
229   {
230     if (create_info->pin_share)
231       ++share->open_count;
232     mysql_mutex_unlock(&THR_LOCK_heap);
233   }
234 
235   *res= share;
236   DBUG_RETURN(0);
237 
238 err:
239   if (!create_info->internal_table)
240     mysql_mutex_unlock(&THR_LOCK_heap);
241   DBUG_RETURN(1);
242 } /* heap_create */
243 
244 
keys_compare(heap_rb_param * param,uchar * key1,uchar * key2)245 static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
246 {
247   uint not_used[2];
248   return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
249 		    param->search_flag, not_used);
250 }
251 
init_block(HP_BLOCK * block,uint reclength,ulong min_records,ulong max_records)252 static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
253 		       ulong max_records)
254 {
255   uint i,recbuffer,records_in_block;
256 
257   max_records= MY_MAX(min_records, max_records);
258   if (!max_records)
259     max_records= 1000;			/* As good as quess as anything */
260   recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
261   records_in_block= max_records / 10;
262   if (records_in_block < 10 && max_records)
263     records_in_block= 10;
264   if (!records_in_block || (ulonglong) records_in_block * recbuffer >
265       (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
266     records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
267 		      HP_MAX_LEVELS) / recbuffer + 1;
268   block->records_in_block= records_in_block;
269   block->recbuffer= recbuffer;
270   block->last_allocated= 0L;
271 
272   for (i= 0; i <= HP_MAX_LEVELS; i++)
273     block->level_info[i].records_under_level=
274       (!i ? 1 : i == 1 ? records_in_block :
275        HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
276 }
277 
278 
heap_try_free(HP_SHARE * share)279 static inline void heap_try_free(HP_SHARE *share)
280 {
281   if (share->open_count == 0)
282     hp_free(share);
283   else
284     share->delete_on_close= 1;
285 }
286 
287 
heap_delete_table(const char * name)288 int heap_delete_table(const char *name)
289 {
290   int result;
291   reg1 HP_SHARE *share;
292   DBUG_ENTER("heap_delete_table");
293 
294   mysql_mutex_lock(&THR_LOCK_heap);
295   if ((share= hp_find_named_heap(name)))
296   {
297     heap_try_free(share);
298     result= 0;
299   }
300   else
301   {
302     result= my_errno=ENOENT;
303   }
304   mysql_mutex_unlock(&THR_LOCK_heap);
305   DBUG_RETURN(result);
306 }
307 
308 
heap_drop_table(HP_INFO * info)309 void heap_drop_table(HP_INFO *info)
310 {
311   DBUG_ENTER("heap_drop_table");
312   mysql_mutex_lock(&THR_LOCK_heap);
313   heap_try_free(info->s);
314   mysql_mutex_unlock(&THR_LOCK_heap);
315   DBUG_VOID_RETURN;
316 }
317 
318 
hp_free(HP_SHARE * share)319 void hp_free(HP_SHARE *share)
320 {
321   if (share->open_list.data)                    /* If not internal table */
322     heap_share_list= list_delete(heap_share_list, &share->open_list);
323   hp_clear(share);			/* Remove blocks from memory */
324   thr_lock_delete(&share->lock);
325   mysql_mutex_destroy(&share->intern_lock);
326   my_free(share->name);
327   my_free(share);
328   return;
329 }
330