~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/heap/hp_create.c

  • Committer: Brian Aker
  • Date: 2008-08-05 06:19:05 UTC
  • mfrom: (244.1.1 drizzle-mem-ebay)
  • mto: This revision was merged to the branch mainline in revision 264.
  • Revision ID: brian@tangent.org-20080805061905-1r8krslxae65qh76
Merge from Harrison Fisk of the Ebay + Google Hash engine.

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"
17
19
 
18
20
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);
 
21
static void init_block(HP_BLOCK *block,uint chunk_length, ulong min_records,
 
22
                        ulong max_records);
 
23
 
 
24
#define FIXED_REC_OVERHEAD (sizeof(uchar))
 
25
#define VARIABLE_REC_OVERHEAD (sizeof(uchar**) + sizeof(uchar))
 
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(uchar**) + VARIABLE_REC_OVERHEAD + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1))
 
30
 
21
31
 
22
32
/* Create a heap table */
23
33
 
24
34
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)
 
35
    uint columns, HP_COLUMNDEF *columndef,
 
36
    uint max_key_fieldnr, uint key_part_size,
 
37
    uint reclength, uint keys_memory_size,
 
38
    ulong max_records, ulong min_records,
 
39
    HP_CREATE_INFO *create_info, HP_SHARE **res)
27
40
{
28
41
  uint i, j, key_segs, max_length, length;
 
42
  ulong max_rows_for_stated_memory;
29
43
  HP_SHARE *share= 0;
30
44
  HA_KEYSEG *keyseg;
31
45
 
41
55
 
42
56
  if (!share)
43
57
  {
 
58
    uint chunk_dataspace_length, chunk_length, is_variable_size;
 
59
    uint fixed_data_length, fixed_column_count;
44
60
    HP_KEYDEF *keyinfo;
45
 
    
 
61
 
 
62
    if (create_info->max_chunk_size)
 
63
    {
 
64
      uint 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
      uint 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
157
    /*
47
 
      We have to store sometimes uchar* del_link in records,
48
 
      so the record length should be at least sizeof(uchar*)
 
158
      We store uchar* del_link inside the data area of deleted records,
 
159
      so the data length should be at least sizeof(uchar*)
49
160
    */
50
 
    set_if_bigger(reclength, sizeof (uchar*));
 
161
    set_if_bigger(chunk_dataspace_length, sizeof (uchar**));
 
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(uchar**) - 1) & ~(sizeof(uchar**) - 1);
 
174
 
 
175
 
51
176
    
52
177
    for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
53
178
    {
125
250
    }
126
251
    if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
127
252
                                       keys*sizeof(HP_KEYDEF)+
 
253
                                       columns*sizeof(HP_COLUMNDEF)+
128
254
                                       key_segs*sizeof(HA_KEYSEG),
129
255
                                       MYF(MY_ZEROFILL))))
130
256
      goto err;
131
 
    share->keydef= (HP_KEYDEF*) (share + 1);
 
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);    
132
272
    share->key_stat_version= 1;
133
273
    keyseg= (HA_KEYSEG*) (share->keydef + keys);
134
 
    init_block(&share->block, reclength + 1, min_records, max_records);
135
 
        /* Fix keys */
 
274
    init_block(&share->recordspace.block, chunk_length, min_records, max_records);
 
275
    /* Fix keys */
136
276
    memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
137
277
    for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
138
278
    {
169
309
    share->min_records= min_records;
170
310
    share->max_records= max_records;
171
311
    share->max_table_size= create_info->max_table_size;
172
 
    share->data_length= share->index_length= 0;
173
 
    share->reclength= reclength;
 
312
    share->index_length= 0;
174
313
    share->blength= 1;
175
314
    share->keys= keys;
176
315
    share->max_key_length= max_length;
 
316
    share->column_count= columns;
177
317
    share->changed= 0;
178
318
    share->auto_key= create_info->auto_key;
179
319
    share->auto_key_type= create_info->auto_key_type;
180
320
    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(uchar**);
 
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
 
181
338
    /* Must be allocated separately for rename to work */
182
339
    if (!(share->name= my_strdup(name,MYF(0))))
183
340
    {
214
371
                    param->search_flag, not_used);
215
372
}
216
373
 
217
 
static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
 
374
static void init_block(HP_BLOCK *block, uint chunk_length, ulong min_records,
218
375
                       ulong max_records)
219
376
{
220
377
  uint i,recbuffer,records_in_block;
222
379
  max_records= max(min_records,max_records);
223
380
  if (!max_records)
224
381
    max_records= 1000;                  /* As good as quess as anything */
225
 
  recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
 
382
  
 
383
  /* we want to start each chunk at 8 bytes boundary, round recbuffer to the next 8 */
 
384
  recbuffer= (uint) (chunk_length + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);  
226
385
  records_in_block= max_records / 10;
227
386
  if (records_in_block < 10 && max_records)
228
387
    records_in_block= 10;