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,
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))
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
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;
52
if (not create_info->internal_table)
32
if (!create_info->internal_table)
34
pthread_mutex_lock(&THR_LOCK_heap);
55
35
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
44
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;
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*)
47
We have to store sometimes uchar* del_link in records,
48
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);
50
set_if_bigger(reclength, sizeof (uchar*));
113
52
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++)
54
bzero((char*) &keyinfo->block,sizeof(keyinfo->block));
55
bzero((char*) &keyinfo->rb_tree ,sizeof(keyinfo->rb_tree));
56
for (j= length= 0; j < keyinfo->keysegs; j++)
118
58
length+= keyinfo->seg[j].length;
119
59
if (keyinfo->seg[j].null_bit)
161
109
keyinfo->length= length;
110
length+= keyinfo->rb_tree.size_of_element +
111
((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(uchar*) : 0);
162
112
if (length > max_length)
163
113
max_length= length;
164
114
key_segs+= keyinfo->keysegs;
115
if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
117
key_segs++; /* additional HA_KEYTYPE_END segment */
118
if (keyinfo->flag & HA_VAR_LENGTH_KEY)
119
keyinfo->get_key_length= hp_rb_var_key_length;
120
else if (keyinfo->flag & HA_NULL_PART_KEY)
121
keyinfo->get_key_length= hp_rb_null_key_length;
123
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);
126
if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
127
keys*sizeof(HP_KEYDEF)+
128
key_segs*sizeof(HA_KEYSEG),
131
share->keydef= (HP_KEYDEF*) (share + 1);
183
132
share->key_stat_version= 1;
184
keyseg= keys ? share->keydef->seg : NULL;
186
init_block(&share->recordspace.block, chunk_length, min_records, max_records);
133
keyseg= (HA_KEYSEG*) (share->keydef + keys);
134
init_block(&share->block, reclength + 1, min_records, max_records);
188
136
memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
189
137
for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
192
140
memcpy(keyseg, keydef[i].seg,
193
141
(size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194
142
keyseg+= keydef[i].keysegs;
144
if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
146
/* additional HA_KEYTYPE_END keyseg */
147
keyseg->type= HA_KEYTYPE_END;
148
keyseg->length= sizeof(uchar*);
153
init_tree(&keyinfo->rb_tree, 0, 0, sizeof(uchar*),
154
(qsort_cmp2)keys_compare, 1, NULL, NULL);
155
keyinfo->delete_key= hp_rb_delete_key;
156
keyinfo->write_key= hp_rb_write_key;
196
160
init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
162
keyinfo->delete_key= hp_delete_key;
163
keyinfo->write_key= hp_write_key;
198
164
keyinfo->hash_buckets= 0;
200
166
if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
203
169
share->min_records= min_records;
204
170
share->max_records= max_records;
205
171
share->max_table_size= create_info->max_table_size;
206
share->index_length= 0;
172
share->data_length= share->index_length= 0;
173
share->reclength= reclength;
207
174
share->blength= 1;
208
175
share->keys= keys;
209
176
share->max_key_length= max_length;
210
share->column_count= columns;
211
177
share->changed= 0;
212
178
share->auto_key= create_info->auto_key;
213
179
share->auto_key_type= create_info->auto_key_type;
214
180
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
181
/* Must be allocated separately for rename to work */
229
share->name.append(name);
182
if (!(share->name= my_strdup(name,MYF(0))))
184
my_free((uchar*) share,MYF(0));
187
thr_lock_init(&share->lock);
188
VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
230
189
if (!create_info->internal_table)
232
heap_share_list.push_front(share);
191
share->open_list.data= (void*) share;
192
heap_share_list= list_add(heap_share_list,&share->open_list);
235
195
share->delete_on_close= 1;
237
197
if (!create_info->internal_table)
238
THR_LOCK_heap.unlock();
198
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();
204
if (!create_info->internal_table)
205
pthread_mutex_unlock(&THR_LOCK_heap);
253
207
} /* 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;
210
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
213
return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
214
param->search_flag, not_used);
217
static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
220
uint i,recbuffer,records_in_block;
261
222
max_records= max(min_records,max_records);
262
223
if (!max_records)
263
224
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);
225
recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
267
226
records_in_block= max_records / 10;
268
227
if (records_in_block < 10 && max_records)
269
228
records_in_block= 10;
270
229
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) *
230
(my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
231
records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
273
232
HP_MAX_LEVELS) / recbuffer + 1;
274
233
block->records_in_block= records_in_block;
275
234
block->recbuffer= recbuffer;
276
235
block->last_allocated= 0L;
278
for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
237
for (i= 0; i <= HP_MAX_LEVELS; i++)
280
238
block->level_info[i].records_under_level=
281
239
(!i ? 1 : i == 1 ? records_in_block :
282
240
HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
309
result= errno=ENOENT;
266
result= my_errno=ENOENT;
311
THR_LOCK_heap.unlock();
268
pthread_mutex_unlock(&THR_LOCK_heap);
273
void heap_drop_table(HP_INFO *info)
275
pthread_mutex_lock(&THR_LOCK_heap);
276
heap_try_free(info->s);
277
pthread_mutex_unlock(&THR_LOCK_heap);
316
282
void hp_free(HP_SHARE *share)
318
heap_share_list.remove(share); /* If not internal table */
284
if (share->open_list.data) /* If not internal table */
285
heap_share_list= list_delete(heap_share_list, &share->open_list);
319
286
hp_clear(share); /* Remove blocks from memory */
321
delete [] share->keydef->seg;
322
delete [] share->keydef;
287
thr_lock_delete(&share->lock);
288
VOID(pthread_mutex_destroy(&share->intern_lock));
289
my_free((uchar*) share->name, MYF(0));
290
my_free((uchar*) share, MYF(0));