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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
#include "heap_priv.h"
17
#include <drizzled/internal/my_sys.h>
18
18
#include <drizzled/common.h>
19
19
#include <drizzled/error.h>
21
21
#include <string.h>
23
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2);
25
using namespace drizzled;
24
27
static void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
25
28
uint32_t max_records);
27
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
28
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + sizeof(unsigned char))
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)));
30
33
/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
31
#define VARIABLE_MIN_CHUNK_SIZE \
32
((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1))
34
static const int VARIABLE_MIN_CHUNK_SIZE =
35
((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1));
35
38
/* Create a heap table */
37
40
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,
41
uint32_t max_records, uint32_t min_records,
42
HP_CREATE_INFO *create_info, HP_SHARE **res)
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)
44
uint32_t i, j, key_segs, max_length, length;
47
uint32_t i, key_segs, max_length, length;
45
48
uint32_t max_rows_for_stated_memory;
46
49
HP_SHARE *share= 0;
49
if (!create_info->internal_table)
52
if (not create_info->internal_table)
51
pthread_mutex_lock(&THR_LOCK_heap);
52
55
if ((share= hp_find_named_heap(name)) && share->open_count == 0)
61
uint32_t chunk_dataspace_length, chunk_length, is_variable_size;
64
size_t chunk_dataspace_length;
65
uint32_t chunk_length;
62
66
uint32_t fixed_data_length, fixed_column_count;
63
67
HP_KEYDEF *keyinfo;
71
75
if (configured_chunk_size < key_part_size)
73
77
/* Eventual chunk_size cannot be smaller than key data,
74
which allows all keys to fit into the first chunk */
78
which allows all keys to fit into the first chunk */
75
79
my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
76
pthread_mutex_unlock(&THR_LOCK_heap);
80
THR_LOCK_heap.unlock();
77
81
return(ER_CANT_USE_OPTION_HERE);
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;
84
/* max_chunk_size is near the full reclength, let's use fixed size */
85
chunk_dataspace_length= reclength;
107
89
/* if max_chunk_size is not specified, put the whole record in one chunk */
109
90
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;
156
94
fixed_data_length= reclength;
157
95
fixed_column_count= columns;
176
109
chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
180
113
for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
182
115
memset(&keyinfo->block, 0, sizeof(keyinfo->block));
183
memset(&keyinfo->rb_tree , 0, sizeof(keyinfo->rb_tree));
184
for (j= length= 0; j < keyinfo->keysegs; j++)
116
for (uint32_t j= length= 0; j < keyinfo->keysegs; j++)
186
118
length+= keyinfo->seg[j].length;
187
119
if (keyinfo->seg[j].null_bit)
190
122
if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
191
123
keyinfo->flag|= HA_NULL_PART_KEY;
192
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
193
keyinfo->rb_tree.size_of_element++;
195
125
switch (keyinfo->seg[j].type) {
196
case HA_KEYTYPE_SHORT_INT:
197
126
case HA_KEYTYPE_LONG_INT:
198
case HA_KEYTYPE_FLOAT:
199
127
case HA_KEYTYPE_DOUBLE:
200
case HA_KEYTYPE_USHORT_INT:
201
128
case HA_KEYTYPE_ULONG_INT:
202
129
case HA_KEYTYPE_LONGLONG:
203
130
case HA_KEYTYPE_ULONGLONG:
204
case HA_KEYTYPE_INT24:
205
case HA_KEYTYPE_UINT24:
206
case HA_KEYTYPE_INT8:
207
131
keyinfo->seg[j].flag|= HA_SWAP_KEY;
209
133
case HA_KEYTYPE_VARBINARY1:
237
161
keyinfo->length= length;
238
length+= keyinfo->rb_tree.size_of_element +
239
((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(unsigned char*) : 0);
240
162
if (length > max_length)
241
163
max_length= length;
242
164
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;
254
if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
255
keys*sizeof(HP_KEYDEF)+
256
columns*sizeof(HP_COLUMNDEF)+
257
key_segs*sizeof(HA_KEYSEG),
168
if (keys && !(share->keydef= new HP_KEYDEF[keys]))
170
if (keys && !(share->keydef->seg= new HA_KEYSEG[key_segs]))
263
175
Calculate the very maximum number of rows (if everything was one chunk) and
264
176
then take either that value or configured max_records (pick smallest one)
266
max_rows_for_stated_memory= (ha_rows) (create_info->max_table_size /
178
max_rows_for_stated_memory= (uint32_t)(create_info->max_table_size /
267
179
(keys_memory_size + chunk_length));
268
max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
180
max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
269
181
max_records : max_rows_for_stated_memory);
271
share->column_defs= (HP_COLUMNDEF*) (share + 1);
272
memcpy(share->column_defs, columndef, (size_t) (sizeof(columndef[0]) * columns));
274
share->keydef= (HP_KEYDEF*) (share->column_defs + columns);
275
183
share->key_stat_version= 1;
276
keyseg= (HA_KEYSEG*) (share->keydef + keys);
184
keyseg= keys ? share->keydef->seg : NULL;
277
186
init_block(&share->recordspace.block, chunk_length, min_records, max_records);
279
188
memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
283
192
memcpy(keyseg, keydef[i].seg,
284
193
(size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
285
194
keyseg+= keydef[i].keysegs;
287
if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
289
/* additional HA_KEYTYPE_END keyseg */
290
keyseg->type= HA_KEYTYPE_END;
291
keyseg->length= sizeof(unsigned char*);
296
init_tree(&keyinfo->rb_tree, 0, 0, sizeof(unsigned char*),
297
(qsort_cmp2)keys_compare, 1, NULL, NULL);
298
keyinfo->delete_key= hp_rb_delete_key;
299
keyinfo->write_key= hp_rb_write_key;
303
196
init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
305
keyinfo->delete_key= hp_delete_key;
306
keyinfo->write_key= hp_write_key;
307
198
keyinfo->hash_buckets= 0;
309
200
if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
328
219
share->recordspace.chunk_length= chunk_length;
329
220
share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
330
share->recordspace.is_variable_size= is_variable_size;
331
221
share->recordspace.total_data_length= 0;
333
if (is_variable_size) {
334
share->recordspace.offset_link= chunk_dataspace_length;
335
share->recordspace.offset_status= share->recordspace.offset_link + sizeof(unsigned char**);
337
224
share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
338
225
share->recordspace.offset_status= chunk_dataspace_length;
341
228
/* Must be allocated separately for rename to work */
342
if (!(share->name= my_strdup(name,MYF(0))))
344
free((unsigned char*) share);
347
thr_lock_init(&share->lock);
348
pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST);
229
share->name.append(name);
349
230
if (!create_info->internal_table)
351
share->open_list.data= (void*) share;
352
heap_share_list= list_add(heap_share_list,&share->open_list);
232
heap_share_list.push_front(share);
355
235
share->delete_on_close= 1;
357
237
if (!create_info->internal_table)
358
pthread_mutex_unlock(&THR_LOCK_heap);
238
THR_LOCK_heap.unlock();
364
if (!create_info->internal_table)
365
pthread_mutex_unlock(&THR_LOCK_heap);
244
if (share && share->keydef)
245
delete[] share->keydef->seg;
247
delete[] share->keydef;
249
if (not create_info->internal_table)
250
THR_LOCK_heap.unlock();
367
252
} /* heap_create */
370
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2)
372
uint32_t not_used[2];
373
return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
374
param->search_flag, not_used);
377
255
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
378
256
uint32_t max_records)
380
uint32_t i,recbuffer,records_in_block;
258
uint32_t recbuffer,records_in_block;
382
max_records= cmax(min_records,max_records);
260
max_records= max(min_records,max_records);
383
261
if (!max_records)
384
262
max_records= 1000; /* As good as quess as anything */
386
264
/* we want to start each chunk at 8 bytes boundary, round recbuffer to the next 8 */
387
recbuffer= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
265
recbuffer= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
388
266
records_in_block= max_records / 10;
389
267
if (records_in_block < 10 && max_records)
390
268
records_in_block= 10;
391
269
if (!records_in_block || records_in_block*recbuffer >
392
(my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
393
records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
270
(internal::my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
271
records_in_block= (internal::my_default_record_cache_size - sizeof(HP_PTRS) *
394
272
HP_MAX_LEVELS) / recbuffer + 1;
395
273
block->records_in_block= records_in_block;
396
274
block->recbuffer= recbuffer;
397
275
block->last_allocated= 0L;
399
for (i= 0; i <= HP_MAX_LEVELS; i++)
277
for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
400
279
block->level_info[i].records_under_level=
401
280
(!i ? 1 : i == 1 ? records_in_block :
402
281
HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
428
result= my_errno=ENOENT;
308
result= errno=ENOENT;
430
pthread_mutex_unlock(&THR_LOCK_heap);
310
THR_LOCK_heap.unlock();
435
void heap_drop_table(HP_INFO *info)
437
pthread_mutex_lock(&THR_LOCK_heap);
438
heap_try_free(info->s);
439
pthread_mutex_unlock(&THR_LOCK_heap);
444
315
void hp_free(HP_SHARE *share)
446
if (share->open_list.data) /* If not internal table */
447
heap_share_list= list_delete(heap_share_list, &share->open_list);
317
heap_share_list.remove(share); /* If not internal table */
448
318
hp_clear(share); /* Remove blocks from memory */
449
thr_lock_delete(&share->lock);
450
pthread_mutex_destroy(&share->intern_lock);
451
free((unsigned char*) share->name);
452
free((unsigned char*) share);
320
delete[] share->keydef->seg;
321
delete[] share->keydef;