~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to plugin/heap/hp_create.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
#include "heap_priv.h"
 
17
 
 
18
#include <drizzled/common.h>
 
19
#include <drizzled/error.h>
 
20
 
 
21
#include <string.h>
 
22
#include <algorithm>
 
23
 
 
24
using namespace std;
 
25
using namespace drizzled;
 
26
 
 
27
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2);
 
28
static void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
 
29
                        uint32_t max_records);
 
30
 
 
31
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
 
32
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + ALIGN_SIZE(sizeof(unsigned char)))
 
33
 
 
34
/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
 
35
#define VARIABLE_MIN_CHUNK_SIZE \
 
36
        ((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1))
 
37
 
 
38
 
 
39
/* Create a heap table */
 
40
 
 
41
int heap_create(const char *name, uint32_t keys, HP_KEYDEF *keydef,
 
42
    uint32_t columns, HP_COLUMNDEF *columndef,
 
43
    uint32_t max_key_fieldnr, uint32_t key_part_size,
 
44
    uint32_t reclength, uint32_t keys_memory_size,
 
45
    uint32_t max_records, uint32_t min_records,
 
46
    HP_CREATE_INFO *create_info, HP_SHARE **res)
 
47
{
 
48
  uint32_t i, j, key_segs, max_length, length;
 
49
  uint32_t max_rows_for_stated_memory;
 
50
  HP_SHARE *share= 0;
 
51
  HA_KEYSEG *keyseg;
 
52
 
 
53
  if (!create_info->internal_table)
 
54
  {
 
55
    pthread_mutex_lock(&THR_LOCK_heap);
 
56
    if ((share= hp_find_named_heap(name)) && share->open_count == 0)
 
57
    {
 
58
      hp_free(share);
 
59
      share= 0;
 
60
    }
 
61
  }
 
62
 
 
63
  if (!share)
 
64
  {
 
65
    size_t chunk_dataspace_length;
 
66
    uint32_t chunk_length, is_variable_size;
 
67
    uint32_t fixed_data_length, fixed_column_count;
 
68
    HP_KEYDEF *keyinfo;
 
69
 
 
70
    if (create_info->max_chunk_size)
 
71
    {
 
72
      uint32_t configured_chunk_size= create_info->max_chunk_size;
 
73
 
 
74
      /* User requested variable-size records, let's see if they're possible */
 
75
 
 
76
      if (configured_chunk_size < key_part_size)
 
77
      {
 
78
        /* Eventual chunk_size cannot be smaller than key data,
 
79
           which allows all keys to fit into the first chunk */
 
80
        my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
 
81
        pthread_mutex_unlock(&THR_LOCK_heap);
 
82
        return(ER_CANT_USE_OPTION_HERE);
 
83
      }
 
84
 
 
85
      if ((reclength - configured_chunk_size) >= VARIABLE_MIN_CHUNK_SIZE<<1)
 
86
      {
 
87
        /* Allow variable size only if we're saving at least two smallest chunks */
 
88
        /* There has to be at least one field after indexed fields */
 
89
        /* Note that NULL bits are already included in key_part_size */
 
90
        is_variable_size= 1;
 
91
        chunk_dataspace_length= configured_chunk_size;
 
92
      }
 
93
      else
 
94
      {
 
95
        /* max_chunk_size is near the full reclength, let's use fixed size */
 
96
        is_variable_size= 0;
 
97
        chunk_dataspace_length= reclength;
 
98
      }
 
99
    }
 
100
    else if (create_info->is_dynamic)
 
101
    {
 
102
      /* User asked for dynamic records - use 256 as the chunk size */
 
103
      if ((key_part_size + VARIABLE_REC_OVERHEAD) > 256)
 
104
        chunk_dataspace_length= key_part_size;
 
105
      else
 
106
        chunk_dataspace_length= 256 - VARIABLE_REC_OVERHEAD;
 
107
 
 
108
      is_variable_size= 1;
 
109
    }
 
110
    else
 
111
    {
 
112
      /* if max_chunk_size is not specified, put the whole record in one chunk */
 
113
      is_variable_size= 0;
 
114
      chunk_dataspace_length= reclength;
 
115
    }
 
116
 
 
117
    if (is_variable_size)
 
118
    {
 
119
      /* Check whether we have any variable size records past key data */
 
120
      uint32_t has_variable_fields= 0;
 
121
 
 
122
      fixed_data_length= key_part_size;
 
123
      fixed_column_count= max_key_fieldnr;
 
124
 
 
125
      for (i= max_key_fieldnr; i < columns; i++)
 
126
      {
 
127
        HP_COLUMNDEF* column= columndef + i;
 
128
        if (column->type == DRIZZLE_TYPE_VARCHAR && column->length >= 32)
 
129
        {
 
130
            /* The field has to be >= 5.0.3 true VARCHAR and have substantial length */
 
131
            /* TODO: do we want to calculate minimum length? */
 
132
            has_variable_fields= 1;
 
133
            break;
 
134
        }
 
135
 
 
136
        if (has_variable_fields)
 
137
        {
 
138
          break;
 
139
        }
 
140
 
 
141
        if ((column->offset + column->length) <= chunk_dataspace_length)
 
142
        {
 
143
          /* Still no variable-size columns, add one fixed-length */
 
144
          fixed_column_count= i + 1;
 
145
          fixed_data_length= column->offset + column->length;
 
146
        }
 
147
      }
 
148
 
 
149
      if (!has_variable_fields)
 
150
      {
 
151
        /* There is no need to use variable-size records without variable-size columns */
 
152
        /* Reset sizes if it's not variable size anymore */
 
153
        is_variable_size= 0;
 
154
        chunk_dataspace_length= reclength;
 
155
        fixed_data_length= reclength;
 
156
        fixed_column_count= columns;
 
157
      }
 
158
    }
 
159
    else
 
160
    {
 
161
      fixed_data_length= reclength;
 
162
      fixed_column_count= columns;
 
163
    }
 
164
 
 
165
    /*
 
166
      We store unsigned char* del_link inside the data area of deleted records,
 
167
      so the data length should be at least sizeof(unsigned char*)
 
168
    */
 
169
    set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
 
170
 
 
171
    if (is_variable_size)
 
172
    {
 
173
      chunk_length= chunk_dataspace_length + VARIABLE_REC_OVERHEAD;
 
174
    }
 
175
    else
 
176
    {
 
177
      chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
 
178
    }
 
179
 
 
180
    /* Align chunk length to the next pointer */
 
181
    chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
 
182
 
 
183
 
 
184
 
 
185
    for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
 
186
    {
 
187
      memset(&keyinfo->block, 0, sizeof(keyinfo->block));
 
188
      memset(&keyinfo->rb_tree , 0, sizeof(keyinfo->rb_tree));
 
189
      for (j= length= 0; j < keyinfo->keysegs; j++)
 
190
      {
 
191
        length+= keyinfo->seg[j].length;
 
192
        if (keyinfo->seg[j].null_bit)
 
193
        {
 
194
          length++;
 
195
          if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
 
196
            keyinfo->flag|= HA_NULL_PART_KEY;
 
197
          if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
 
198
            keyinfo->rb_tree.size_of_element++;
 
199
        }
 
200
        switch (keyinfo->seg[j].type) {
 
201
        case HA_KEYTYPE_LONG_INT:
 
202
        case HA_KEYTYPE_DOUBLE:
 
203
        case HA_KEYTYPE_ULONG_INT:
 
204
        case HA_KEYTYPE_LONGLONG:
 
205
        case HA_KEYTYPE_ULONGLONG:
 
206
        case HA_KEYTYPE_UINT24:
 
207
          keyinfo->seg[j].flag|= HA_SWAP_KEY;
 
208
          break;
 
209
        case HA_KEYTYPE_VARBINARY1:
 
210
          /* Case-insensitiveness is handled in coll->hash_sort */
 
211
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
 
212
          /* fall_through */
 
213
        case HA_KEYTYPE_VARTEXT1:
 
214
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
 
215
          length+= 2;
 
216
          /* Save number of bytes used to store length */
 
217
          keyinfo->seg[j].bit_start= 1;
 
218
          break;
 
219
        case HA_KEYTYPE_VARBINARY2:
 
220
          /* Case-insensitiveness is handled in coll->hash_sort */
 
221
          /* fall_through */
 
222
        case HA_KEYTYPE_VARTEXT2:
 
223
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
 
224
          length+= 2;
 
225
          /* Save number of bytes used to store length */
 
226
          keyinfo->seg[j].bit_start= 2;
 
227
          /*
 
228
            Make future comparison simpler by only having to check for
 
229
            one type
 
230
          */
 
231
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
 
232
          break;
 
233
        default:
 
234
          break;
 
235
        }
 
236
      }
 
237
      keyinfo->length= length;
 
238
      length+= keyinfo->rb_tree.size_of_element +
 
239
               ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(unsigned char*) : 0);
 
240
      if (length > max_length)
 
241
        max_length= length;
 
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
      }
 
253
    }
 
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));
 
