~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/heap/hp_create.c

  • Committer: brian
  • Date: 2008-07-03 12:39:14 UTC
  • Revision ID: brian@localhost.localdomain-20080703123914-lry82qf74f6cbyzs
Disabling myisam tools until incomming link patch from Monty

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
#include "heapdef.h"
17
 
#include "libdrizzle/drizzle_com.h"
18
 
#include "drizzled/error.h"
19
 
 
20
 
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2);
21
 
static void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
22
 
                        uint32_t max_records);
23
 
 
24
 
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
25
 
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + sizeof(unsigned char))
26
 
 
27
 
/* 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))
30
 
 
 
17
 
 
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,
 
20
                       ulong max_records);
31
21
 
32
22
/* Create a heap table */
33
23
 
34
 
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)
 
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)
40
27
{
41
 
  uint32_t i, j, key_segs, max_length, length;
42
 
  uint32_t max_rows_for_stated_memory;
 
28
  uint i, j, key_segs, max_length, length;
43
29
  HP_SHARE *share= 0;
44
30
  HA_KEYSEG *keyseg;
 
31
  DBUG_ENTER("heap_create");
45
32
 
46
33
  if (!create_info->internal_table)
47
34
  {
55
42
 
56
43
  if (!share)
57
44
  {
58
 
    uint32_t chunk_dataspace_length, chunk_length, is_variable_size;
59
 
    uint32_t fixed_data_length, fixed_column_count;
60
45
    HP_KEYDEF *keyinfo;
61
 
 
62
 
    if (create_info->max_chunk_size)
63
 
    {
64
 
      uint32_t configured_chunk_size= create_info->max_chunk_size;
65
 
 
66
 
      /* User requested variable-size records, let's see if they're possible */
67
 
 
68
 
      if (configured_chunk_size < key_part_size)
69
 
      {
70
 
        /* Eventual chunk_size cannot be smaller than key data,
71
 
           which allows all keys to fit into the first chunk */
72
 
        my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
73
 
        pthread_mutex_unlock(&THR_LOCK_heap);
74
 
        return(ER_CANT_USE_OPTION_HERE);
75
 
      }
76
 
 
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;
101
 
    }
102
 
    else
103
 
    {
104
 
      /* if max_chunk_size is not specified, put the whole record in one chunk */
105
 
      is_variable_size= 0;
106
 
      chunk_dataspace_length= reclength;
107
 
    }
108
 
 
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
 
    {
153
 
      fixed_data_length= reclength;
154
 
      fixed_column_count= columns;
155
 
    }
156
 
 
 
46
    DBUG_PRINT("info",("Initializing new table"));
 
47
    
157
48
    /*
158
 
      We store unsigned char* del_link inside the data area of deleted records,
159
 
      so the data length should be at least sizeof(unsigned char*)
 
49
      We have to store sometimes uchar* del_link in records,
 
50
      so the record length should be at least sizeof(uchar*)
160
51
    */
161
 
    set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
162
 
 
163
 
    if (is_variable_size)
164
 
    {
165
 
      chunk_length= chunk_dataspace_length + VARIABLE_REC_OVERHEAD;
166
 
    }
167
 
    else
168
 
    {
169
 
      chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
170
 
    }
171
 
 
172
 
    /* Align chunk length to the next pointer */
173
 
    chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
174
 
 
175
 
 
 
52
    set_if_bigger(reclength, sizeof (uchar*));
176
53
    
177
54
    for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
178
55
    {
179
 
      memset(&keyinfo->block, 0, sizeof(keyinfo->block));
180
 
      memset(&keyinfo->rb_tree , 0, sizeof(keyinfo->rb_tree));
 
56
      bzero((char*) &keyinfo->block,sizeof(keyinfo->block));
 
57
      bzero((char*) &keyinfo->rb_tree ,sizeof(keyinfo->rb_tree));
181
58
      for (j= length= 0; j < keyinfo->keysegs; j++)
182
59
      {
183
60
        length+= keyinfo->seg[j].length;
208
85
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
209
86
          /* fall_through */
210
87
        case HA_KEYTYPE_VARTEXT1:
 
88
          if (!my_binary_compare(keyinfo->seg[j].charset))
 
89
            keyinfo->flag|= HA_END_SPACE_KEY;
211
90
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
212
91
          length+= 2;
213
92
          /* Save number of bytes used to store length */
217
96
          /* Case-insensitiveness is handled in coll->hash_sort */
218
97
          /* fall_through */
219
98
        case HA_KEYTYPE_VARTEXT2:
 
99
          if (!my_binary_compare(keyinfo->seg[j].charset))
 
100
            keyinfo->flag|= HA_END_SPACE_KEY;
220
101
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
221
102
          length+= 2;
222
103
          /* Save number of bytes used to store length */
230
111
        default:
231
112
          break;
232
113
        }
 
114
        if (keyinfo->seg[j].flag & HA_END_SPACE_ARE_EQUAL)
 
115
          keyinfo->flag|= HA_END_SPACE_KEY;
233
116
      }
234
117
      keyinfo->length= length;
235
118
      length+= keyinfo->rb_tree.size_of_element + 
236
 
               ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(unsigned char*) : 0);
 
119
               ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(uchar*) : 0);
237
120
      if (length > max_length)
238
121
        max_length= length;
239
122
      key_segs+= keyinfo->keysegs;
250
133
    }
