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

« back to all changes in this revision

Viewing changes to plugin/memory/hp_create.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-10-02 14:17:48 UTC
  • mfrom: (1.1.1 upstream)
  • mto: (2.1.17 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20101002141748-m6vbfbfjhrw1153e
Tags: 2010.09.1802-1
* New upstream release.
* Removed pid-file argument hack.
* Updated GPL-2 address to be new address.
* Directly copy in drizzledump.1 since debian doesn't have sphinx 1.0 yet.
* Link to jquery from libjs-jquery. Add it as a depend.
* Add drizzled.8 symlink to the install files.

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 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
}