~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"
612.2.13 by Monty Taylor
Work on removing global.h from headers that should be installed.
17
18
#include <drizzled/common.h>
19
#include <drizzled/error.h>
20
21
#include <string.h>
1 by brian
clean slate
22
481 by Brian Aker
Remove all of uchar.
23
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2);
482 by Brian Aker
Remove uint.
24
static void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
291 by Brian Aker
Head ulong conversion.
25
                        uint32_t max_records);
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
26
481 by Brian Aker
Remove all of uchar.
27
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
28
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + sizeof(unsigned char))
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
29
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
30
/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
31
#define VARIABLE_MIN_CHUNK_SIZE \
481 by Brian Aker
Remove all of uchar.
32
        ((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1))
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
33
1 by brian
clean slate
34
35
/* Create a heap table */
36
482 by Brian Aker
Remove uint.
37
int heap_create(const char *name, uint32_t keys, HP_KEYDEF *keydef,
38
    uint32_t columns, HP_COLUMNDEF *columndef,
39
    uint32_t max_key_fieldnr, uint32_t key_part_size,
40
    uint32_t reclength, uint32_t keys_memory_size,
291 by Brian Aker
Head ulong conversion.
41
    uint32_t max_records, uint32_t min_records,
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
42
    HP_CREATE_INFO *create_info, HP_SHARE **res)
