00001 /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #include "heapdef.h" 00018 00019 static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2); 00020 static void init_block(HP_BLOCK *block,uint reclength,ulong min_records, 00021 ulong max_records); 00022 00023 int heap_create(const char *name, uint keys, HP_KEYDEF *keydef, 00024 uint reclength, ulong max_records, ulong min_records, 00025 HP_CREATE_INFO *create_info) 00026 { 00027 uint i, j, key_segs, max_length, length; 00028 HP_SHARE *share; 00029 HA_KEYSEG *keyseg; 00030 00031 DBUG_ENTER("heap_create"); 00032 pthread_mutex_lock(&THR_LOCK_heap); 00033 00034 if ((share= hp_find_named_heap(name)) && share->open_count == 0) 00035 { 00036 hp_free(share); 00037 share= NULL; 00038 } 00039 00040 if (!share) 00041 { 00042 HP_KEYDEF *keyinfo; 00043 DBUG_PRINT("info",("Initializing new table")); 00044 00045 /* 00046 We have to store sometimes byte* del_link in records, 00047 so the record length should be at least sizeof(byte*) 00048 */ 00049 set_if_bigger(reclength, sizeof (byte*)); 00050 00051 for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++) 00052 { 00053 bzero((char*) &keyinfo->block,sizeof(keyinfo->block)); 00054 bzero((char*) &keyinfo->rb_tree ,sizeof(keyinfo->rb_tree)); 00055 for (j= length= 0; j < keyinfo->keysegs; j++) 00056 { 00057 length+= keyinfo->seg[j].length; 00058 if (keyinfo->seg[j].null_bit) 00059 { 00060 length++; 00061 if (!(keyinfo->flag & HA_NULL_ARE_EQUAL)) 00062 keyinfo->flag|= HA_NULL_PART_KEY; 00063 if (keyinfo->algorithm == HA_KEY_ALG_BTREE) 00064 keyinfo->rb_tree.size_of_element++; 00065 } 00066 switch (keyinfo->seg[j].type) { 00067 case HA_KEYTYPE_SHORT_INT: 00068 case HA_KEYTYPE_LONG_INT: 00069 case HA_KEYTYPE_FLOAT: 00070 case HA_KEYTYPE_DOUBLE: 00071 case HA_KEYTYPE_USHORT_INT: 00072 case HA_KEYTYPE_ULONG_INT: 00073 case HA_KEYTYPE_LONGLONG: 00074 case HA_KEYTYPE_ULONGLONG: 00075 case HA_KEYTYPE_INT24: 00076 case HA_KEYTYPE_UINT24: 00077 case HA_KEYTYPE_INT8: 00078 keyinfo->seg[j].flag|= HA_SWAP_KEY; 00079 break; 00080 case HA_KEYTYPE_VARBINARY1: 00081 /* Case-insensitiveness is handled in coll->hash_sort */ 00082 keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1; 00083 /* fall_through */ 00084 case HA_KEYTYPE_VARTEXT1: 00085 if (!my_binary_compare(keyinfo->seg[j].charset)) 00086 keyinfo->flag|= HA_END_SPACE_KEY; 00087 keyinfo->flag|= HA_VAR_LENGTH_KEY; 00088 length+= 2; 00089 /* Save number of bytes used to store length */ 00090 keyinfo->seg[j].bit_start= 1; 00091 break; 00092 case HA_KEYTYPE_VARBINARY2: 00093 /* Case-insensitiveness is handled in coll->hash_sort */ 00094 /* fall_through */ 00095 case HA_KEYTYPE_VARTEXT2: 00096 if (!my_binary_compare(keyinfo->seg[j].charset)) 00097 keyinfo->flag|= HA_END_SPACE_KEY; 00098 keyinfo->flag|= HA_VAR_LENGTH_KEY; 00099 length+= 2; 00100 /* Save number of bytes used to store length */ 00101 keyinfo->seg[j].bit_start= 2; 00102 /* 00103 Make future comparison simpler by only having to check for 00104 one type 00105 */ 00106 keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1; 00107 break; 00108 default: 00109 break; 00110 } 00111 if (keyinfo->seg[j].flag & HA_END_SPACE_ARE_EQUAL) 00112 keyinfo->flag|= HA_END_SPACE_KEY; 00113 } 00114 keyinfo->length= length; 00115 length+= keyinfo->rb_tree.size_of_element + 00116 ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(byte*) : 0); 00117 if (length > max_length) 00118 max_length= length; 00119 key_segs+= keyinfo->keysegs; 00120 if (keyinfo->algorithm == HA_KEY_ALG_BTREE) 00121 { 00122 key_segs++; /* additional HA_KEYTYPE_END segment */ 00123 if (keyinfo->flag & HA_VAR_LENGTH_KEY) 00124 keyinfo->get_key_length= hp_rb_var_key_length; 00125 else if (keyinfo->flag & HA_NULL_PART_KEY) 00126 keyinfo->get_key_length= hp_rb_null_key_length; 00127 else 00128 keyinfo->get_key_length= hp_rb_key_length; 00129 } 00130 } 00131 if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+ 00132 keys*sizeof(HP_KEYDEF)+ 00133 key_segs*sizeof(HA_KEYSEG), 00134 MYF(MY_ZEROFILL)))) 00135 { 00136 pthread_mutex_unlock(&THR_LOCK_heap); 00137 DBUG_RETURN(1); 00138 } 00139 share->keydef= (HP_KEYDEF*) (share + 1); 00140 share->key_stat_version= 1; 00141 keyseg= (HA_KEYSEG*) (share->keydef + keys); 00142 init_block(&share->block, reclength + 1, min_records, max_records); 00143 /* Fix keys */ 00144 memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys)); 00145 for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++) 00146 { 00147 keyinfo->seg= keyseg; 00148 memcpy(keyseg, keydef[i].seg, 00149 (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs)); 00150 keyseg+= keydef[i].keysegs; 00151 00152 if (keydef[i].algorithm == HA_KEY_ALG_BTREE) 00153 { 00154 /* additional HA_KEYTYPE_END keyseg */ 00155 keyseg->type= HA_KEYTYPE_END; 00156 keyseg->length= sizeof(byte*); 00157 keyseg->flag= 0; 00158 keyseg->null_bit= 0; 00159 keyseg++; 00160 00161 init_tree(&keyinfo->rb_tree, 0, 0, sizeof(byte*), 00162 (qsort_cmp2)keys_compare, 1, NULL, NULL); 00163 keyinfo->delete_key= hp_rb_delete_key; 00164 keyinfo->write_key= hp_rb_write_key; 00165 } 00166 else 00167 { 00168 init_block(&keyinfo->block, sizeof(HASH_INFO), min_records, 00169 max_records); 00170 keyinfo->delete_key= hp_delete_key; 00171 keyinfo->write_key= hp_write_key; 00172 keyinfo->hash_buckets= 0; 00173 } 00174 if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment) 00175 share->auto_key= i + 1; 00176 } 00177 share->min_records= min_records; 00178 share->max_records= max_records; 00179 share->max_table_size= create_info->max_table_size; 00180 share->data_length= share->index_length= 0; 00181 share->reclength= reclength; 00182 share->blength= 1; 00183 share->keys= keys; 00184 share->max_key_length= max_length; 00185 share->changed= 0; 00186 share->auto_key= create_info->auto_key; 00187 share->auto_key_type= create_info->auto_key_type; 00188 share->auto_increment= create_info->auto_increment; 00189 /* Must be allocated separately for rename to work */ 00190 if (!(share->name= my_strdup(name,MYF(0)))) 00191 { 00192 my_free((gptr) share,MYF(0)); 00193 pthread_mutex_unlock(&THR_LOCK_heap); 00194 DBUG_RETURN(1); 00195 } 00196 #ifdef THREAD 00197 thr_lock_init(&share->lock); 00198 VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST)); 00199 #endif 00200 share->open_list.data= (void*) share; 00201 heap_share_list= list_add(heap_share_list,&share->open_list); 00202 } 00203 pthread_mutex_unlock(&THR_LOCK_heap); 00204 DBUG_RETURN(0); 00205 } /* heap_create */ 00206 00207 static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2) 00208 { 00209 uint not_used[2]; 00210 return ha_key_cmp(param->keyseg, key1, key2, param->key_length, 00211 param->search_flag, not_used); 00212 } 00213 00214 static void init_block(HP_BLOCK *block, uint reclength, ulong min_records, 00215 ulong max_records) 00216 { 00217 uint i,recbuffer,records_in_block; 00218 00219 max_records= max(min_records,max_records); 00220 if (!max_records) 00221 max_records= 1000; /* As good as quess as anything */ 00222 recbuffer= (uint) (reclength + sizeof(byte**) - 1) & ~(sizeof(byte**) - 1); 00223 records_in_block= max_records / 10; 00224 if (records_in_block < 10 && max_records) 00225 records_in_block= 10; 00226 if (!records_in_block || records_in_block*recbuffer > 00227 (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS)) 00228 records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) * 00229 HP_MAX_LEVELS) / recbuffer + 1; 00230 block->records_in_block= records_in_block; 00231 block->recbuffer= recbuffer; 00232 block->last_allocated= 0L; 00233 00234 for (i= 0; i <= HP_MAX_LEVELS; i++) 00235 block->level_info[i].records_under_level= 00236 (!i ? 1 : i == 1 ? records_in_block : 00237 HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level); 00238 } 00239 00240 00241 static inline void heap_try_free(HP_SHARE *share) 00242 { 00243 if (share->open_count == 0) 00244 hp_free(share); 00245 else 00246 share->delete_on_close= 1; 00247 } 00248 00249 00250 int heap_delete_table(const char *name) 00251 { 00252 int result; 00253 reg1 HP_SHARE *share; 00254 DBUG_ENTER("heap_delete_table"); 00255 00256 pthread_mutex_lock(&THR_LOCK_heap); 00257 if ((share= hp_find_named_heap(name))) 00258 { 00259 heap_try_free(share); 00260 result= 0; 00261 } 00262 else 00263 { 00264 result= my_errno=ENOENT; 00265 } 00266 pthread_mutex_unlock(&THR_LOCK_heap); 00267 DBUG_RETURN(result); 00268 } 00269 00270 00271 void heap_drop_table(HP_INFO *info) 00272 { 00273 DBUG_ENTER("heap_drop_table"); 00274 pthread_mutex_lock(&THR_LOCK_heap); 00275 heap_try_free(info->s); 00276 pthread_mutex_unlock(&THR_LOCK_heap); 00277 DBUG_VOID_RETURN; 00278 } 00279 00280 00281 void hp_free(HP_SHARE *share) 00282 { 00283 heap_share_list= list_delete(heap_share_list, &share->open_list); 00284 hp_clear(share); /* Remove blocks from memory */ 00285 #ifdef THREAD 00286 thr_lock_delete(&share->lock); 00287 VOID(pthread_mutex_destroy(&share->intern_lock)); 00288 #endif 00289 my_free((gptr) share->name, MYF(0)); 00290 my_free((gptr) share, MYF(0)); 00291 return; 00292 }
1.4.7