251
134
    if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
252
135
                                       keys*sizeof(HP_KEYDEF)+
253
 
                                       columns*sizeof(HP_COLUMNDEF)+
254
136
                                       key_segs*sizeof(HA_KEYSEG),
255
137
                                       MYF(MY_ZEROFILL))))
256
138
      goto err;
257
 
 
258
 
    /*
259
 
       Max_records is used for estimating block sizes and for enforcement.
260
 
       Calculate the very maximum number of rows (if everything was one chunk) and
261
 
       then take either that value or configured max_records (pick smallest one)
262
 
    */
263
 
    max_rows_for_stated_memory= (ha_rows) (create_info->max_table_size /
264
 
      (keys_memory_size + chunk_length));
265
 
    max_records = ((max_records && max_records < max_rows_for_stated_memory) ? 
266
 
                      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
 
 
271
 
    share->keydef= (HP_KEYDEF*) (share->column_defs + columns);    
 
139
    share->keydef= (HP_KEYDEF*) (share + 1);
272
140
    share->key_stat_version= 1;
273
141
    keyseg= (HA_KEYSEG*) (share->keydef + keys);
274
 
    init_block(&share->recordspace.block, chunk_length, min_records, max_records);
275
 
    /* Fix keys */
 
142
    init_block(&share->block, reclength + 1, min_records, max_records);
 
143
        /* Fix keys */
276
144
    memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
277
145
    for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
278
146
    {
285
153
      {
286
154
        /* additional HA_KEYTYPE_END keyseg */
287
155
        keyseg->type=     HA_KEYTYPE_END;
288
 
        keyseg->length=   sizeof(unsigned char*);
 
156
        keyseg->length=   sizeof(uchar*);
289
157
        keyseg->flag=     0;
290
158
        keyseg->null_bit= 0;
291
159
        keyseg++;
292
160
 
293
 
        init_tree(&keyinfo->rb_tree, 0, 0, sizeof(unsigned char*),
 
161
        init_tree(&keyinfo->rb_tree, 0, 0, sizeof(uchar*),
294
162
                  (qsort_cmp2)keys_compare, 1, NULL, NULL);
295
163
        keyinfo->delete_key= hp_rb_delete_key;
296
164
        keyinfo->write_key= hp_rb_write_key;
309
177
    share->min_records= min_records;
310
178
    share->max_records= max_records;
311
179
    share->max_table_size= create_info->max_table_size;
312
 
    share->index_length= 0;
 
180
    share->data_length= share->index_length= 0;
 
181
    share->reclength= reclength;
313
182
    share->blength= 1;
314
183
    share->keys= keys;
315
184
    share->max_key_length= max_length;
316
 
    share->column_count= columns;
317
185
    share->changed= 0;
318
186
    share->auto_key= create_info->auto_key;
319
187
    share->auto_key_type= create_info->auto_key_type;
320
188
    share->auto_increment= create_info->auto_increment;
321
 
 
322
 
    share->fixed_data_length= fixed_data_length;
323
 
    share->fixed_column_count= fixed_column_count;
324
 
 
325
 
    share->recordspace.chunk_length= chunk_length;
326
 
    share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
327
 
    share->recordspace.is_variable_size= is_variable_size;
328
 
    share->recordspace.total_data_length= 0;
329
 
 
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 {
334
 
      share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
335
 
      share->recordspace.offset_status= chunk_dataspace_length;
336
 
    }
337
 
 
338
189
    /* Must be allocated separately for rename to work */
339
190
    if (!(share->name= my_strdup(name,MYF(0))))
340
191
    {
341
 
      free((unsigned char*) share);
 
192
      my_free((uchar*) share,MYF(0));
342
193
      goto err;
343
194
    }
344
195
    thr_lock_init(&share->lock);
345
 
    pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST);
 
196
    VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
346
197
    if (!create_info->internal_table)
347
198
    {
348
199
      share->open_list.data= (void*) share;
355
206
    pthread_mutex_unlock(&THR_LOCK_heap);
356
207
 
357
208
  *res= share;
358
 
  return(0);
 
209
  DBUG_RETURN(0);
359
210
 
360
211
err:
361
212
  if (!create_info->internal_table)
362
213
    pthread_mutex_unlock(&THR_LOCK_heap);
363
 
  return(1);
 
214
  DBUG_RETURN(1);
364
215
} /* heap_create */
365
216
 
366
217
 
367
 
static int keys_compare(heap_rb_param *param, unsigned char *key1, unsigned char *key2)
 
218
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
368
219
{
369
 
  uint32_t not_used[2];
 
220
  uint not_used[2];
370
221
  return ha_key_cmp(param->keyseg, key1, key2, param->key_length, 
371
222
                    param->search_flag, not_used);
372
223
}
373
224
 
374
 
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
375
 
                       uint32_t max_records)
 
225
static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
 
226
                       ulong max_records)
376
227
{
377
 
  uint32_t i,recbuffer,records_in_block;
 
228
  uint i,recbuffer,records_in_block;
378
229
 
379
 
  max_records= cmax(min_records,max_records);
 
230
  max_records= max(min_records,max_records);
380
231
  if (!max_records)
381
232
    max_records= 1000;                  /* As good as quess as anything */
382
 
  
383
 
  /* 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);  
 
233
  recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
385
234
  records_in_block= max_records / 10;
386
235
  if (records_in_block < 10 && max_records)
387
236
    records_in_block= 10;
413
262
{
414
263
  int result;
415
264
  register HP_SHARE *share;
 
265
  DBUG_ENTER("heap_delete_table");
416
266
 
417
267
  pthread_mutex_lock(&THR_LOCK_heap);
418
268
  if ((share= hp_find_named_heap(name)))
425
275
    result= my_errno=ENOENT;
426
276
  }
427
277
  pthread_mutex_unlock(&THR_LOCK_heap);
428
 
  return(result);
 
278
  DBUG_RETURN(result);
429
279
}
430
280
 
431
281
 
432
282
void heap_drop_table(HP_INFO *info)
433
283
{
 
284
  DBUG_ENTER("heap_drop_table");
434
285
  pthread_mutex_lock(&THR_LOCK_heap);
435
286
  heap_try_free(info->s);
436
287
  pthread_mutex_unlock(&THR_LOCK_heap);
437
 
  return;
 
288
  DBUG_VOID_RETURN;
438
289
}
439
290
 
440
291
 
444
295
    heap_share_list= list_delete(heap_share_list, &share->open_list);
445
296
  hp_clear(share);                      /* Remove blocks from memory */
446
297
  thr_lock_delete(&share->lock);
447
 
  pthread_mutex_destroy(&share->intern_lock);
448
 
  free((unsigned char*) share->name);
449
 
  free((unsigned char*) share);
 
298
  VOID(pthread_mutex_destroy(&share->intern_lock));
 
299
  my_free((uchar*) share->name, MYF(0));
 
300
  my_free((uchar*) share, MYF(0));
450
301
  return;
451
302
}