1 by brian
clean slate
43
{
482 by Brian Aker
Remove uint.
44
  uint32_t i, j, key_segs, max_length, length;
291 by Brian Aker
Head ulong conversion.
45
  uint32_t max_rows_for_stated_memory;
1 by brian
clean slate
46
  HP_SHARE *share= 0;
47
  HA_KEYSEG *keyseg;
48
49
  if (!create_info->internal_table)
50
  {
51
    pthread_mutex_lock(&THR_LOCK_heap);
52
    if ((share= hp_find_named_heap(name)) && share->open_count == 0)
53
    {
54
      hp_free(share);
55
      share= 0;
56
    }
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
57
  }
1 by brian
clean slate
58
59
  if (!share)
60
  {
482 by Brian Aker
Remove uint.
61
    uint32_t chunk_dataspace_length, chunk_length, is_variable_size;
62
    uint32_t fixed_data_length, fixed_column_count;
1 by brian
clean slate
63
    HP_KEYDEF *keyinfo;
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
64
65
    if (create_info->max_chunk_size)
66
    {
482 by Brian Aker
Remove uint.
67
      uint32_t configured_chunk_size= create_info->max_chunk_size;
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
68
69
      /* User requested variable-size records, let's see if they're possible */
70
71
      if (configured_chunk_size < key_part_size)
72
      {
73
        /* Eventual chunk_size cannot be smaller than key data,
74
           which allows all keys to fit into the first chunk */
75
        my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
76
        pthread_mutex_unlock(&THR_LOCK_heap);
77
        return(ER_CANT_USE_OPTION_HERE);
78
      }
79
80
      if ((reclength - configured_chunk_size) >= VARIABLE_MIN_CHUNK_SIZE<<1)
81
      {
82
        /* Allow variable size only if we're saving at least two smallest chunks */
83
        /* There has to be at least one field after indexed fields */
84
        /* Note that NULL bits are already included in key_part_size */
85
        is_variable_size= 1;
86
        chunk_dataspace_length= configured_chunk_size;
87
      }
88
      else
89
      {
90
        /* max_chunk_size is near the full reclength, let's use fixed size */
91
        is_variable_size= 0;
92
        chunk_dataspace_length= reclength;
93
      }
94
    }
95
    else if (create_info->is_dynamic)
96
    {
97
      /* User asked for dynamic records - use 256 as the chunk size */
98
      if ((key_part_size + VARIABLE_REC_OVERHEAD) > 256)
99
        chunk_dataspace_length= key_part_size;
100
      else
101
        chunk_dataspace_length= 256 - VARIABLE_REC_OVERHEAD;
102
103
      is_variable_size= 1;
104
    }
105
    else
106
    {
107
      /* if max_chunk_size is not specified, put the whole record in one chunk */
108
      is_variable_size= 0;
109
      chunk_dataspace_length= reclength;
110
    }
111
112
    if (is_variable_size)
113
    {
114
      /* Check whether we have any variable size records past key data */
482 by Brian Aker
Remove uint.
115
      uint32_t has_variable_fields= 0;
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
116
117
      fixed_data_length= key_part_size;
118
      fixed_column_count= max_key_fieldnr;
119
120
      for (i= max_key_fieldnr; i < columns; i++)
121
      {
122
        HP_COLUMNDEF* column= columndef + i;
123
        if (column->type == DRIZZLE_TYPE_VARCHAR && column->length >= 32)
124
        {
125
            /* The field has to be >= 5.0.3 true VARCHAR and have substantial length */
126
            /* TODO: do we want to calculate minimum length? */
127
            has_variable_fields= 1;
128
            break;
129
        }
130
131
        if (has_variable_fields)
132
        {
133
          break;
134
        }
135
136
        if ((column->offset + column->length) <= chunk_dataspace_length)
137
        {
138
          /* Still no variable-size columns, add one fixed-length */
139
          fixed_column_count= i + 1;
140
          fixed_data_length= column->offset + column->length;
141
        }
142
      }
143
144
      if (!has_variable_fields)
145
      {
146
        /* There is no need to use variable-size records without variable-size columns */
147
        /* Reset sizes if it's not variable size anymore */
148
        is_variable_size= 0;
149
        chunk_dataspace_length= reclength;
150
        fixed_data_length= reclength;
151
        fixed_column_count= columns;
152
      }
153
    }
154
    else
155
    {
156
      fixed_data_length= reclength;
157
      fixed_column_count= columns;
158
    }
159
1 by brian
clean slate
160
    /*
481 by Brian Aker
Remove all of uchar.
161
      We store unsigned char* del_link inside the data area of deleted records,
162
      so the data length should be at least sizeof(unsigned char*)
1 by brian
clean slate
163
    */
481 by Brian Aker
Remove all of uchar.
164
    set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
165
166
    if (is_variable_size)
167
    {
168
      chunk_length= chunk_dataspace_length + VARIABLE_REC_OVERHEAD;
169
    }
170
    else
171
    {
172
      chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
173
    }
174
175
    /* Align chunk length to the next pointer */
481 by Brian Aker
Remove all of uchar.
176
    chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
177
178
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
179
1 by brian
clean slate
180
    for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
181
    {
212.6.8 by Mats Kindahl
Removing extreneous explicit casts for the heap storage engine.
182
      memset(&keyinfo->block, 0, sizeof(keyinfo->block));
183
      memset(&keyinfo->rb_tree , 0, sizeof(keyinfo->rb_tree));
1 by brian
clean slate
184
      for (j= length= 0; j < keyinfo->keysegs; j++)
185
      {
186
	length+= keyinfo->seg[j].length;
187
	if (keyinfo->seg[j].null_bit)
188
	{
189
	  length++;
190
	  if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
191
	    keyinfo->flag|= HA_NULL_PART_KEY;
192
	  if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
193
	    keyinfo->rb_tree.size_of_element++;
194
	}
195
	switch (keyinfo->seg[j].type) {
196
	case HA_KEYTYPE_SHORT_INT:
197
	case HA_KEYTYPE_LONG_INT:
198
	case HA_KEYTYPE_FLOAT:
199
	case HA_KEYTYPE_DOUBLE:
200
	case HA_KEYTYPE_USHORT_INT:
201
	case HA_KEYTYPE_ULONG_INT:
202
	case HA_KEYTYPE_LONGLONG:
203
	case HA_KEYTYPE_ULONGLONG:
204
	case HA_KEYTYPE_INT24:
205
	case HA_KEYTYPE_UINT24:
206
	case HA_KEYTYPE_INT8:
207
	  keyinfo->seg[j].flag|= HA_SWAP_KEY;
208
          break;
209
        case HA_KEYTYPE_VARBINARY1:
210
          /* Case-insensitiveness is handled in coll->hash_sort */
211
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
212
          /* fall_through */
213
        case HA_KEYTYPE_VARTEXT1:
214
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
215
          length+= 2;
216
          /* Save number of bytes used to store length */
217
          keyinfo->seg[j].bit_start= 1;
218
          break;
219
        case HA_KEYTYPE_VARBINARY2:
220
          /* Case-insensitiveness is handled in coll->hash_sort */
221
          /* fall_through */
222
        case HA_KEYTYPE_VARTEXT2:
223
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
224
          length+= 2;
225
          /* Save number of bytes used to store length */
226
          keyinfo->seg[j].bit_start= 2;
227
          /*
228
            Make future comparison simpler by only having to check for
229
            one type
230
          */
231
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
232
          break;
233
	default:
234
	  break;
235
	}
236
      }
237
      keyinfo->length= length;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
238
      length+= keyinfo->rb_tree.size_of_element +
481 by Brian Aker
Remove all of uchar.
239
	       ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(unsigned char*) : 0);
1 by brian
clean slate
240
      if (length > max_length)
241
	max_length= length;
242
      key_segs+= keyinfo->keysegs;
243
      if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
244
      {
245
        key_segs++; /* additional HA_KEYTYPE_END segment */
246
        if (keyinfo->flag & HA_VAR_LENGTH_KEY)
247
          keyinfo->get_key_length= hp_rb_var_key_length;
248
        else if (keyinfo->flag & HA_NULL_PART_KEY)
249
          keyinfo->get_key_length= hp_rb_null_key_length;
250
        else
251
          keyinfo->get_key_length= hp_rb_key_length;
252
      }
253
    }
656.1.25 by Monty Taylor
Removed my_malloc stuff from storage/
254
    if (!(share= (HP_SHARE*) malloc(sizeof(HP_SHARE)+
255
				    keys*sizeof(HP_KEYDEF)+
256
                                    columns*sizeof(HP_COLUMNDEF)+
257
				    key_segs*sizeof(HA_KEYSEG))))
1 by brian
clean slate
258
      goto err;
656.1.25 by Monty Taylor
Removed my_malloc stuff from storage/
259
    memset(share, 0, sizeof(HP_SHARE)+
260
                     keys*sizeof(HP_KEYDEF)+
261
                     columns*sizeof(HP_COLUMNDEF)+
262
                     key_segs*sizeof(HA_KEYSEG));
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
263
264
    /*
265
       Max_records is used for estimating block sizes and for enforcement.
266
       Calculate the very maximum number of rows (if everything was one chunk) and
267
       then take either that value or configured max_records (pick smallest one)
268
    */
269
    max_rows_for_stated_memory= (ha_rows) (create_info->max_table_size /
270
      (keys_memory_size + chunk_length));
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
271
    max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
272
                      max_records : max_rows_for_stated_memory);
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
273
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
274
    share->column_defs= (HP_COLUMNDEF*) (share + 1);
