~drizzle-trunk/drizzle/development

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