1
/* Copyright (C) 2000-2006 MySQL AB
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.
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.
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 */
16
#include "heap_priv.h"
18
#include <drizzled/common.h>
19
#include <drizzled/error.h>
25
using namespace drizzled;
27
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2);
28
static void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
29
uint32_t max_records);
31
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
32
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + ALIGN_SIZE(sizeof(unsigned char)))
34
/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
35
#define VARIABLE_MIN_CHUNK_SIZE \
36
((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1))
39
/* Create a heap table */
41
int heap_create(const char *name, uint32_t keys, HP_KEYDEF *keydef,
42
uint32_t columns, HP_COLUMNDEF *columndef,
43
uint32_t max_key_fieldnr, uint32_t key_part_size,
44
uint32_t reclength, uint32_t keys_memory_size,
45
uint32_t max_records, uint32_t min_records,
46
HP_CREATE_INFO *create_info, HP_SHARE **res)
48
uint32_t i, j, key_segs, max_length, length;
49
uint32_t max_rows_for_stated_memory;
53
if (!create_info->internal_table)
55
pthread_mutex_lock(&THR_LOCK_heap);
56
if ((share= hp_find_named_heap(name)) && share->open_count == 0)
65
size_t chunk_dataspace_length;
66
uint32_t chunk_length, is_variable_size;
67
uint32_t fixed_data_length, fixed_column_count;
70
if (create_info->max_chunk_size)
72
uint32_t configured_chunk_size= create_info->max_chunk_size;
74
/* User requested variable-size records, let's see if they're possible */
76
if (configured_chunk_size < key_part_size)
78
/* Eventual chunk_size cannot be smaller than key data,
79
which allows all keys to fit into the first chunk */
80
my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
81
pthread_mutex_unlock(&THR_LOCK_heap);
82
return(ER_CANT_USE_OPTION_HERE);
85
if ((reclength - configured_chunk_size) >= VARIABLE_MIN_CHUNK_SIZE<<1)
87
/* Allow variable size only if we're saving at least two smallest chunks */
88
/* There has to be at least one field after indexed fields */
89
/* Note that NULL bits are already included in key_part_size */
91
chunk_dataspace_length= configured_chunk_size;
95
/* max_chunk_size is near the full reclength, let's use fixed size */
97
chunk_dataspace_length= reclength;
100
else if (create_info->is_dynamic)
102
/* User asked for dynamic records - use 256 as the chunk size */
103
if ((key_part_size + VARIABLE_REC_OVERHEAD) > 256)
104
chunk_dataspace_length= key_part_size;
106
chunk_dataspace_length= 256 - VARIABLE_REC_OVERHEAD;
112
/* if max_chunk_size is not specified, put the whole record in one chunk */
114
chunk_dataspace_length= reclength;
117
if (is_variable_size)
119
/* Check whether we have any variable size records past key data */
120
uint32_t has_variable_fields= 0;
122
fixed_data_length= key_part_size;
123
fixed_column_count= max_key_fieldnr;
125
for (i= max_key_fieldnr; i < columns; i++)
127
HP_COLUMNDEF* column= columndef + i;
128
if (column->type == DRIZZLE_TYPE_VARCHAR && column->length >= 32)
130
/* The field has to be >= 5.0.3 true VARCHAR and have substantial length */
131
/* TODO: do we want to calculate minimum length? */
132
has_variable_fields= 1;
136
if (has_variable_fields)
141
if ((column->offset + column->length) <= chunk_dataspace_length)
143
/* Still no variable-size columns, add one fixed-length */
144
fixed_column_count= i + 1;
145
fixed_data_length= column->offset + column->length;
149
if (!has_variable_fields)
151
/* There is no need to use variable-size records without variable-size columns */
152
/* Reset sizes if it's not variable size anymore */
154
chunk_dataspace_length= reclength;
155
fixed_data_length= reclength;
156
fixed_column_count= columns;
161
fixed_data_length= reclength;
162
fixed_column_count= columns;
166
We store unsigned char* del_link inside the data area of deleted records,
167
so the data length should be at least sizeof(unsigned char*)
169
set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
171
if (is_variable_size)
173
chunk_length= chunk_dataspace_length + VARIABLE_REC_OVERHEAD;
177
chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
180
/* Align chunk length to the next pointer */
181
chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
185
for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
187
memset(&keyinfo->block, 0, sizeof(keyinfo->block));
188
memset(&keyinfo->rb_tree , 0, sizeof(keyinfo->rb_tree));
189
for (j= length= 0; j < keyinfo->keysegs; j++)
191
length+= keyinfo->seg[j].length;
192
if (keyinfo->seg[j].null_bit)
195
if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
196
keyinfo->flag|= HA_NULL_PART_KEY;
197
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
198
keyinfo->rb_tree.size_of_element++;
200
switch (keyinfo->seg[j].type) {
201
case HA_KEYTYPE_LONG_INT:
202
case HA_KEYTYPE_DOUBLE:
203
case HA_KEYTYPE_ULONG_INT:
204
case HA_KEYTYPE_LONGLONG:
205
case HA_KEYTYPE_ULONGLONG:
206
case HA_KEYTYPE_UINT24:
207
keyinfo->seg[j].flag|= HA_SWAP_KEY;
209
case HA_KEYTYPE_VARBINARY1:
210
/* Case-insensitiveness is handled in coll->hash_sort */
211
keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
213
case HA_KEYTYPE_VARTEXT1:
214
keyinfo->flag|= HA_VAR_LENGTH_KEY;
216
/* Save number of bytes used to store length */
217
keyinfo->seg[j].bit_start= 1;
219
case HA_KEYTYPE_VARBINARY2:
220
/* Case-insensitiveness is handled in coll->hash_sort */
222
case HA_KEYTYPE_VARTEXT2:
223
keyinfo->flag|= HA_VAR_LENGTH_KEY;
225
/* Save number of bytes used to store length */
226
keyinfo->seg[j].bit_start= 2;
228
Make future comparison simpler by only having to check for
231
keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
237
keyinfo->length= length;
238
length+= keyinfo->rb_tree.size_of_element +
239
((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(unsigned char*) : 0);
240
if (length > max_length)
242
key_segs+= keyinfo->keysegs;
243
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
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;
251
keyinfo->get_key_length= hp_rb_key_length;
255
if (!(share= (HP_SHARE*) malloc(sizeof(HP_SHARE))))
258
memset(share, 0, sizeof(HP_SHARE));
260
if (keys && !(share->keydef= (HP_KEYDEF*) malloc(keys*sizeof(HP_KEYDEF))))
263
memset(share->keydef, 0, keys*sizeof(HP_KEYDEF));
265
if (keys && !(share->keydef->seg= (HA_KEYSEG*) malloc(key_segs*sizeof(HA_KEYSEG))))
267
if (!(share->column_defs= (HP_COLUMNDEF*)
268
malloc(columns*sizeof(HP_COLUMNDEF))))
271
memset(share->column_defs, 0, columns*sizeof(HP_COLUMNDEF));
274
Max_records is used for estimating block sizes and for enforcement.
275
Calculate the very maximum number of rows (if everything was one chunk) and
276
then take either that value or configured max_records (pick smallest one)
278
max_rows_for_stated_memory= (uint32_t)(create_info->max_table_size /
279
(keys_memory_size + chunk_length));
280
max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
281
max_records : max_rows_for_stated_memory);
283
memcpy(share->column_defs, columndef, (size_t) (sizeof(columndef[0]) * columns));
285
share->key_stat_version= 1;
286
keyseg= keys ? share->keydef->seg : NULL;
288
init_block(&share->recordspace.block, chunk_length, min_records, max_records);
290
memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
291
for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
293
keyinfo->seg= keyseg;
294
memcpy(keyseg, keydef[i].seg,
295
(size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
296
keyseg+= keydef[i].keysegs;
298
if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
300
/* additional HA_KEYTYPE_END keyseg */
301
keyseg->type= HA_KEYTYPE_END;
302
keyseg->length= sizeof(unsigned char*);
307
init_tree(&keyinfo->rb_tree, 0, 0, sizeof(unsigned char*),
308
(qsort_cmp2)keys_compare, true, NULL, NULL);
309
keyinfo->delete_key= hp_rb_delete_key;
310
keyinfo->write_key= hp_rb_write_key;
314
init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
316
keyinfo->delete_key= hp_delete_key;
317
keyinfo->write_key= hp_write_key;
318
keyinfo->hash_buckets= 0;
320
if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
321
share->auto_key= i + 1;
323
share->min_records= min_records;
324
share->max_records= max_records;
325
share->max_table_size= create_info->max_table_size;
326
share->index_length= 0;
329
share->max_key_length= max_length;
330
share->column_count= columns;
332
share->auto_key= create_info->auto_key;
333
share->auto_key_type= create_info->auto_key_type;
334
share->auto_increment= create_info->auto_increment;
336
share->fixed_data_length= fixed_data_length;
337
share->fixed_column_count= fixed_column_count;
339
share->recordspace.chunk_length= chunk_length;
340
share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
341
share->recordspace.is_variable_size= is_variable_size;
342
share->recordspace.total_data_length= 0;
344
if (is_variable_size) {
345
share->recordspace.offset_link= chunk_dataspace_length;
346
share->recordspace.offset_status= share->recordspace.offset_link + sizeof(unsigned char**);
348
share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
349
share->recordspace.offset_status= chunk_dataspace_length;
352
/* Must be allocated separately for rename to work */
353
if (!(share->name= strdup(name)))
357
thr_lock_init(&share->lock);
358
pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST);
359
if (!create_info->internal_table)
361
heap_share_list.push_front(share);
364
share->delete_on_close= 1;
366
if (!create_info->internal_table)
367
pthread_mutex_unlock(&THR_LOCK_heap);
373
if(share && share->keydef && share->keydef->seg)
374
free(share->keydef->seg);
375
if(share && share->keydef)
377
if(share && share->column_defs)
378
free(share->column_defs);
381
if (!create_info->internal_table)
382
pthread_mutex_unlock(&THR_LOCK_heap);
387
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2)
389
uint32_t not_used[2];
390
return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
391
param->search_flag, not_used);
394
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
395
uint32_t max_records)
397
uint32_t i,recbuffer,records_in_block;
399
max_records= max(min_records,max_records);
401
max_records= 1000; /* As good as quess as anything */
403
/* we want to start each chunk at 8 bytes boundary, round recbuffer to the next 8 */
404
recbuffer= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
405
records_in_block= max_records / 10;
406
if (records_in_block < 10 && max_records)
407
records_in_block= 10;
408
if (!records_in_block || records_in_block*recbuffer >
409
(internal::my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
410
records_in_block= (internal::my_default_record_cache_size - sizeof(HP_PTRS) *
411
HP_MAX_LEVELS) / recbuffer + 1;
412
block->records_in_block= records_in_block;
413
block->recbuffer= recbuffer;
414
block->last_allocated= 0L;
416
for (i= 0; i <= HP_MAX_LEVELS; i++)
417
block->level_info[i].records_under_level=
418
(!i ? 1 : i == 1 ? records_in_block :
419
HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
423
static inline void heap_try_free(HP_SHARE *share)
425
if (share->open_count == 0)
428
share->delete_on_close= 1;
432
int heap_delete_table(const char *name)
435
register HP_SHARE *share;
437
pthread_mutex_lock(&THR_LOCK_heap);
438
if ((share= hp_find_named_heap(name)))
440
heap_try_free(share);
445
result= errno=ENOENT;
447
pthread_mutex_unlock(&THR_LOCK_heap);
452
void heap_drop_table(HP_INFO *info)
454
pthread_mutex_lock(&THR_LOCK_heap);
455
heap_try_free(info->s);
456
pthread_mutex_unlock(&THR_LOCK_heap);
461
void hp_free(HP_SHARE *share)
463
heap_share_list.remove(share); /* If not internal table */
464
hp_clear(share); /* Remove blocks from memory */
465
thr_lock_delete(&share->lock);
466
pthread_mutex_destroy(&share->intern_lock);
467
if (share->keydef && share->keydef->seg)
468
free(share->keydef->seg);
471
free(share->column_defs);
472
free((unsigned char*) share->name);
473
free((unsigned char*) share);