~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/memory/hp_create.cc

  • Committer: Olaf van der Spek
  • Date: 2011-07-05 11:15:32 UTC
  • mto: This revision was merged to the branch mainline in revision 2367.
  • Revision ID: olafvdspek@gmail.com-20110705111532-zod5hduzwcqe01ea
Use boost::to_lower

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