hp_create.c 7.06 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com 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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com 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.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com 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"

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,
24 25
		uint reclength, ulong max_records, ulong min_records,
		HP_CREATE_INFO *create_info)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
26
{
27 28 29 30
  uint i, j, key_segs, max_length, length;
  HP_SHARE *share;
  HA_KEYSEG *keyseg;
  
bk@work.mysql.com's avatar
bk@work.mysql.com committed
31
  DBUG_ENTER("heap_create");
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
32
  pthread_mutex_lock(&THR_LOCK_heap);
33 34

  if ((share= hp_find_named_heap(name)) && share->open_count == 0)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
35
  {
36 37
    hp_free(share);
    share= NULL;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
38
  }
39 40
  
  if (!share)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
41
  {
42 43 44 45 46 47 48 49 50 51 52
    HP_KEYDEF *keyinfo;
    DBUG_PRINT("info",("Initializing new table"));
    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)
	{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
53
	  length++;
54 55 56 57 58
	  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++;
	}
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
	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;
	default:
	  break;
	}
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
      }
      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 */
        if (keyinfo->flag & HA_NULL_PART_KEY)
          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++)
    {
106 107 108 109
      keyinfo->seg= keyseg;
      memcpy(keyseg, keydef[i].seg,
	     (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
      keyseg+= keydef[i].keysegs;
110 111 112

      if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
      {
113 114 115 116 117 118 119
	/* additional HA_KEYTYPE_END keyseg */
	keyseg->type=     HA_KEYTYPE_END;
	keyseg->length=   sizeof(byte*);
	keyseg->flag=     0;
	keyseg->null_bit= 0;
	keyseg++;
	
120 121 122 123 124 125 126 127 128 129 130
	init_tree(&keyinfo->rb_tree, 0, 0, sizeof(byte*), 
		  (qsort_cmp2)keys_compare, 1, NULL, NULL);
	keyinfo->delete_key= hp_rb_delete_key;
	keyinfo->write_key= hp_rb_write_key;
      }
      else
      {
	init_block(&keyinfo->block, sizeof(HASH_INFO), min_records, 
		   max_records);
	keyinfo->delete_key= hp_delete_key;
	keyinfo->write_key= hp_write_key;
131
        keyinfo->hash_buckets= 0;
132 133 134 135 136 137 138 139 140 141
      }
    }
    share->min_records= min_records;
    share->max_records= max_records;
    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;
142 143 144
    share->auto_key= create_info->auto_key;
    share->auto_key_type= create_info->auto_key_type;
    share->auto_increment= create_info->auto_increment;
145
    /* Must be allocated separately for rename to work */
146 147 148 149 150 151 152 153 154 155 156 157
    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);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
158 159
  }
  pthread_mutex_unlock(&THR_LOCK_heap);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
160
  DBUG_RETURN(0);
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
} /* 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);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
194 195
}

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
196
int heap_delete_table(const char *name)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
197
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
198 199 200 201
  int result;
  reg1 HP_SHARE *share;
  DBUG_ENTER("heap_delete_table");

bk@work.mysql.com's avatar
bk@work.mysql.com committed
202
  pthread_mutex_lock(&THR_LOCK_heap);
203
  if ((share= hp_find_named_heap(name)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
204
  {
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
205
    if (share->open_count == 0)
206
      hp_free(share);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
207
    else
208 209
     share->delete_on_close= 1;
    result= 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
210 211 212
  }
  else
  {
213
    result= my_errno=ENOENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
214 215
  }
  pthread_mutex_unlock(&THR_LOCK_heap);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
216
  DBUG_RETURN(result);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
217 218
}

219
void hp_free(HP_SHARE *share)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
220
{
221
  heap_share_list= list_delete(heap_share_list, &share->open_list);
222
  hp_clear(share);			/* Remove blocks from memory */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
223 224 225 226
#ifdef THREAD
  thr_lock_delete(&share->lock);
  VOID(pthread_mutex_destroy(&share->intern_lock));
#endif
227 228
  my_free((gptr) share->name, MYF(0));
  my_free((gptr) share, MYF(0));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
229 230
  return;
}