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