272
 
 
273
    /*
 
274
       Max_records is used for estimating block sizes and for enforcement.
 
275
       Calculate the very maximum number of rows (if everything was one chunk) and
 
276
       then take either that value or configured max_records (pick smallest one)
 
277
    */
 
278
    max_rows_for_stated_memory= (uint32_t)(create_info->max_table_size /
 
279
      (keys_memory_size + chunk_length));
 
280
    max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
 
281
                      max_records : max_rows_for_stated_memory);
 
282
 
 
283
    memcpy(share->column_defs, columndef, (size_t) (sizeof(columndef[0]) * columns));
 
284
 
 
285
    share->key_stat_version= 1;
 
286
    keyseg= keys ? share->keydef->seg : NULL;
 
287
 
 
288
    init_block(&share->recordspace.block, chunk_length, min_records, max_records);
 
289
    /* Fix keys */
 
290
    memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
 
291
    for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
 
292
    {
 
293
      keyinfo->seg= keyseg;
 
294
      memcpy(keyseg, keydef[i].seg,
 
295
             (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
 
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, true, NULL, NULL);
 
309
        keyinfo->delete_key= hp_rb_delete_key;
 
310
        keyinfo->write_key= hp_rb_write_key;
 
311
      }
 
312
      else
 
313
      {
 
314
        init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
 
315
                   max_records);
 
316
        keyinfo->delete_key= hp_delete_key;
 
317
        keyinfo->write_key= hp_write_key;
 
318
        keyinfo->hash_buckets= 0;
 
319
      }
 
