~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/heap/hp_create.c

  • Committer: Brian Aker
  • Date: 2009-01-07 00:04:25 UTC
  • Revision ID: brian@tangent.org-20090107000425-67n3f86rw6k423xe
Fixed index_merge_innodb test.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
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 */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
 
#include "heap_priv.h"
 
16
#include "heapdef.h"
17
17
 
18
18
#include <drizzled/common.h>
19
19
#include <drizzled/error.h>
20
20
 
21
21
#include <string.h>
22
 
#include <algorithm>
23
 
 
24
 
using namespace std;
25
 
using namespace drizzled;
26
 
 
 
22
 
 
23
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2);
27
24
static void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
28
25
                        uint32_t max_records);
29
26
 
30
27
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
31
 
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + ALIGN_SIZE(sizeof(unsigned char)))
 
28
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + sizeof(unsigned char))
32
29
 
33
30
/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
34
31
#define VARIABLE_MIN_CHUNK_SIZE \
38
35
/* Create a heap table */
39
36
 
40
37
int heap_create(const char *name, uint32_t keys, HP_KEYDEF *keydef,
41
 
                uint32_t columns,
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)
 
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)
46
43
{
47
 
  uint32_t i, key_segs, max_length, length;
 
44
  uint32_t i, j, key_segs, max_length, length;
48
45
  uint32_t max_rows_for_stated_memory;
49
46
  HP_SHARE *share= 0;
50
47
  HA_KEYSEG *keyseg;
51
48
 
52
 
  if (not create_info->internal_table)
 
49
  if (!create_info->internal_table)
53
50
  {
54
 
    THR_LOCK_heap.lock();
 
51
    pthread_mutex_lock(&THR_LOCK_heap);
55
52
    if ((share= hp_find_named_heap(name)) && share->open_count == 0)
56
53
    {
57
54
      hp_free(share);
61
58
 
62
59
  if (!share)
63
60
  {
64
 
    size_t chunk_dataspace_length;
65
 
    uint32_t chunk_length;
 
61
    uint32_t chunk_dataspace_length, chunk_length, is_variable_size;
66
62
    uint32_t fixed_data_length, fixed_column_count;
67
63
    HP_KEYDEF *keyinfo;
68
64
 
75
71
      if (configured_chunk_size < key_part_size)
76
72
      {
77
73
        /* Eventual chunk_size cannot be smaller than key data,
78
 
          which allows all keys to fit into the first chunk */
 
74
           which allows all keys to fit into the first chunk */
79
75
        my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
80
 
        THR_LOCK_heap.unlock();
 
76
        pthread_mutex_unlock(&THR_LOCK_heap);
81
77
        return(ER_CANT_USE_OPTION_HERE);
82
78
      }
83
79
 
84
 
      /* max_chunk_size is near the full reclength, let's use fixed size */
85
 
      chunk_dataspace_length= reclength;
 
80
      if ((reclength - configured_chunk_size) >= VARIABLE_MIN_CHUNK_SIZE<<1)
 
81
      {
 
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 */
 
85
        is_variable_size= 1;
 
86
        chunk_dataspace_length= configured_chunk_size;
 
87
      }
 
88
      else
 
89
      {
 
90
        /* max_chunk_size is near the full reclength, let's use fixed size */
 
91
        is_variable_size= 0;
 
92
        chunk_dataspace_length= reclength;
 
93
      }
 
94
    }
 
95
    else if (create_info->is_dynamic)
 
96
    {
 
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;
 
100
      else
 
101
        chunk_dataspace_length= 256 - VARIABLE_REC_OVERHEAD;
 
102
 
 
103
      is_variable_size= 1;
86
104
    }
87
105
    else
88
106
    {
89
107
      /* if max_chunk_size is not specified, put the whole record in one chunk */
 
108
      is_variable_size= 0;
90
109
      chunk_dataspace_length= reclength;
91
110
    }
92
111
 
 
112
    if (is_variable_size)
 
113
    {
 
114
      /* Check whether we have any variable size records past key data */
 
115
      uint32_t has_variable_fields= 0;
 
116
 
 
117
      fixed_data_length= key_part_size;
 
118
      fixed_column_count= max_key_fieldnr;
 
119
 
 
120
      for (i= max_key_fieldnr; i < columns; i++)
 
121
      {
 
122
        HP_COLUMNDEF* column= columndef + i;
 
123
        if (column->type == DRIZZLE_TYPE_VARCHAR && column->length >= 32)
 
124
        {
 
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;
 
128
            break;
 
129
        }
 
130
 
 
131
        if (has_variable_fields)
 
132
        {
 
133
          break;
 
134
        }
 
135
 
 
136
        if ((column->offset + column->length) <= chunk_dataspace_length)
 
137
        {
 
138
          /* Still no variable-size columns, add one fixed-length */
 
139
          fixed_column_count= i + 1;
 
140
          fixed_data_length= column->offset + column->length;
 
141
        }
 
142
      }
 
143
 
 
144
      if (!has_variable_fields)
 
145
      {
 
146
        /* There is no need to use variable-size records without variable-size columns */
 
147
        /* Reset sizes if it's not variable size anymore */
 
148
        is_variable_size= 0;
 
149
        chunk_dataspace_length= reclength;
 
150
        fixed_data_length= reclength;
 
151
        fixed_column_count= columns;
 
152
      }
 
153
    }
 
154
    else
93
155
    {
94
156
      fixed_data_length= reclength;
95
157
      fixed_column_count= columns;
101
163
    */
102
164
    set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
103
165
 
 
166
    if (is_variable_size)
 
167
    {
 
168
      chunk_length= chunk_dataspace_length + VARIABLE_REC_OVERHEAD;
 
169
    }
 
170
    else
104
171
    {
105
172
      chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
106
173
    }
113
180
    for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
114
181
    {
115
182
      memset(&keyinfo->block, 0, sizeof(keyinfo->block));
116
 
      for (uint32_t j= length= 0; j < keyinfo->keysegs; j++)
 
183
      memset(&keyinfo->rb_tree , 0, sizeof(keyinfo->rb_tree));
 
184
      for (j= length= 0; j < keyinfo->keysegs; j++)
117
185
      {
118
186
        length+= keyinfo->seg[j].length;
119
187
        if (keyinfo->seg[j].null_bit)
121
189
          length++;
122
190
          if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
123
191
            keyinfo->flag|= HA_NULL_PART_KEY;
 
192
          if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
 
193
            keyinfo->rb_tree.size_of_element++;
124
194
        }
125
195
        switch (keyinfo->seg[j].type) {
 
196
        case HA_KEYTYPE_SHORT_INT:
126
197
        case HA_KEYTYPE_LONG_INT:
 
198
        case HA_KEYTYPE_FLOAT:
127
199
        case HA_KEYTYPE_DOUBLE:
 
200
        case HA_KEYTYPE_USHORT_INT:
128
201
        case HA_KEYTYPE_ULONG_INT:
129
202
        case HA_KEYTYPE_LONGLONG:
130
203
        case HA_KEYTYPE_ULONGLONG:
 
204
        case HA_KEYTYPE_INT24:
 
205
        case HA_KEYTYPE_UINT24:
 
206
        case HA_KEYTYPE_INT8:
131
207
          keyinfo->seg[j].flag|= HA_SWAP_KEY;
132
208
          break;
133
209
        case HA_KEYTYPE_VARBINARY1:
159
235
        }
160
236
      }
161
237
      keyinfo->length= length;
 
238
      length+= keyinfo->rb_tree.size_of_element +
 
239
               ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(unsigned char*) : 0);
162
240
      if (length > max_length)
163
241
        max_length= length;
164
242
      key_segs+= keyinfo->keysegs;
 
243
      if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
 
244
      {
 
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;
 
250
        else
 
251
          keyinfo->get_key_length= hp_rb_key_length;
 
252
      }
165
253
    }
166
 
    share= new HP_SHARE;
167
 
 
168
 
    if (keys && !(share->keydef= new HP_KEYDEF[keys]))
169
 
      goto err;
170
 
    if (keys && !(share->keydef->seg= new HA_KEYSEG[key_segs]))
171
 
      goto err;
 
254
    if (!(share= (HP_SHARE*) malloc(sizeof(HP_SHARE)+
 
255
                                    keys*sizeof(HP_KEYDEF)+
 
256
                                    columns*sizeof(HP_COLUMNDEF)+
 
257
                                    key_segs*sizeof(HA_KEYSEG))))
 
258
      goto err;
 
259
    memset(share, 0, sizeof(HP_SHARE)+
 
260
                     keys*sizeof(HP_KEYDEF)+
 
261
                     columns*sizeof(HP_COLUMNDEF)+
 
262
                     key_segs*sizeof(HA_KEYSEG));
172
263
 
173
264
    /*
174
265
       Max_records is used for estimating block sizes and for enforcement.
175
266
       Calculate the very maximum number of rows (if everything was one chunk) and
176
267
       then take either that value or configured max_records (pick smallest one)
177
268
    */
178
 
    max_rows_for_stated_memory= (uint32_t)(create_info->max_table_size /
 
269
    max_rows_for_stated_memory= (ha_rows) (create_info->max_table_size /
179
270
      (keys_memory_size + chunk_length));
180
271
    max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
181
272
                      max_records : max_rows_for_stated_memory);
182
273
 
 
274
    share->column_defs= (HP_COLUMNDEF*) (share + 1);
 
275
    memcpy(share->column_defs, columndef, (size_t) (sizeof(columndef[0]) * columns));
 
276
 
 
277
    share->keydef= (HP_KEYDEF*) (share->column_defs + columns);
183
278
    share->key_stat_version= 1;
184
 
    keyseg= keys ? share->keydef->seg : NULL;
185
 
 
 
279
    keyseg= (HA_KEYSEG*) (share->keydef + keys);
186
280
    init_block(&share->recordspace.block, chunk_length, min_records, max_records);
187
281
    /* Fix keys */
188
282
    memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
192
286
      memcpy(keyseg, keydef[i].seg,
193
287
             (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194
288
      keyseg+= keydef[i].keysegs;
 
289
 
 
290
      if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
 
291
      {
 
292
        /* additional HA_KEYTYPE_END keyseg */
 
293
        keyseg->type=     HA_KEYTYPE_END;
 
294
        keyseg->length=   sizeof(unsigned char*);
 
295
        keyseg->flag=     0;
 
296
        keyseg->null_bit= 0;
 
297
        keyseg++;
 
298
 
 
299
        init_tree(&keyinfo->rb_tree, 0, 0, sizeof(unsigned char*),
 
300
                  (qsort_cmp2)keys_compare, 1, NULL, NULL);
 
301
        keyinfo->delete_key= hp_rb_delete_key;
 
302
        keyinfo->write_key= hp_rb_write_key;
 
303
      }
 
304
      else
195
305
      {
196
306
        init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
197
307
                   max_records);
 
308
        keyinfo->delete_key= hp_delete_key;
 
309
        keyinfo->write_key= hp_write_key;
198
310
        keyinfo->hash_buckets= 0;
199
311
      }
200
312
      if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
218
330
 
219
331
    share->recordspace.chunk_length= chunk_length;
220
332
    share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
 
333
    share->recordspace.is_variable_size= is_variable_size;
221
334
    share->recordspace.total_data_length= 0;
222
335
 
223
 
    {
 
336
    if (is_variable_size) {
 
337
      share->recordspace.offset_link= chunk_dataspace_length;
 
338
      share->recordspace.offset_status= share->recordspace.offset_link + sizeof(unsigned char**);
 
339
    } else {
224
340
      share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
225
341
      share->recordspace.offset_status= chunk_dataspace_length;
226
342
    }
227
343
 
228
344
    /* Must be allocated separately for rename to work */
229
 
    share->name.append(name);
 
345
    if (!(share->name= strdup(name)))
 
346
    {
 
347
      free((unsigned char*) share);
 
348
      goto err;
 
349
    }
 
350
    thr_lock_init(&share->lock);
 
351
    pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST);
230
352
    if (!create_info->internal_table)
231
353
    {
232
 
      heap_share_list.push_front(share);
 
354
      share->open_list.data= (void*) share;
 
355
      heap_share_list= list_add(heap_share_list,&share->open_list);
233
356
    }
234
357
    else
235
358
      share->delete_on_close= 1;
236
359
  }
237
360
  if (!create_info->internal_table)
238
 
    THR_LOCK_heap.unlock();
 
361
    pthread_mutex_unlock(&THR_LOCK_heap);
239
362
 
240
363
  *res= share;
241
364
  return(0);
242
365
 
243
366
err:
244
 
  if (share && share->keydef && share->keydef->seg)
245
 
    delete [] share->keydef->seg;
246
 
  if (share && share->keydef)
247
 
    delete [] share->keydef;
248
 
  if (share)
249
 
    delete share;
250
 
  if (not create_info->internal_table)
251
 
    THR_LOCK_heap.unlock();
 
367
  if (!create_info->internal_table)
 
368
    pthread_mutex_unlock(&THR_LOCK_heap);
252
369
  return(1);
253
370
} /* heap_create */
254
371
 
255
372
 
 
373
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2)
 
