hp_create.c 8.69 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
unknown's avatar
unknown committed
2

unknown's avatar
unknown committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
unknown's avatar
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
unknown's avatar
unknown committed
12

unknown's avatar
unknown committed
13 14 15 16 17 18
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "heapdef.h"

unknown's avatar
unknown committed
19 20 21 22 23
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2);
static void init_block(HP_BLOCK *block,uint reclength,ulong min_records,
		       ulong max_records);

int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
unknown's avatar
unknown committed
24 25
		uint reclength, ulong max_records, ulong min_records,
		HP_CREATE_INFO *create_info)
unknown's avatar
unknown committed
26
{
unknown's avatar
unknown committed
27 28 29 30
  uint i, j, key_segs, max_length, length;
  HP_SHARE *share;
  HA_KEYSEG *keyseg;
  
unknown's avatar
unknown committed
31
  DBUG_ENTER("heap_create");
unknown's avatar
unknown committed
32
  pthread_mutex_lock(&THR_LOCK_heap);
unknown's avatar
unknown committed
33 34

  if ((share= hp_find_named_heap(name)) && share->open_count == 0)
unknown's avatar
unknown committed
35
  {
unknown's avatar
unknown committed
36 37
    hp_free(share);
    share= NULL;
unknown's avatar
unknown committed
38
  }
unknown's avatar
unknown committed
39 40
  
  if (!share)
unknown's avatar
unknown committed
41
  {
unknown's avatar
unknown committed
42 43
    HP_KEYDEF *keyinfo;
    DBUG_PRINT("info",("Initializing new table"));
44 45 46 47 48 49 50
    
    /*
      We have to store sometimes byte* del_link in records,
      so the record length should be at least sizeof(byte*)
    */
    set_if_bigger(reclength, sizeof (byte*));
    
unknown's avatar
unknown committed
51 52 53 54 55 56 57 58 59
    for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
    {
      bzero((char*) &keyinfo->block,sizeof(keyinfo->block));
      bzero((char*) &keyinfo->rb_tree ,sizeof(keyinfo->rb_tree));
      for (j= length= 0; j < keyinfo->keysegs; j++)
      {
	length+= keyinfo->seg[j].length;
	if (keyinfo->seg[j].null_bit)
	{
unknown's avatar
unknown committed
60
	  length++;
unknown's avatar
unknown committed
61 62 63 64 65
	  if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
	    keyinfo->flag|= HA_NULL_PART_KEY;
	  if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
	    keyinfo->rb_tree.size_of_element++;
	}
66 67 68 69 70 71 72 73 74 75 76 77 78
	switch (keyinfo->seg[j].type) {
	case HA_KEYTYPE_SHORT_INT:
	case HA_KEYTYPE_LONG_INT:
	case HA_KEYTYPE_FLOAT:
	case HA_KEYTYPE_DOUBLE:
	case HA_KEYTYPE_USHORT_INT:
	case HA_KEYTYPE_ULONG_INT:
	case HA_KEYTYPE_LONGLONG:
	case HA_KEYTYPE_ULONGLONG:
	case HA_KEYTYPE_INT24:
	case HA_KEYTYPE_UINT24:
	case HA_KEYTYPE_INT8:
	  keyinfo->seg[j].flag|= HA_SWAP_KEY;
79
          break;
80
        case HA_KEYTYPE_VARBINARY1:
81
          /* Case-insensitiveness is handled in coll->hash_sort */
82
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
83
          /* fall_through */
84
        case HA_KEYTYPE_VARTEXT1:
85 86 87
          if (!my_binary_compare(keyinfo->seg[j].charset))
            keyinfo->flag|= HA_END_SPACE_KEY;
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
          /* Save number of bytes used to store length */
          keyinfo->seg[j].bit_start= 1;
          break;
        case HA_KEYTYPE_VARBINARY2:
          /* Case-insensitiveness is handled in coll->hash_sort */
          /* fall_through */
        case HA_KEYTYPE_VARTEXT2:
          if (!my_binary_compare(keyinfo->seg[j].charset))
            keyinfo->flag|= HA_END_SPACE_KEY;
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
          /* Save number of bytes used to store length */
          keyinfo->seg[j].bit_start= 2;
          /*
            Make future comparison simpler by only having to check for
            one type
          */
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
105
          break;
106 107 108
	default:
	  break;
	}
109 110
        if (keyinfo->seg[j].flag & HA_END_SPACE_ARE_EQUAL)
          keyinfo->flag|= HA_END_SPACE_KEY;
unknown's avatar
unknown committed
111 112 113 114 115 116 117 118 119 120
      }
      keyinfo->length= length;
      length+= keyinfo->rb_tree.size_of_element + 
	       ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(byte*) : 0);
      if (length > max_length)
	max_length= length;
      key_segs+= keyinfo->keysegs;
      if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
      {
        key_segs++; /* additional HA_KEYTYPE_END segment */
121 122 123
        if (keyinfo->flag & HA_VAR_LENGTH_KEY)
          keyinfo->get_key_length= hp_rb_var_key_length;
        else if (keyinfo->flag & HA_NULL_PART_KEY)
unknown's avatar
unknown committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
          keyinfo->get_key_length= hp_rb_null_key_length;
        else
          keyinfo->get_key_length= hp_rb_key_length;
      }
    }
    if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
				       keys*sizeof(HP_KEYDEF)+
				       key_segs*sizeof(HA_KEYSEG),
				       MYF(MY_ZEROFILL))))
    {
      pthread_mutex_unlock(&THR_LOCK_heap);
      DBUG_RETURN(1);
    }
    share->keydef= (HP_KEYDEF*) (share + 1);
    keyseg= (HA_KEYSEG*) (share->keydef + keys);
    init_block(&share->block, reclength + 1, min_records, max_records);
	/* Fix keys */
    memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
    for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
    {
144 145 146 147
      keyinfo->seg= keyseg;
      memcpy(keyseg, keydef[i].seg,
	     (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
      keyseg+= keydef[i].keysegs;
unknown's avatar
unknown committed
148 149 150

      if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
      {
151 152 153 154 155 156
	/* additional HA_KEYTYPE_END keyseg */
	keyseg->type=     HA_KEYTYPE_END;
	keyseg->length=   sizeof(byte*);
	keyseg->flag=     0;
	keyseg->null_bit= 0;
	keyseg++;
157 158

	init_tree(&keyinfo->rb_tree, 0, 0, sizeof(byte*),
unknown's avatar
unknown committed
159 160 161 162 163 164
		  (qsort_cmp2)keys_compare, 1, NULL, NULL);
	keyinfo->delete_key= hp_rb_delete_key;
	keyinfo->write_key= hp_rb_write_key;
      }
      else
      {
165
	init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
unknown's avatar
unknown committed
166 167 168
		   max_records);
	keyinfo->delete_key= hp_delete_key;
	keyinfo->write_key= hp_write_key;
169
        keyinfo->hash_buckets= 0;
unknown's avatar
unknown committed
170
      }
unknown's avatar
unknown committed
171 172
      if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
        share->auto_key= i + 1;
unknown's avatar
unknown committed
173 174 175
    }
    share->min_records= min_records;
    share->max_records= max_records;
176
    share->max_table_size= create_info->max_table_size;
unknown's avatar
unknown committed
177 178 179 180 181 182
    share->data_length= share->index_length= 0;
    share->reclength= reclength;
    share->blength= 1;
    share->keys= keys;
    share->max_key_length= max_length;
    share->changed= 0;
183
    share->auto_key= create_info->auto_key;
unknown's avatar
unknown committed
184 185
    share->auto_key_type= create_info->auto_key_type;
    share->auto_increment= create_info->auto_increment;
186
    /* Must be allocated separately for rename to work */
unknown's avatar
unknown committed
187 188 189 190 191 192 193 194 195 196 197 198
    if (!(share->name= my_strdup(name,MYF(0))))
    {
      my_free((gptr) share,MYF(0));
      pthread_mutex_unlock(&THR_LOCK_heap);
      DBUG_RETURN(1);
    }
#ifdef THREAD
    thr_lock_init(&share->lock);
    VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
#endif
    share->open_list.data= (void*) share;
    heap_share_list= list_add(heap_share_list,&share->open_list);
unknown's avatar
unknown committed
199 200
  }
  pthread_mutex_unlock(&THR_LOCK_heap);
