~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/memory/hp_create.cc

  • Committer: Stewart Smith
  • Date: 2010-09-20 05:32:43 UTC
  • mto: (1786.1.1 build)
  • mto: This revision was merged to the branch mainline in revision 1787.
  • Revision ID: stewart@flamingspork.com-20100920053243-u844cs5xc1sby4xw
add argument check to EXP()

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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  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 void init_block(HP_BLOCK *block,uint32_t chunk_length, uint32_t min_records,
28
 
                        uint32_t max_records);
29
 
 
30
 
#define FIXED_REC_OVERHEAD (sizeof(unsigned char))
31
 
#define VARIABLE_REC_OVERHEAD (sizeof(unsigned char**) + ALIGN_SIZE(sizeof(unsigned char)))
32
 
 
33
 
/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
34
 
#define VARIABLE_MIN_CHUNK_SIZE \
35
 
        ((sizeof(unsigned char**) + VARIABLE_REC_OVERHEAD + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1))
36
 
 
37
 
 
38
 
/* Create a heap table */
39
 
 
40
 
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)
46
 
{
47
 
  uint32_t i, key_segs, max_length, length;
48
 
  uint32_t max_rows_for_stated_memory;
49
 
  HP_SHARE *share= 0;
50
 
  HA_KEYSEG *keyseg;
51
 
 
52
 
  if (not create_info->internal_table)
53
 
  {
54
 
    THR_LOCK_heap.lock();
55
 
    if ((share= hp_find_named_heap(name)) && share->open_count == 0)
56
 
    {
57
 
      hp_free(share);
58
 
      share= 0;
59
 
    }
60
 
  }
61
 
 
62
 
  if (!share)
63
 
  {
64
 
    size_t chunk_dataspace_length;
65
 
    uint32_t chunk_length;
66
 
    uint32_t fixed_data_length, fixed_column_count;
67
 
    HP_KEYDEF *keyinfo;
68
 
 
69
 
    if (create_info->max_chunk_size)
70
 
    {
71
 
      uint32_t configured_chunk_size= create_info->max_chunk_size;
72
 
 
73
 
      /* User requested variable-size records, let's see if they're possible */
74
 
 
75
 
      if (configured_chunk_size < key_part_size)
76
 
      {
77
 
        /* Eventual chunk_size cannot be smaller than key data,
78
 
          which allows all keys to fit into the first chunk */
79
 
        my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "block_size");
80
 
        THR_LOCK_heap.unlock();
81
 
        return(ER_CANT_USE_OPTION_HERE);
82
 
      }
83
 
 
84
 
      /* max_chunk_size is near the full reclength, let's use fixed size */
85
 
      chunk_dataspace_length= reclength;
86
 
    }
87
 
    else
88
 
    {
89
 
      /* if max_chunk_size is not specified, put the whole record in one chunk */
90
 
      chunk_dataspace_length= reclength;
91
 
    }
92
 
 
93
 
    {
94
 
      fixed_data_length= reclength;
95
 
      fixed_column_count= columns;
96
 
    }
97
 
 
98
 
    /*
99
 
      We store unsigned char* del_link inside the data area of deleted records,
100
 
      so the data length should be at least sizeof(unsigned char*)
101
 
    */
102
 
    set_if_bigger(chunk_dataspace_length, sizeof (unsigned char**));
103
 
 
104
 
    {
105
 
      chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
106
 
    }
107
 
 
108
 
    /* Align chunk length to the next pointer */
109
 
    chunk_length= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
110
 
 
111
 
 
112
 
 
113
 
    for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
114
 
    {
115
 
      memset(&keyinfo->block, 0, sizeof(keyinfo->block));
116
 
      for (uint32_t j= length= 0; j < keyinfo->keysegs; j++)
117
 
      {
118
 
        length+= keyinfo->seg[j].length;
119
 
        if (keyinfo->seg[j].null_bit)
120
 
        {
121
 
          length++;
122
 
          if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
123
 
            keyinfo->flag|= HA_NULL_PART_KEY;
124
 
        }
125
 
        switch (keyinfo->seg[j].type) {
126
 
        case HA_KEYTYPE_LONG_INT:
127
 
        case HA_KEYTYPE_DOUBLE:
128
 
        case HA_KEYTYPE_ULONG_INT:
129
 
        case HA_KEYTYPE_LONGLONG:
130
 
        case HA_KEYTYPE_ULONGLONG:
131
 
          keyinfo->seg[j].flag|= HA_SWAP_KEY;
132
 
          break;
133
 
        case HA_KEYTYPE_VARBINARY1:
134
 
          /* Case-insensitiveness is handled in coll->hash_sort */
135
 
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
136
 
          /* fall_through */
137
 
        case HA_KEYTYPE_VARTEXT1:
138
 
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
139
 
          length+= 2;
140
 
          /* Save number of bytes used to store length */
141
 
          keyinfo->seg[j].bit_start= 1;
142
 
          break;
143
 
        case HA_KEYTYPE_VARBINARY2:
144
 
          /* Case-insensitiveness is handled in coll->hash_sort */
145
 
          /* fall_through */
146
 
        case HA_KEYTYPE_VARTEXT2:
147
 
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
148
 
          length+= 2;
149
 
          /* Save number of bytes used to store length */
150
 
          keyinfo->seg[j].bit_start= 2;
151
 
          /*
152
 
            Make future comparison simpler by only having to check for
153
 
            one type
154
 
          */
155
 
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
156
 
          break;
157
 
        default:
158
 
          break;
159
 
        }
160
 
      }
161
 
      keyinfo->length= length;
162
 
      if (length > max_length)
163
 
        max_length= length;
164
 
      key_segs+= keyinfo->keysegs;
165
 
    }
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;
172
 
 
173
 
    /*
174
 
       Max_records is used for estimating block sizes and for enforcement.
175
 
       Calculate the very maximum number of rows (if everything was one chunk) and
176
 
       then take either that value or configured max_records (pick smallest one)
177
 
    */
178
 
    max_rows_for_stated_memory= (uint32_t)(create_info->max_table_size /
179
 
      (keys_memory_size + chunk_length));
180
 
    max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
181
 
                      max_records : max_rows_for_stated_memory);