275
    memcpy(share->column_defs, columndef, (size_t) (sizeof(columndef[0]) * columns));
276
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
277
    share->keydef= (HP_KEYDEF*) (share->column_defs + columns);
1 by brian
clean slate
278
    share->key_stat_version= 1;
279
    keyseg= (HA_KEYSEG*) (share->keydef + keys);
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
280
    init_block(&share->recordspace.block, chunk_length, min_records, max_records);
281
    /* Fix keys */
1 by brian
clean slate
282
    memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
283
    for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
284
    {
285
      keyinfo->seg= keyseg;
286
      memcpy(keyseg, keydef[i].seg,
287
	     (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
288
      keyseg+= keydef[i].keysegs;
289
290
      if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
291
      {
292
	/* additional HA_KEYTYPE_END keyseg */
293
	keyseg->type=     HA_KEYTYPE_END;
481 by Brian Aker
Remove all of uchar.
294
	keyseg->length=   sizeof(unsigned char*);
1 by brian
clean slate
295
	keyseg->flag=     0;
296
	keyseg->null_bit= 0;
297
	keyseg++;
298
481 by Brian Aker
Remove all of uchar.
299
	init_tree(&keyinfo->rb_tree, 0, 0, sizeof(unsigned char*),
1 by brian
clean slate
300
		  (qsort_cmp2)keys_compare, 1, NULL, NULL);
301
	keyinfo->delete_key= hp_rb_delete_key;
302
	keyinfo->write_key= hp_rb_write_key;
303
      }
304
      else
305
      {
306
	init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
307
		   max_records);
308
	keyinfo->delete_key= hp_delete_key;
309
	keyinfo->write_key= hp_write_key;
310
        keyinfo->hash_buckets= 0;
311
      }
312
      if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
313
        share->auto_key= i + 1;
314
    }
315
    share->min_records= min_records;
316
    share->max_records= max_records;
317
    share->max_table_size= create_info->max_table_size;
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
318
    share->index_length= 0;
1 by brian
clean slate
319
    share->blength= 1;
320
    share->keys= keys;
321
    share->max_key_length= max_length;
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
322
    share->column_count= columns;
1 by brian
clean slate
323
    share->changed= 0;
324
    share->auto_key= create_info->auto_key;
325
    share->auto_key_type= create_info->auto_key_type;
326
    share->auto_increment= create_info->auto_increment;
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
327
328
    share->fixed_data_length= fixed_data_length;
329
    share->fixed_column_count= fixed_column_count;
330
331
    share->recordspace.chunk_length= chunk_length;
332
    share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
333
    share->recordspace.is_variable_size= is_variable_size;
334
    share->recordspace.total_data_length= 0;
335
336
    if (is_variable_size) {
337
      share->recordspace.offset_link= chunk_dataspace_length;
481 by Brian Aker
Remove all of uchar.
338
      share->recordspace.offset_status= share->recordspace.offset_link + sizeof(unsigned char**);
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
339
    } else {
340
      share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
341
      share->recordspace.offset_status= chunk_dataspace_length;
342
    }
343
1 by brian
clean slate
344
    /* Must be allocated separately for rename to work */
656.1.25 by Monty Taylor
Removed my_malloc stuff from storage/
345
    if (!(share->name= strdup(name)))
1 by brian
clean slate
346
    {
481 by Brian Aker
Remove all of uchar.
347
      free((unsigned char*) share);
1 by brian
clean slate
348
      goto err;
349
    }
350
    thr_lock_init(&share->lock);
398.1.10 by Monty Taylor
Actually removed VOID() this time.
351
    pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST);