unknown's avatar
unknown committed
201
  DBUG_RETURN(0);
unknown's avatar
unknown committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
} /* heap_create */

static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
{
  uint not_used;
  return ha_key_cmp(param->keyseg, key1, key2, param->key_length, 
		    param->search_flag, &not_used);
}

static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
		       ulong max_records)
{
  uint i,recbuffer,records_in_block;

  max_records= max(min_records,max_records);
  if (!max_records)
    max_records= 1000;			/* As good as quess as anything */
  recbuffer= (uint) (reclength + sizeof(byte**) - 1) & ~(sizeof(byte**) - 1);
  records_in_block= max_records / 10;
  if (records_in_block < 10 && max_records)
    records_in_block= 10;
  if (!records_in_block || records_in_block*recbuffer >
      (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
    records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
		      HP_MAX_LEVELS) / recbuffer + 1;
  block->records_in_block= records_in_block;
  block->recbuffer= recbuffer;
  block->last_allocated= 0L;

  for (i= 0; i <= HP_MAX_LEVELS; i++)
    block->level_info[i].records_under_level=
      (!i ? 1 : i == 1 ? records_in_block :
       HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
unknown's avatar
unknown committed
235 236
}

unknown's avatar
unknown committed
237
int heap_delete_table(const char *name)
unknown's avatar
unknown committed
238
{
unknown's avatar
unknown committed
239 240 241 242
  int result;
  reg1 HP_SHARE *share;
  DBUG_ENTER("heap_delete_table");

unknown's avatar
unknown committed
243
  pthread_mutex_lock(&THR_LOCK_heap);
unknown's avatar
unknown committed
244
  if ((share= hp_find_named_heap(name)))
unknown's avatar
unknown committed
245
  {
unknown's avatar
unknown committed
246
    if (share->open_count == 0)
247
      hp_free(share);
unknown's avatar
unknown committed
248
    else
unknown's avatar
unknown committed
249 250
     share->delete_on_close= 1;
    result= 0;
unknown's avatar
unknown committed
251 252 253
  }
  else
  {
unknown's avatar
unknown committed
254
    result= my_errno=ENOENT;
unknown's avatar
unknown committed
255 256
  }
  pthread_mutex_unlock(&THR_LOCK_heap);
unknown's avatar
unknown committed
257
  DBUG_RETURN(result);
unknown's avatar
unknown committed
258 259
}

260
void hp_free(HP_SHARE *share)
unknown's avatar
unknown committed
261
{
unknown's avatar
unknown committed
262
  heap_share_list= list_delete(heap_share_list, &share->open_list);
263
  hp_clear(share);			/* Remove blocks from memory */
unknown's avatar
unknown committed
264 265 266 267
#ifdef THREAD
  thr_lock_delete(&share->lock);
  VOID(pthread_mutex_destroy(&share->intern_lock));
#endif
unknown's avatar
unknown committed
268 269
  my_free((gptr) share->name, MYF(0));
  my_free((gptr) share, MYF(0));
unknown's avatar
unknown committed
270 271
  return;
}