182
 
 
183
 
    share->key_stat_version= 1;
184
 
    keyseg= keys ? share->keydef->seg : NULL;
185
 
 
186
 
    init_block(&share->recordspace.block, chunk_length, min_records, max_records);
187
 
    /* Fix keys */
188
 
    memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
189
 
    for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
190
 
    {
191
 
      keyinfo->seg= keyseg;
192
 
      memcpy(keyseg, keydef[i].seg,
193
 
             (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194
 
      keyseg+= keydef[i].keysegs;
195
 
      {
196
 
        init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
197
 
                   max_records);
198
 
        keyinfo->hash_buckets= 0;
199
 
      }
200
 
      if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
201
 
        share->auto_key= i + 1;
202
 
    }
203
 
    share->min_records= min_records;
204
 
    share->max_records= max_records;
205
 
    share->max_table_size= create_info->max_table_size;
206
 
    share->index_length= 0;
207
 
    share->blength= 1;
208
 
    share->keys= keys;
209
 
    share->max_key_length= max_length;
210
 
    share->column_count= columns;
211
 
    share->changed= 0;
212
 
    share->auto_key= create_info->auto_key;
213
 
    share->auto_key_type= create_info->auto_key_type;
214
 
    share->auto_increment= create_info->auto_increment;
215
 
 
216
 
    share->fixed_data_length= fixed_data_length;
217
 
    share->fixed_column_count= fixed_column_count;
218
 
 
219
 
    share->recordspace.chunk_length= chunk_length;
220
 
    share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
221
 
    share->recordspace.total_data_length= 0;
222
 
 
223
 
    {
224
 
      share->recordspace.offset_link= 1<<22; /* Make it likely to fail if anyone uses this offset */
225
 
      share->recordspace.offset_status= chunk_dataspace_length;
226
 
    }
227
 
 
228
 
    /* Must be allocated separately for rename to work */
229
 
    share->name.append(name);
230
 
    if (!create_info->internal_table)
231
 
    {
232
 
      heap_share_list.push_front(share);
233
 
    }
234
 
    else
235
 
      share->delete_on_close= 1;
236
 
  }
237
 
  if (!create_info->internal_table)
238
 
    THR_LOCK_heap.unlock();
239
 
 
240
 
  *res= share;
241
 
  return(0);
242
 
 
243
 
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();
252
 
  return(1);
253
 
} /* heap_create */
254
 
 
255
 
 
256
 
static void init_block(HP_BLOCK *block, uint32_t chunk_length, uint32_t min_records,
257
 
                       uint32_t max_records)
258
 
{
259
 
  uint32_t recbuffer,records_in_block;
260
 
 
261
 
  max_records= max(min_records,max_records);
262
 
  if (!max_records)
263
 
    max_records= 1000;                  /* As good as quess as anything */
264
 
 
265
 
  /* we want to start each chunk at 8 bytes boundary, round recbuffer to the next 8 */
266
 
  recbuffer= (uint) (chunk_length + sizeof(unsigned char**) - 1) & ~(sizeof(unsigned char**) - 1);
267
 
  records_in_block= max_records / 10;
268
 
  if (records_in_block < 10 && max_records)
269
 
    records_in_block= 10;
270
 
  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) *
273
 
                      HP_MAX_LEVELS) / recbuffer + 1;
274
 
  block->records_in_block= records_in_block;
275
 
  block->recbuffer= recbuffer;
276
 
  block->last_allocated= 0L;
277
 
 
278
 
  for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
279
 
  {
280
 
    block->level_info[i].records_under_level=
281
 
      (!i ? 1 : i == 1 ? records_in_block :
282
 
       HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
283
 
  }
284
 
}
285
 
 
286
 
 
287
 
static inline void heap_try_free(HP_SHARE *share)
288
 
{
289
 
  if (share->open_count == 0)
290
 
    hp_free(share);
291
 
  else
292
 
    share->delete_on_close= 1;
293
 
}
294
 
 
295
 
 
296
 
int heap_delete_table(const char *name)
297
 
{
298
 
  int result;
299
 
  register HP_SHARE *share;
300
 
 
301
 
  THR_LOCK_heap.lock();
302
 
  if ((share= hp_find_named_heap(name)))
303
 
  {
304
 
    heap_try_free(share);
305
 
    result= 0;
306
 
  }
307
 
  else
308
 
  {
309
 
    result= errno=ENOENT;
310
 
  }
311
 
  THR_LOCK_heap.unlock();
312
 
  return(result);
313
 
}
314
 
 
315
 
 
316
 
void hp_free(HP_SHARE *share)
317
 
{
318
 
  heap_share_list.remove(share);        /* If not internal table */
319
 
  hp_clear(share);                      /* Remove blocks from memory */
320
 
  if (share->keydef)
321
 
    delete [] share->keydef->seg;
322
 
  delete [] share->keydef;
323
 
  delete share;
324
 
}