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 */
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,
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
#include "libdrizzle/drizzle_com.h"
18
#include "drizzled/error.h"
20
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2);
21
static void init_block(HP_BLOCK *block,uint chunk_length, uint32_t min_records,
28
22
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)));
24
#define FIXED_REC_OVERHEAD (sizeof(uchar))
25
#define VARIABLE_REC_OVERHEAD (sizeof(uchar**) + sizeof(uchar))
33
27
/* 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));
28
#define VARIABLE_MIN_CHUNK_SIZE \
29
((sizeof(uchar**) + VARIABLE_REC_OVERHEAD + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1))
38
32
/* 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)
34
int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
35
uint columns, HP_COLUMNDEF *columndef,
36
uint max_key_fieldnr, uint key_part_size,
37
uint reclength, uint keys_memory_size,
38
uint32_t max_records, uint32_t min_records,
39
HP_CREATE_INFO *create_info, HP_SHARE **res)
47
uint32_t i, key_segs, max_length, length;
41
uint i, j, key_segs, max_length, length;
48
42
uint32_t max_rows_for_stated_memory;
49
43
HP_SHARE *share= 0;
52
if (not create_info->internal_table)
46
if (!create_info->internal_table)
48
pthread_mutex_lock(&THR_LOCK_heap);
55
49
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;
58
uint chunk_dataspace_length, chunk_length, is_variable_size;
59
uint fixed_data_length, fixed_column_count;
67
60
HP_KEYDEF *keyinfo;
69
62
if (create_info->max_chunk_size)
71
uint32_t configured_chunk_size= create_info->max_chunk_size;
64
uint configured_chunk_size= create_info->max_chunk_size;
73
66
/* User requested variable-size records, let's see if they're possible */
75
68
if (configured_chunk_size < key_part_size)
77
70
/* Eventual chunk_size cannot be smaller than key data,
78
which allows all keys to fit into the first chunk */
71
which allows all keys to fit into the first chunk */
79
72
my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
80
THR_LOCK_heap.unlock();
73
pthread_mutex_unlock(&THR_LOCK_heap);
81
74
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;
77
if ((reclength - configured_chunk_size) >= VARIABLE_MIN_CHUNK_SIZE<<1)
79
/* Allow variable size only if we're saving at least two smallest chunks */
80
/* There has to be at least one field after indexed fields */
81
/* Note that NULL bits are already included in key_part_size */
83
chunk_dataspace_length= configured_chunk_size;
87
/* max_chunk_size is near the full reclength, let's use fixed size */
89
chunk_dataspace_length= reclength;
92
else if (create_info->is_dynamic)
94
/* User asked for dynamic records - use 256 as the chunk size */
95
if ((key_part_size + VARIABLE_REC_OVERHEAD) > 256)
96
chunk_dataspace_length= key_part_size;
98
chunk_dataspace_length= 256 - VARIABLE_REC_OVERHEAD;
89
104
/* if max_chunk_size is not specified, put the whole record in one chunk */
90
106
chunk_dataspace_length= reclength;
109
if (is_variable_size)
111
/* Check whether we have any variable size records past key data */
112
uint has_variable_fields= 0;
114
fixed_data_length= key_part_size;
115
fixed_column_count= max_key_fieldnr;
117
for (i= max_key_fieldnr; i < columns; i++)
119
HP_COLUMNDEF* column= columndef + i;
120
if (column->type == DRIZZLE_TYPE_VARCHAR && column->length >= 32)
122
/* The field has to be >= 5.0.3 true VARCHAR and have substantial length */
123
/* TODO: do we want to calculate minimum length? */
124
has_variable_fields= 1;
128
if (has_variable_fields)
133
if ((column->offset + column->length) <= chunk_dataspace_length)
135
/* Still no variable-size columns, add one fixed-length */
136
fixed_column_count= i + 1;
137
fixed_data_length= column->offset + column->length;
141
if (!has_variable_fields)
143
/* There is no need to use variable-size records without variable-size columns */
144
/* Reset sizes if it's not variable size anymore */
146
chunk_dataspace_length= reclength;
147
fixed_data_length= reclength;
148
fixed_column_count= columns;
94
153
fixed_data_length= reclength;
95
154
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*)
158
We store uchar* del_link inside the data area of deleted records,
159
so the data length should be at least sizeof(uchar*)
102
set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
161
set_if_bigger(chunk_dataspace_length, sizeof (uchar**));
163
if (is_variable_size)
165
chunk_length= chunk_dataspace_length + VARIABLE_REC_OVERHEAD;
105
169
chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
108
172
/* Align chunk length to the next pointer */
109
chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
173
chunk_length= (uint) (chunk_length + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
113
177
for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
115
179
memset(&keyinfo->block, 0, sizeof(keyinfo->block));
116
for (uint32_t j= length= 0; j < keyinfo->keysegs; j++)
180
memset(&keyinfo->rb_tree , 0, sizeof(keyinfo->rb_tree));
181
for (j= length= 0; j < keyinfo->keysegs; j++)
118
183
length+= keyinfo->seg[j].length;
119
184
if (keyinfo->seg[j].null_bit)
219
325
share->recordspace.chunk_length= chunk_length;
220
326
share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
327
share->recordspace.is_variable_size= is_variable_size;
221
328
share->recordspace.total_data_length= 0;
330
if (is_variable_size) {
331
share->recordspace.offset_link= chunk_dataspace_length;
332
share->recordspace.offset_status= share->recordspace.offset_link + sizeof(uchar**);
224
334
share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
225
335
share->recordspace.offset_status= chunk_dataspace_length;
228
338
/* Must be allocated separately for rename to work */
229
share->name.append(name);
339
if (!(share->name= my_strdup(name,MYF(0))))
341
my_free((uchar*) share,MYF(0));
344
thr_lock_init(&share->lock);
345
VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
230
346
if (!create_info->internal_table)
232
heap_share_list.push_front(share);
348
share->open_list.data= (void*) share;
349
heap_share_list= list_add(heap_share_list,&share->open_list);
235
352
share->delete_on_close= 1;
237
354
if (!create_info->internal_table)
238
THR_LOCK_heap.unlock();
355
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();
361
if (!create_info->internal_table)
362
pthread_mutex_unlock(&THR_LOCK_heap);
253
364
} /* heap_create */
256
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
367
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
370
return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
371
param->search_flag, not_used);
374
static void init_block(HP_BLOCK *block, uint chunk_length, uint32_t min_records,
257
375
uint32_t max_records)
259
uint32_t recbuffer,records_in_block;
377
uint i,recbuffer,records_in_block;
261
379
max_records= max(min_records,max_records);
262
380
if (!max_records)
263
381
max_records= 1000; /* As good as quess as anything */
265
383
/* 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);
384
recbuffer= (uint) (chunk_length + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
267
385
records_in_block= max_records / 10;
268
386
if (records_in_block < 10 && max_records)
269
387
records_in_block= 10;
270
388
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) *
389
(my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
390
records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
273
391
HP_MAX_LEVELS) / recbuffer + 1;
274
392
block->records_in_block= records_in_block;
275
393
block->recbuffer= recbuffer;
276
394
block->last_allocated= 0L;
278
for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
396
for (i= 0; i <= HP_MAX_LEVELS; i++)
280
397
block->level_info[i].records_under_level=
281
398
(!i ? 1 : i == 1 ? records_in_block :
282
399
HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);