~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/heap/hp_create.c

  • Committer: Monty Taylor
  • Date: 2009-03-18 18:45:23 UTC
  • mto: (950.1.1 mordred)
  • mto: This revision was merged to the branch mainline in revision 943.
  • Revision ID: mordred@inaugust.com-20090318184523-mfbjyj5wkipv4n3b
Moved big tests to big suite. Added make target "make test-big" to allow for easy running of the big tests.

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
 
static const int FIXED_REC_OVERHEAD = (sizeof(unsigned char));
31
 
static const int VARIABLE_REC_OVERHEAD = (sizeof(unsigned char**) + ALIGN_SIZE(sizeof(unsigned char)));
 
27
#define FIXED_REC_OVERHEAD (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
 
static const int VARIABLE_MIN_CHUNK_SIZE =
35
 
        ((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1));
 
31
#define VARIABLE_MIN_CHUNK_SIZE \
 
32
        ((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1))
36
33
 
37
34
 
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
    share= NULL;
 
255
    if (!(share= (HP_SHARE*) malloc(sizeof(HP_SHARE))))
 
256
      goto err;
 
257
 
 
258
    memset(share, 0, sizeof(HP_SHARE));
 
259
 
 
260
    if (keys && !(share->keydef= (HP_KEYDEF*) malloc(keys*sizeof(HP_KEYDEF))))
 
261
      goto err;
 
262
 
 
263
    memset(share->keydef, 0, keys*sizeof(HP_KEYDEF));
 
264
 
 
265
    if (keys && !(share->keydef->seg= (HA_KEYSEG*) malloc(key_segs*sizeof(HA_KEYSEG))))
 
266
      goto err;
 
267
    if (!(share->column_defs= (HP_COLUMNDEF*)
 
268
          malloc(columns*sizeof(HP_COLUMNDEF))))
 
269
      goto err;
 
270
 
 
271
    memset(share->column_defs, 0, columns*sizeof(HP_COLUMNDEF));
172
272
 
173
273
    /*
174
274
       Max_records is used for estimating block sizes and for enforcement.
175
275
       Calculate the very maximum number of rows (if everything was one chunk) and
176
276
       then take either that value or configured max_records (pick smallest one)
177
277
    */
178
 
    max_rows_for_stated_memory= (uint32_t)(create_info->max_table_size /
 
278
    max_rows_for_stated_memory= (ha_rows) (create_info->max_table_size /
179
279
      (keys_memory_size + chunk_length));
180
280
    max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
181
281
                      max_records : max_rows_for_stated_memory);
182
282
 
 
283
    memcpy(share->column_defs, columndef, (size_t) (sizeof(columndef[0]) * columns));
 
284
 
183
285
    share->key_stat_version= 1;
184
286
    keyseg= keys ? share->keydef->seg : NULL;
185
287
 
192
294
      memcpy(keyseg, keydef[i].seg,
193
295
             (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194
296
      keyseg+= keydef[i].keysegs;
 
297
 
 
298
      if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
 
299
      {
 
300
        /* additional HA_KEYTYPE_END keyseg */
 
301
        keyseg->type=     HA_KEYTYPE_END;
 
302
        keyseg->length=   sizeof(unsigned char*);
 
303
        keyseg->flag=     0;
 
304
        keyseg->null_bit= 0;
 
305
        keyseg++;
 
306
 
 
307
        init_tree(&keyinfo->rb_tree, 0, 0, sizeof(unsigned char*),
 
308
                  (qsort_cmp2)keys_compare, 1, NULL, NULL);
 
309
        keyinfo->delete_key= hp_rb_delete_key;
 
310
        keyinfo->write_key= hp_rb_write_key;
 
311
      }
 
312
      else
195
313
      {
196
314
        init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
197
315
                   max_records);
 
316
        keyinfo->delete_key= hp_delete_key;
 
317
        keyinfo->write_key= hp_write_key;
198
318
        keyinfo->hash_buckets= 0;
199
319
      }
200
320
      if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
218
338
 
219
339
    share->recordspace.chunk_length= chunk_length;
220
340
    share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
 
341
    share->recordspace.is_variable_size= is_variable_size;
221
342
    share->recordspace.total_data_length= 0;
222
343
 
223
 
    {
 
344
    if (is_variable_size) {
 
345
      share->recordspace.offset_link= chunk_dataspace_length;
 
346
      share->recordspace.offset_status= share->recordspace.offset_link + sizeof(unsigned char**);
 
347
    } else {
224
348
      share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
225
349
      share->recordspace.offset_status= chunk_dataspace_length;
226
350
    }
227
351
 
228
352
    /* Must be allocated separately for rename to work */
229
 
    share->name.append(name);
 
353
    if (!(share->name= strdup(name)))
 
354
    {
 
355
      goto err;
 
356
    }
 
357
    thr_lock_init(&share->lock);
 
358
    pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST);
230
359
    if (!create_info->internal_table)
231
360
    {
232
 
      heap_share_list.push_front(share);
 
361
      share->open_list.data= (void*) share;
 
362
      heap_share_list= list_add(heap_share_list,&share->open_list);
233
363
    }
234
364
    else
235
365
      share->delete_on_close= 1;
236
366
  }