1 by brian
clean slate
352
    if (!create_info->internal_table)
353
    {
354
      share->open_list.data= (void*) share;
355
      heap_share_list= list_add(heap_share_list,&share->open_list);
356
    }
357
    else
358
      share->delete_on_close= 1;
359
  }
360
  if (!create_info->internal_table)
361
    pthread_mutex_unlock(&THR_LOCK_heap);
362
363
  *res= share;
51.3.1 by Jay Pipes
Removed all DBUG symbols from heap storage engine
364
  return(0);
1 by brian
clean slate
365
366
err:
367
  if (!create_info->internal_table)
368
    pthread_mutex_unlock(&THR_LOCK_heap);
51.3.1 by Jay Pipes
Removed all DBUG symbols from heap storage engine
369
  return(1);
1 by brian
clean slate
370
} /* heap_create */
371
372
481 by Brian Aker
Remove all of uchar.
373
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2)
1 by brian
clean slate
374
{
482 by Brian Aker
Remove uint.
375
  uint32_t not_used[2];
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
376
  return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
1 by brian
clean slate
377
		    param->search_flag, not_used);
378
}
379
482 by Brian Aker
Remove uint.
380
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
291 by Brian Aker
Head ulong conversion.
381
		       uint32_t max_records)
1 by brian
clean slate
382
{
482 by Brian Aker
Remove uint.
383
  uint32_t i,recbuffer,records_in_block;
1 by brian
clean slate
384
398.1.4 by Monty Taylor
Renamed max/min.
385
  max_records= cmax(min_records,max_records);
1 by brian
clean slate
386
  if (!max_records)
387
    max_records= 1000;			/* As good as quess as anything */
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
388
244.1.1 by Harrison Fisk
Port Ebay/Google memory storage engine variable width columns.
389
  /* we want to start each chunk at 8 bytes boundary, round recbuffer to the next 8 */
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
390
  recbuffer= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
1 by brian
clean slate
391
  records_in_block= max_records / 10;
392
  if (records_in_block < 10 && max_records)
393
    records_in_block= 10;
394
  if (!records_in_block || records_in_block*recbuffer >
395
      (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
396
    records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
397
		      HP_MAX_LEVELS) / recbuffer + 1;
398
  block->records_in_block= records_in_block;
399
  block->recbuffer= recbuffer;
400
  block->last_allocated= 0L;
401
402
  for (i= 0; i <= HP_MAX_LEVELS; i++)
403
    block->level_info[i].records_under_level=
404
      (!i ? 1 : i == 1 ? records_in_block :
405
       HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
406
}
407
408
409
static inline void heap_try_free(HP_SHARE *share)
410
{
411
  if (share->open_count == 0)
412
    hp_free(share);
413
  else
414
    share->delete_on_close= 1;
415
}
416
417
418
int heap_delete_table(const char *name)
419
{
420
  int result;
421
  register HP_SHARE *share;
422
423
  pthread_mutex_lock(&THR_LOCK_heap);
424
  if ((share= hp_find_named_heap(name)))
425
  {
426
    heap_try_free(share);
427
    result= 0;
428
  }
429
  else
430
  {
431
    result= my_errno=ENOENT;
432
  }
433
  pthread_mutex_unlock(&THR_LOCK_heap);
51.3.1 by Jay Pipes
Removed all DBUG symbols from heap storage engine
434
  return(result);
1 by brian
clean slate
435
}
436
437
438
void heap_drop_table(HP_INFO *info)
439
{
440
  pthread_mutex_lock(&THR_LOCK_heap);
441
  heap_try_free(info->s);
442
  pthread_mutex_unlock(&THR_LOCK_heap);
51.3.1 by Jay Pipes
Removed all DBUG symbols from heap storage engine
443
  return;
1 by brian
clean slate
444
}
445
446
447
void hp_free(HP_SHARE *share)
448
{
449
  if (share->open_list.data)                    /* If not internal table */
450
    heap_share_list= list_delete(heap_share_list, &share->open_list);
451
  hp_clear(share);			/* Remove blocks from memory */
452
  thr_lock_delete(&share->lock);
398.1.10 by Monty Taylor
Actually removed VOID() this time.
453
  pthread_mutex_destroy(&share->intern_lock);
481 by Brian Aker
Remove all of uchar.
454
  free((unsigned char*) share->name);
455
  free((unsigned char*) share);
1 by brian
clean slate
456
  return;
457
}