12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
#include "heap_priv.h"
18
18
#include <drizzled/common.h>
19
19
#include <drizzled/error.h>
21
21
#include <string.h>
25
using namespace drizzled;
23
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2);
27
24
static void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
28
25
uint32_t max_records);
30
static const int FIXED_REC_OVERHEAD = (sizeof(unsigned char));
31
static const int VARIABLE_REC_OVERHEAD = (sizeof(unsigned char**) + ALIGN_SIZE(sizeof(unsigned char)));
27
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
28
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + sizeof(unsigned char))
33
30
/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
34
static const int VARIABLE_MIN_CHUNK_SIZE =
35
((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1));
31
#define VARIABLE_MIN_CHUNK_SIZE \
32
((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1))
38
35
/* Create a heap table */
40
37
int heap_create(const char *name, uint32_t keys, HP_KEYDEF *keydef,
42
uint32_t key_part_size,
43
uint32_t reclength, uint32_t keys_memory_size,
44
uint32_t max_records, uint32_t min_records,
45
HP_CREATE_INFO *create_info, HP_SHARE **res)
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,
41
uint32_t max_records, uint32_t min_records,
42
HP_CREATE_INFO *create_info, HP_SHARE **res)
47
uint32_t i, key_segs, max_length, length;
44
uint32_t i, j, key_segs, max_length, length;
48
45
uint32_t max_rows_for_stated_memory;
49
46
HP_SHARE *share= 0;
52
if (not create_info->internal_table)
49
if (!create_info->internal_table)
51
pthread_mutex_lock(&THR_LOCK_heap);
55
52
if ((share= hp_find_named_heap(name)) && share->open_count == 0)
75
71
if (configured_chunk_size < key_part_size)
77
73
/* Eventual chunk_size cannot be smaller than key data,
78
which allows all keys to fit into the first chunk */
74
which allows all keys to fit into the first chunk */
79
75
my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
80
THR_LOCK_heap.unlock();
76
pthread_mutex_unlock(&THR_LOCK_heap);
81
77
return(ER_CANT_USE_OPTION_HERE);
84
/* max_chunk_size is near the full reclength, let's use fixed size */
85
chunk_dataspace_length= reclength;
80
if ((reclength - configured_chunk_size) >= VARIABLE_MIN_CHUNK_SIZE<<1)
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 */
86
chunk_dataspace_length= configured_chunk_size;
90
/* max_chunk_size is near the full reclength, let's use fixed size */
92
chunk_dataspace_length= reclength;
95
else if (create_info->is_dynamic)
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;
101
chunk_dataspace_length= 256 - VARIABLE_REC_OVERHEAD;
89
107
/* if max_chunk_size is not specified, put the whole record in one chunk */
90
109
chunk_dataspace_length= reclength;
112
if (is_variable_size)
114
/* Check whether we have any variable size records past key data */
115
uint32_t has_variable_fields= 0;
117
fixed_data_length= key_part_size;
118
fixed_column_count= max_key_fieldnr;
120
for (i= max_key_fieldnr; i < columns; i++)
122
HP_COLUMNDEF* column= columndef + i;
123
if (column->type == DRIZZLE_TYPE_VARCHAR && column->length >= 32)
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;
131
if (has_variable_fields)
136
if ((column->offset + column->length) <= chunk_dataspace_length)
138
/* Still no variable-size columns, add one fixed-length */
139
fixed_column_count= i + 1;
140
fixed_data_length= column->offset + column->length;
144
if (!has_variable_fields)
146
/* There is no need to use variable-size records without variable-size columns */
147
/* Reset sizes if it's not variable size anymore */
149
chunk_dataspace_length= reclength;
150
fixed_data_length= reclength;
151
fixed_column_count= columns;
94
156
fixed_data_length= reclength;
95
157
fixed_column_count= columns;
113
180
for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
115
182
memset(&keyinfo->block, 0, sizeof(keyinfo->block));
116
for (uint32_t j= length= 0; j < keyinfo->keysegs; j++)
183
memset(&keyinfo->rb_tree , 0, sizeof(keyinfo->rb_tree));
184
for (j= length= 0; j < keyinfo->keysegs; j++)
118
186
length+= keyinfo->seg[j].length;
119
187
if (keyinfo->seg[j].null_bit)
122
190
if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
123
191
keyinfo->flag|= HA_NULL_PART_KEY;
192
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
193
keyinfo->rb_tree.size_of_element++;
125
195
switch (keyinfo->seg[j].type) {
196
case HA_KEYTYPE_SHORT_INT:
126
197
case HA_KEYTYPE_LONG_INT:
198
case HA_KEYTYPE_FLOAT:
127
199
case HA_KEYTYPE_DOUBLE:
200
case HA_KEYTYPE_USHORT_INT:
128
201
case HA_KEYTYPE_ULONG_INT:
129
202
case HA_KEYTYPE_LONGLONG:
130
203
case HA_KEYTYPE_ULONGLONG:
204
case HA_KEYTYPE_INT24:
205
case HA_KEYTYPE_UINT24:
206
case HA_KEYTYPE_INT8:
131
207
keyinfo->seg[j].flag|= HA_SWAP_KEY;
133
209
case HA_KEYTYPE_VARBINARY1:
161
237
keyinfo->length= length;
238
length+= keyinfo->rb_tree.size_of_element +
239
((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(unsigned char*) : 0);
162
240
if (length > max_length)
163
241
max_length= length;
164
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;
168
if (keys && !(share->keydef= new HP_KEYDEF[keys]))
170
if (keys && !(share->keydef->seg= new HA_KEYSEG[key_segs]))
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));
174
274
Max_records is used for estimating block sizes and for enforcement.
175
275
Calculate the very maximum number of rows (if everything was one chunk) and
176
276
then take either that value or configured max_records (pick smallest one)
178
max_rows_for_stated_memory= (uint32_t)(create_info->max_table_size /
278
max_rows_for_stated_memory= (ha_rows) (create_info->max_table_size /
179
279
(keys_memory_size + chunk_length));
180
280
max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
181
281
max_records : max_rows_for_stated_memory);
283
memcpy(share->column_defs, columndef, (size_t) (sizeof(columndef[0]) * columns));
183
285
share->key_stat_version= 1;
184
286
keyseg= keys ? share->keydef->seg : NULL;
192
294
memcpy(keyseg, keydef[i].seg,
193
295
(size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194
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, 1, NULL, NULL);
309
keyinfo->delete_key= hp_rb_delete_key;
310
keyinfo->write_key= hp_rb_write_key;
196
314
init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
316
keyinfo->delete_key= hp_delete_key;
317
keyinfo->write_key= hp_write_key;
198
318
keyinfo->hash_buckets= 0;
200
320
if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
219
339
share->recordspace.chunk_length= chunk_length;
220
340
share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
341
share->recordspace.is_variable_size= is_variable_size;
221
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**);
224
348
share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
225
349
share->recordspace.offset_status= chunk_dataspace_length;
228
352
/* Must be allocated separately for rename to work */
229
share->name.append(name);
353
if (!(share->name= strdup(name)))
357
thr_lock_init(&share->lock);
358
pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST);
230
359
if (!create_info->internal_table)
232
heap_share_list.push_front(share);
361
share->open_list.data= (void*) share;
362
heap_share_list= list_add(heap_share_list,&share->open_list);
235
365
share->delete_on_close= 1;
237
367
if (!create_info->internal_table)
238
THR_LOCK_heap.unlock();
368
pthread_mutex_unlock(&THR_LOCK_heap);
244
if (share && share->keydef && share->keydef->seg)
245
delete [] share->keydef->seg;
246
if (share && share->keydef)
247
delete [] share->keydef;
250
if (not create_info->internal_table)
251
THR_LOCK_heap.unlock();
374
if(share && share->keydef && share->keydef->seg)
375
free(share->keydef->seg);
376
if(share && share->keydef)
378
if(share && share->column_defs)
379
free(share->column_defs);
382
if (!create_info->internal_table)
383
pthread_mutex_unlock(&THR_LOCK_heap);
253
385
} /* heap_create */
388
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2)
390
uint32_t not_used[2];
391
return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
392
param->search_flag, not_used);
256
395
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
257
396
uint32_t max_records)
259
uint32_t recbuffer,records_in_block;
398
uint32_t i,recbuffer,records_in_block;
261
max_records= max(min_records,max_records);
400
max_records= cmax(min_records,max_records);
262
401
if (!max_records)
263
402
max_records= 1000; /* As good as quess as anything */
268
407
if (records_in_block < 10 && max_records)
269
408
records_in_block= 10;
270
409
if (!records_in_block || records_in_block*recbuffer >
271
(internal::my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
272
records_in_block= (internal::my_default_record_cache_size - sizeof(HP_PTRS) *
410
(my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
411
records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
273
412
HP_MAX_LEVELS) / recbuffer + 1;
274
413
block->records_in_block= records_in_block;
275
414
block->recbuffer= recbuffer;
276
415
block->last_allocated= 0L;
278
for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
417
for (i= 0; i <= HP_MAX_LEVELS; i++)
280
418
block->level_info[i].records_under_level=
281
419
(!i ? 1 : i == 1 ? records_in_block :
282
420
HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
309
result= errno=ENOENT;
446
result= my_errno=ENOENT;
311
THR_LOCK_heap.unlock();
448
pthread_mutex_unlock(&THR_LOCK_heap);
453
void heap_drop_table(HP_INFO *info)
455
pthread_mutex_lock(&THR_LOCK_heap);
456
heap_try_free(info->s);
457
pthread_mutex_unlock(&THR_LOCK_heap);
316
462
void hp_free(HP_SHARE *share)
318
heap_share_list.remove(share); /* If not internal table */
464
if (share->open_list.data) /* If not internal table */
465
heap_share_list= list_delete(heap_share_list, &share->open_list);
319
466
hp_clear(share); /* Remove blocks from memory */
321
delete [] share->keydef->seg;
322
delete [] share->keydef;
467
thr_lock_delete(&share->lock);
468
pthread_mutex_destroy(&share->intern_lock);
470
free(share->keydef->seg);
473
free(share->column_defs);
474
free((unsigned char*) share->name);
475
free((unsigned char*) share);