13
13
along with this program; if not, write to the Free Software
14
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))
18
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2);
19
static void init_block(HP_BLOCK *block,uint reclength,ulong min_records,
38
22
/* 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)
24
int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
25
uint reclength, ulong max_records, ulong min_records,
26
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;
28
uint i, j, key_segs, max_length, length;
49
29
HP_SHARE *share= 0;
31
DBUG_ENTER("heap_create");
52
if (not create_info->internal_table)
33
if (!create_info->internal_table)
35
pthread_mutex_lock(&THR_LOCK_heap);
55
36
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;
67
45
HP_KEYDEF *keyinfo;
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;
46
DBUG_PRINT("info",("Initializing new table"));
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*)
49
We have to store sometimes uchar* del_link in records,
50
so the record length should be at least sizeof(uchar*)
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);
52
set_if_bigger(reclength, sizeof (uchar*));
113
54
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++)
56
bzero((char*) &keyinfo->block,sizeof(keyinfo->block));
57
bzero((char*) &keyinfo->rb_tree ,sizeof(keyinfo->rb_tree));
58
for (j= length= 0; j < keyinfo->keysegs; j++)
118
60
length+= keyinfo->seg[j].length;
119
61
if (keyinfo->seg[j].null_bit)
114
if (keyinfo->seg[j].flag & HA_END_SPACE_ARE_EQUAL)
115
keyinfo->flag|= HA_END_SPACE_KEY;
161
117
keyinfo->length= length;
118
length+= keyinfo->rb_tree.size_of_element +
119
((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(uchar*) : 0);
162
120
if (length > max_length)
163
121
max_length= length;
164
122
key_segs+= keyinfo->keysegs;
123
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
125
key_segs++; /* additional HA_KEYTYPE_END segment */
126
if (keyinfo->flag & HA_VAR_LENGTH_KEY)
127
keyinfo->get_key_length= hp_rb_var_key_length;
128
else if (keyinfo->flag & HA_NULL_PART_KEY)
129
keyinfo->get_key_length= hp_rb_null_key_length;
131
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]))
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);
134
if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
135
keys*sizeof(HP_KEYDEF)+
136
key_segs*sizeof(HA_KEYSEG),
139
share->keydef= (HP_KEYDEF*) (share + 1);
183
140
share->key_stat_version= 1;
184
keyseg= keys ? share->keydef->seg : NULL;
186
init_block(&share->recordspace.block, chunk_length, min_records, max_records);
141
keyseg= (HA_KEYSEG*) (share->keydef + keys);
142
init_block(&share->block, reclength + 1, min_records, max_records);
188
144
memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
189
145
for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
192
148
memcpy(keyseg, keydef[i].seg,
193
149
(size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194
150
keyseg+= keydef[i].keysegs;
152
if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
154
/* additional HA_KEYTYPE_END keyseg */
155
keyseg->type= HA_KEYTYPE_END;
156
keyseg->length= sizeof(uchar*);
161
init_tree(&keyinfo->rb_tree, 0, 0, sizeof(uchar*),
162
(qsort_cmp2)keys_compare, 1, NULL, NULL);
163
keyinfo->delete_key= hp_rb_delete_key;
164
keyinfo->write_key= hp_rb_write_key;
196
168
init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
170
keyinfo->delete_key= hp_delete_key;
171
keyinfo->write_key= hp_write_key;
198
172
keyinfo->hash_buckets= 0;
200
174
if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
203
177
share->min_records= min_records;
204
178
share->max_records= max_records;
205
179
share->max_table_size= create_info->max_table_size;
206
share->index_length= 0;
180
share->data_length= share->index_length= 0;
181
share->reclength= reclength;
207
182
share->blength= 1;
208
183
share->keys= keys;
209
184
share->max_key_length= max_length;
210
share->column_count= columns;
211
185
share->changed= 0;
212
186
share->auto_key= create_info->auto_key;
213
187
share->auto_key_type= create_info->auto_key_type;
214
188
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
189
/* Must be allocated separately for rename to work */
229
share->name.append(name);
190
if (!(share->name= my_strdup(name,MYF(0))))
192
my_free((uchar*) share,MYF(0));
196
thr_lock_init(&share->lock);
197
VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
230
199
if (!create_info->internal_table)
232
heap_share_list.push_front(share);
201
share->open_list.data= (void*) share;
202
heap_share_list= list_add(heap_share_list,&share->open_list);
235
205
share->delete_on_close= 1;
237
207
if (!create_info->internal_table)
238
THR_LOCK_heap.unlock();
208
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();
214
if (!create_info->internal_table)
215
pthread_mutex_unlock(&THR_LOCK_heap);
253
217
} /* heap_create */
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;
220
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
223
return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
224
param->search_flag, not_used);
227
static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
230
uint i,recbuffer,records_in_block;
261
232
max_records= max(min_records,max_records);
262
233
if (!max_records)
263
234
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);
235
recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
267
236
records_in_block= max_records / 10;
268
237
if (records_in_block < 10 && max_records)
269
238
records_in_block= 10;
270
239
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) *
240
(my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
241
records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
273
242
HP_MAX_LEVELS) / recbuffer + 1;
274
243
block->records_in_block= records_in_block;
275
244
block->recbuffer= recbuffer;
276
245
block->last_allocated= 0L;
278
for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
247
for (i= 0; i <= HP_MAX_LEVELS; i++)
280
248
block->level_info[i].records_under_level=
281
249
(!i ? 1 : i == 1 ? records_in_block :
282
250
HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
309
result= errno=ENOENT;
277
result= my_errno=ENOENT;
311
THR_LOCK_heap.unlock();
279
pthread_mutex_unlock(&THR_LOCK_heap);
284
void heap_drop_table(HP_INFO *info)
286
DBUG_ENTER("heap_drop_table");
287
pthread_mutex_lock(&THR_LOCK_heap);
288
heap_try_free(info->s);
289
pthread_mutex_unlock(&THR_LOCK_heap);
316
294
void hp_free(HP_SHARE *share)
318
heap_share_list.remove(share); /* If not internal table */
296
if (share->open_list.data) /* If not internal table */
297
heap_share_list= list_delete(heap_share_list, &share->open_list);
319
298
hp_clear(share); /* Remove blocks from memory */
321
delete [] share->keydef->seg;
322
delete [] share->keydef;
300
thr_lock_delete(&share->lock);
301
VOID(pthread_mutex_destroy(&share->intern_lock));
303
my_free((uchar*) share->name, MYF(0));
304
my_free((uchar*) share, MYF(0));