374
{
 
375
  uint32_t not_used[2];
 
376
  return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
 
377
                    param->search_flag, not_used);
 
378
}
 
379
 
256
380
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
257
381
                       uint32_t max_records)
258
382
{
259
 
  uint32_t recbuffer,records_in_block;
 
383
  uint32_t i,recbuffer,records_in_block;
260
384
 
261
 
  max_records= max(min_records,max_records);
 
385
  max_records= cmax(min_records,max_records);
262
386
  if (!max_records)
263
387
    max_records= 1000;                  /* As good as quess as anything */
264
388
 
268
392
  if (records_in_block < 10 && max_records)
269
393
    records_in_block= 10;
270
394
  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) *
 
395
      (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
 
396
    records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
273
397
                      HP_MAX_LEVELS) / recbuffer + 1;
274
398
  block->records_in_block= records_in_block;
275
399
  block->recbuffer= recbuffer;
276
400
  block->last_allocated= 0L;
277
401
 
278
 
  for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
279
 
  {
 
402
  for (i= 0; i <= HP_MAX_LEVELS; i++)
280
403
    block->level_info[i].records_under_level=
281
404
      (!i ? 1 : i == 1 ? records_in_block :
282
405
       HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
283
 
  }
284
406
}
285
407
 
286
408
 