237
367
  if (!create_info->internal_table)
238
 
    THR_LOCK_heap.unlock();
 
368
    pthread_mutex_unlock(&THR_LOCK_heap);
239
369
 
240
370
  *res= share;
241
371
  return(0);
242
372
 
243
373
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();
 
374
  if(share && share->keydef && share->keydef->seg)
 
375
    free(share->keydef->seg);
 
376
  if(share && share->keydef)
 
377
    free(share->keydef);
 
378
  if(share && share->column_defs)
 
379
    free(share->column_defs);
 
380
  if(share)
 
381
    free(share);
 
382
  if (!create_info->internal_table)
 
383
    pthread_mutex_unlock(&THR_LOCK_heap);
252
384
  return(1);
253
385
} /* heap_create */
254
386
 
255
387
 
 
388
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2)
 
389
{
 
390
  uint32_t not_used[2];
 
391
  return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
 
392
                    param->search_flag, not_used);
 
393
}
 
394
 
256
395
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
257
396
                       uint32_t max_records)
258
397
{
259
 
  uint32_t recbuffer,records_in_block;
 
398
  uint32_t i,recbuffer,records_in_block;
260
399
 
261
 
  max_records= max(min_records,max_records);
 
400
  max_records= cmax(min_records,max_records);
262
401
  if (!max_records)
263
402
    max_records= 1000;                  /* As good as quess as anything */
264
403
 
268
407
  if (records_in_block < 10 && max_records)
269
408
    records_in_block= 10;
270
409
  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) *
 
410
      (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
 
411
    records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
273
412
                      HP_MAX_LEVELS) / recbuffer + 1;
274
413
  block->records_in_block= records_in_block;
275
414
  block->recbuffer= recbuffer;
276
415
  block->last_allocated= 0L;
277
416
 
278
 
  for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
279
 
  {
 
417
  for (i= 0; i <= HP_MAX_LEVELS; i++)
280
418
    block->level_info[i].records_under_level=
281
419
      (!i ? 1 : i == 1 ? records_in_block :
282
420
       HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
283
 
  }
284
421
}
285
422
 
286
423
 
298
435
  int result;
299
436
  register HP_SHARE *share;
300
437
 
301
 
  THR_LOCK_heap.lock();
 
438
  pthread_mutex_lock(&THR_LOCK_heap);
302
439
  if ((share= hp_find_named_heap(name)))
303
440
  {
304
441
    heap_try_free(share);
306
443
  }
307
444
  else
308
445
  {
309
 
    result= errno=ENOENT;
 
446
    result= my_errno=ENOENT;
310
447
  }
311
 
  THR_LOCK_heap.unlock();
 
448
  pthread_mutex_unlock(&THR_LOCK_heap);
312
449
  return(result);
313
450
}
314
451
 
315
452
 
 
453
void heap_drop_table(HP_INFO *info)
 
454
{
 
455
  pthread_mutex_lock(&THR_LOCK_heap);
 
456
  heap_try_free(info->s);
 
457
  pthread_mutex_unlock(&THR_LOCK_heap);
 
458
  return;
 
459
}
 
460
 
 
461
 
316
462
void hp_free(HP_SHARE *share)
317
463
{
318
 
  heap_share_list.remove(share);        /* If not internal table */
 
464
  if (share->open_list.data)                    /* If not internal table */
 
465
    heap_share_list= list_delete(heap_share_list, &share->open_list);
319
466
  hp_clear(share);                      /* Remove blocks from memory */
320
 
  if (share->keydef)
321
 
    delete [] share->keydef->seg;
322
 
  delete [] share->keydef;
323
 
  delete share;
 
467
  thr_lock_delete(&share->lock);
 
468
  pthread_mutex_destroy(&share->intern_lock);
 
469
  if(share->keys)
 
470
    free(share->keydef->seg);
 
471
  if(share->keys)
 
472
    free(share->keydef);
 
473
  free(share->column_defs);
 
474
  free((unsigned char*) share->name);
 
475
  free((unsigned char*) share);
 
476
  return;
324
477
}