320
      if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
 
321
        share->auto_key= i + 1;
 
322
    }
 
323
    share->min_records= min_records;
 
324
    share->max_records= max_records;
 
325
    share->max_table_size= create_info->max_table_size;
 
326
    share->index_length= 0;
 
327
    share->blength= 1;
 
328
    share->keys= keys;
 
329
    share->max_key_length= max_length;
 
330
    share->column_count= columns;
 
331
    share->changed= 0;
 
332
    share->auto_key= create_info->auto_key;
 
333
    share->auto_key_type= create_info->auto_key_type;
 
334
    share->auto_increment= create_info->auto_increment;
 
335
 
 
336
    share->fixed_data_length= fixed_data_length;
 
337
    share->fixed_column_count= fixed_column_count;
 
338
 
 
339
    share->recordspace.chunk_length= chunk_length;
 
340
    share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
 
341
    share->recordspace.is_variable_size= is_variable_size;
 
342
    share->recordspace.total_data_length= 0;
 
343
 
 
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 {
 
348
      share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
 
349
      share->recordspace.offset_status= chunk_dataspace_length;
 
350
    }
 
351
 
 
352
    /* Must be allocated separately for rename to work */
 
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);
 
359
    if (!create_info->internal_table)
 
360
    {
 
361
      heap_share_list.push_front(share);
 
362
    }
 
363
    else
 
364
      share->delete_on_close= 1;
 
365
  }
 
366
  if (!create_info->internal_table)
 
