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 void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
28
uint32_t max_records);
30
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
31
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + ALIGN_SIZE(sizeof(unsigned char)))
33
/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
34
#define VARIABLE_MIN_CHUNK_SIZE \
35
((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1))
38
/* Create a heap table */
40
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)
47
uint32_t i, key_segs, max_length, length;
48
uint32_t max_rows_for_stated_memory;
52
if (not create_info->internal_table)
55
if ((share= hp_find_named_heap(name)) && share->open_count == 0)
64
size_t chunk_dataspace_length;
65
uint32_t chunk_length;
66
uint32_t fixed_data_length, fixed_column_count;
69
if (create_info->max_chunk_size)
71
uint32_t configured_chunk_size= create_info->max_chunk_size;
73
/* User requested variable-size records, let's see if they're possible */
75
if (configured_chunk_size < key_part_size)
77
/* Eventual chunk_size cannot be smaller than key data,
78
which allows all keys to fit into the first chunk */
79
my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
80
THR_LOCK_heap.unlock();
81
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;
89
/* if max_chunk_size is not specified, put the whole record in one chunk */
90
chunk_dataspace_length= reclength;
94
fixed_data_length= reclength;
95
fixed_column_count= columns;
99
We store unsigned char* del_link inside the data area of deleted records,
100
so the data length should be at least sizeof(unsigned char*)
102
set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
105
chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
108
/* Align chunk length to the next pointer */
109
chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
113
for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
115
memset(&keyinfo->block, 0, sizeof(keyinfo->block));
116
for (uint32_t j= length= 0; j < keyinfo->keysegs; j++)
118
length+= keyinfo->seg[j].length;
119
if (keyinfo->seg[j].null_bit)
122
if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
123
keyinfo->flag|= HA_NULL_PART_KEY;
125
switch (keyinfo->seg[j].type) {
126
case HA_KEYTYPE_LONG_INT:
127
case HA_KEYTYPE_DOUBLE:
128
case HA_KEYTYPE_ULONG_INT:
129
case HA_KEYTYPE_LONGLONG:
130
case HA_KEYTYPE_ULONGLONG:
131
keyinfo->seg[j].flag|= HA_SWAP_KEY;
133
case HA_KEYTYPE_VARBINARY1:
134
/* Case-insensitiveness is handled in coll->hash_sort */
135
keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
137
case HA_KEYTYPE_VARTEXT1:
138
keyinfo->flag|= HA_VAR_LENGTH_KEY;
140
/* Save number of bytes used to store length */
141
keyinfo->seg[j].bit_start= 1;
143
case HA_KEYTYPE_VARBINARY2:
144
/* Case-insensitiveness is handled in coll->hash_sort */
146
case HA_KEYTYPE_VARTEXT2:
147
keyinfo->flag|= HA_VAR_LENGTH_KEY;
149
/* Save number of bytes used to store length */
150
keyinfo->seg[j].bit_start= 2;
152
Make future comparison simpler by only having to check for
155
keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
161
keyinfo->length= length;
162
if (length > max_length)
164
key_segs+= keyinfo->keysegs;
168
if (keys && !(share->keydef= new HP_KEYDEF[keys]))
170
if (keys && !(share->keydef->seg= new HA_KEYSEG[key_segs]))
174
Max_records is used for estimating block sizes and for enforcement.
175
Calculate the very maximum number of rows (if everything was one chunk) and
176
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 /
179
(keys_memory_size + chunk_length));
180
max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
181
max_records : max_rows_for_stated_memory);
183
share->key_stat_version= 1;
184
keyseg= keys ? share->keydef->seg : NULL;
186
init_block(&share->recordspace.block, chunk_length, min_records, max_records);
188
memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
189
for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
191
keyinfo->seg= keyseg;
192
memcpy(keyseg, keydef[i].seg,
193
(size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194
keyseg+= keydef[i].keysegs;
196
init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
198
keyinfo->hash_buckets= 0;
200
if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
201
share->auto_key= i + 1;
203
share->min_records= min_records;
204
share->max_records= max_records;
205
share->max_table_size= create_info->max_table_size;
206
share->index_length= 0;
209
share->max_key_length= max_length;
210
share->column_count= columns;
212
share->auto_key= create_info->auto_key;
213
share->auto_key_type= create_info->auto_key_type;
214
share->auto_increment= create_info->auto_increment;
216
share->fixed_data_length= fixed_data_length;
217
share->fixed_column_count= fixed_column_count;
219
share->recordspace.chunk_length= chunk_length;
220
share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
221
share->recordspace.total_data_length= 0;
224
share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
225
share->recordspace.offset_status= chunk_dataspace_length;
228
/* Must be allocated separately for rename to work */
229
share->name.append(name);
230
if (!create_info->internal_table)
232
heap_share_list.push_front(share);
235
share->delete_on_close= 1;
237
if (!create_info->internal_table)
238
THR_LOCK_heap.unlock();
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();
256
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
257
uint32_t max_records)
259
uint32_t recbuffer,records_in_block;
261
max_records= max(min_records,max_records);
263
max_records= 1000; /* As good as quess as anything */
265
/* we want to start each chunk at 8 bytes boundary, round recbuffer to the next 8 */
266
recbuffer= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
267
records_in_block= max_records / 10;
268
if (records_in_block < 10 && max_records)
269
records_in_block= 10;
270
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) *
273
HP_MAX_LEVELS) / recbuffer + 1;
274
block->records_in_block= records_in_block;
275
block->recbuffer= recbuffer;
276
block->last_allocated= 0L;
278
for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
280
block->level_info[i].records_under_level=
281
(!i ? 1 : i == 1 ? records_in_block :
282
HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
287
static inline void heap_try_free(HP_SHARE *share)
289
if (share->open_count == 0)
292
share->delete_on_close= 1;
296
int heap_delete_table(const char *name)
299
register HP_SHARE *share;
301
THR_LOCK_heap.lock();
302
if ((share= hp_find_named_heap(name)))
304
heap_try_free(share);
309
result= errno=ENOENT;
311
THR_LOCK_heap.unlock();
316
void hp_free(HP_SHARE *share)
318
heap_share_list.remove(share); /* If not internal table */
319
hp_clear(share); /* Remove blocks from memory */
321
delete [] share->keydef->seg;
322
delete [] share->keydef;