298
420
  int result;
299
421
  register HP_SHARE *share;
300
422
 
301
 
  THR_LOCK_heap.lock();
 
423
  pthread_mutex_lock(&THR_LOCK_heap);
302
424
  if ((share= hp_find_named_heap(name)))
303
425
  {
304
426
    heap_try_free(share);
306
428
  }
307
429
  else
308
430
  {
309
 
    result= errno=ENOENT;
 
431
    result= my_errno=ENOENT;
310
432
  }
311
 
  THR_LOCK_heap.unlock();
 
433
  pthread_mutex_unlock(&THR_LOCK_heap);
312
434
  return(result);
313
435
}
314
436
 
315
437
 
 
438
void heap_drop_table(HP_INFO *info)
 
439
{
 
440
  pthread_mutex_lock(&THR_LOCK_heap);
 
441
  heap_try_free(info->s);
 
442
  pthread_mutex_unlock(&THR_LOCK_heap);
 
443
  return;
 
444
}
 
445
 
 
446
 
316
447
void hp_free(HP_SHARE *share)
317
448
{
318
 
  heap_share_list.remove(share);        /* If not internal table */
 
449
  if (share->open_list.data)                    /* If not internal table */
 
450
    heap_share_list= list_delete(heap_share_list, &share->open_list);
319
451
  hp_clear(share);                      /* Remove blocks from memory */
320
 
  if (share->keydef)
321
 
    delete [] share->keydef->seg;
322
 
  delete [] share->keydef;
323
 
  delete share;
 
452
  thr_lock_delete(&share->lock);
 
453
  pthread_mutex_destroy(&share->intern_lock);
 
454
  free((unsigned char*) share->name);
 
455
  free((unsigned char*) share);
 
456
  return;
324
457
}