367
    pthread_mutex_unlock(&THR_LOCK_heap);
 
368
 
 
369
  *res= share;
 
370
  return(0);
 
371
 
 
372
err:
 
373
  if(share && share->keydef && share->keydef->seg)
 
374
    free(share->keydef->seg);
 
375
  if(share && share->keydef)
 
376
    free(share->keydef);
 
377
  if(share && share->column_defs)
 
378
    free(share->column_defs);
 
379
  if(share)
 
380
    free(share);
 
381
  if (!create_info->internal_table)
 
382
    pthread_mutex_unlock(&THR_LOCK_heap);
 
383
  return(1);
 
384
} /* heap_create */
 
385
 
 
386
 
 
387
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2)
 
388
{
 
389
  uint32_t not_used[2];
 
390
  return ha_key_cmp(param->keyseg, key1, key2, param->key_length,
 
391
                    param->search_flag, not_used);
 
392
}
 
393
 
 
394
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
 
395
                       uint32_t max_records)
 
396
{
 
397
  uint32_t i,recbuffer,records_in_block;
 
398
 
 
399
  max_records= max(min_records,max_records);
 
400
  if (!max_records)
 
401
    max_records= 1000;                  /* As good as quess as anything */
 
402
 
 
403
  /* we want to start each chunk at 8 bytes boundary, round recbuffer to the next 8 */
 
404
  recbuffer= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
 
405
  records_in_block= max_records / 10;
 
406
  if (records_in_block < 10 && max_records)
 
407
    records_in_block= 10;
 
408
  if (!records_in_block || records_in_block*recbuffer >
 
409
      (internal::my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
 
410
    records_in_block= (internal::my_default_record_cache_size - sizeof(HP_PTRS) *
 
411
                      HP_MAX_LEVELS) / recbuffer + 1;
 
412
  block->records_in_block= records_in_block;
 
413
  block->recbuffer= recbuffer;
 
414
  block->last_allocated= 0L;
 
415
 
 
416
  for (i= 0; i <= HP_MAX_LEVELS; i++)
 
417
    block->level_info[i].records_under_level=
 
418
      (!i ? 1 : i == 1 ? records_in_block :
 
419
       HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
 
420
}
 
421
 
 
422
 
 
423
static inline void heap_try_free(HP_SHARE *share)
 
424
{
 
425
  if (share->open_count == 0)
 
426
    hp_free(share);
 
427
  else
 
428
    share->delete_on_close= 1;
 
429
}
 
430
 
 
431
 
 
432
int heap_delete_table(const char *name)
 
433
{
 
434
  int result;
 
435
  register HP_SHARE *share;
 
436
 
 
437
  pthread_mutex_lock(&THR_LOCK_heap);
 
438
  if ((share= hp_find_named_heap(name)))
 
439
  {
 
440
    heap_try_free(share);
 
441
    result= 0;
 
442
  }
 
443
  else
 
444
  {
 
445
    result= errno=ENOENT;
 
446
  }
 
447
  pthread_mutex_unlock(&THR_LOCK_heap);
 
448
  return(result);
 
449
}
 
450
 
 
451
 
 
452
void heap_drop_table(HP_INFO *info)
 
453
{
 
454
  pthread_mutex_lock(&THR_LOCK_heap);
 
455
  heap_try_free(info->s);
 
456
  pthread_mutex_unlock(&THR_LOCK_heap);
 
457
  return;
 
458
}
 
459
 
 
460
 
 
461
void hp_free(HP_SHARE *share)
 
462
{
 
463
  heap_share_list.remove(share);        /* If not internal table */
 
464
  hp_clear(share);                      /* Remove blocks from memory */
 
465
  thr_lock_delete(&share->lock);
 
466
  pthread_mutex_destroy(&share->intern_lock);
 
467
  if (share->keydef && share->keydef->seg)
 
468
    free(share->keydef->seg);
 
469
  if (share->keydef)
 
470
    free(share->keydef);
 
471
  free(share->column_defs);
 
472
  free((unsigned char*) share->name);
 
473
  free((unsigned char*) share);
 
474
  return;
 
475
}