~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/heap/hp_create.c

  • Committer: Brian Aker
  • Date: 2008-06-28 01:01:34 UTC
  • Revision ID: brian@tangent.org-20080628010134-n44ixrdgb6yexhkb
Remove my_pthread_getspecific_ptr()

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   along with this program; if not, write to the Free Software
14
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
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
 
 
 
16
#include "heapdef.h"
 
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);
37
21
 
38
22
/* Create a heap table */
39
23
 
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)
 
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)
46
27
{
47
 
  uint32_t i, key_segs, max_length, length;
48
 
  uint32_t max_rows_for_stated_memory;
 
28
  uint i, j, key_segs, max_length, length;
49
29
  HP_SHARE *share= 0;
50
30
  HA_KEYSEG *keyseg;
 
31
  DBUG_ENTER("heap_create");
51
32
 
52
 
  if (not create_info->internal_table)
 
33
  if (!create_info->internal_table)
53
34
  {
54
 
    THR_LOCK_heap.lock();
 
35
    pthread_mutex_lock(&THR_LOCK_heap);
55
36
    if ((share= hp_find_named_heap(name)) && share->open_count == 0)
56
37
    {
57
38
      hp_free(share);
58
39
      share= 0;
59
40
    }
60
 
  }
 
41
  }  
61
42
 
62
43
  if (!share)
63
44
  {
64
 
    size_t chunk_dataspace_length;
65
 
    uint32_t chunk_length;
66
 
    uint32_t fixed_data_length, fixed_column_count;
67
45
    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
 
 
 
46
    DBUG_PRINT("info",("Initializing new table"));
 
47
    
98
48
    /*
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*)
 
49
      We have to store sometimes uchar* del_link in records,
 
50
      so the record length should be at least sizeof(uchar*)
101
51
    */
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
 
 
 
52
    set_if_bigger(reclength, sizeof (uchar*));
 
53
    
113
54
    for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++)
114
55
    {
115
 
      memset(&keyinfo->block, 0, sizeof(keyinfo->block));
116
 
      for (uint32_t j= length= 0; j < keyinfo->keysegs; j++)
 
56
      bzero((char*) &keyinfo->block,sizeof(keyinfo->block));
 
57
      bzero((char*) &keyinfo->rb_tree ,sizeof(keyinfo->rb_tree));
 
58
      for (j= length= 0; j < keyinfo->keysegs; j++)
117
59
      {
118
60
        length+= keyinfo->seg[j].length;
119
61
        if (keyinfo->seg[j].null_bit)
121
63
          length++;
122
64
          if (!(keyinfo->flag & HA_NULL_ARE_EQUAL))
123
65
            keyinfo->flag|= HA_NULL_PART_KEY;
 
66
          if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
 
67
            keyinfo->rb_tree.size_of_element++;
124
68
        }
125
69
        switch (keyinfo->seg[j].type) {
 
70
        case HA_KEYTYPE_SHORT_INT:
126
71
        case HA_KEYTYPE_LONG_INT:
 
72
        case HA_KEYTYPE_FLOAT:
127
73
        case HA_KEYTYPE_DOUBLE:
 
74
        case HA_KEYTYPE_USHORT_INT:
128
75
        case HA_KEYTYPE_ULONG_INT:
129
76
        case HA_KEYTYPE_LONGLONG:
130
77
        case HA_KEYTYPE_ULONGLONG:
 
78
        case HA_KEYTYPE_INT24:
 
79
        case HA_KEYTYPE_UINT24:
 
80
        case HA_KEYTYPE_INT8:
131
81
          keyinfo->seg[j].flag|= HA_SWAP_KEY;
132
82
          break;
133
83
        case HA_KEYTYPE_VARBINARY1:
135
85
          keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
136
86
          /* fall_through */
137
87
        case HA_KEYTYPE_VARTEXT1:
 
88
          if (!my_binary_compare(keyinfo->seg[j].charset))
 
89
            keyinfo->flag|= HA_END_SPACE_KEY;
138
90
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
139
91
          length+= 2;
140
92
          /* Save number of bytes used to store length */
144
96
          /* Case-insensitiveness is handled in coll->hash_sort */
145
97
          /* fall_through */
146
98
        case HA_KEYTYPE_VARTEXT2:
 
99
          if (!my_binary_compare(keyinfo->seg[j].charset))
 
100
            keyinfo->flag|= HA_END_SPACE_KEY;
147
101
          keyinfo->flag|= HA_VAR_LENGTH_KEY;
148
102
          length+= 2;
149
103
          /* Save number of bytes used to store length */
157
111
        default:
158
112
          break;
159
113
        }
 
114
        if (keyinfo->seg[j].flag & HA_END_SPACE_ARE_EQUAL)
 
115
          keyinfo->flag|= HA_END_SPACE_KEY;
160
116
      }
161
117
      keyinfo->length= length;
 
118
      length+= keyinfo->rb_tree.size_of_element + 
 
119
               ((keyinfo->algorithm == HA_KEY_ALG_BTREE) ? sizeof(uchar*) : 0);
162
120
      if (length > max_length)
163
121
        max_length= length;
164
122
      key_segs+= keyinfo->keysegs;
 
123
      if (keyinfo->algorithm == HA_KEY_ALG_BTREE)
 
124
      {
 
125
        key_segs++; /* additional HA_KEYTYPE_END segment */
 
126
        if (keyinfo->flag & HA_VAR_LENGTH_KEY)
 
127
          keyinfo->get_key_length= hp_rb_var_key_length;
 
128
        else if (keyinfo->flag & HA_NULL_PART_KEY)
 
129
          keyinfo->get_key_length= hp_rb_null_key_length;
 
130
        else
 
131
          keyinfo->get_key_length= hp_rb_key_length;
 
132
      }
165
133
    }
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
 
 
 
134
    if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+
 
135
                                       keys*sizeof(HP_KEYDEF)+
 
136
                                       key_segs*sizeof(HA_KEYSEG),
 
137
                                       MYF(MY_ZEROFILL))))
 
138
      goto err;
 
139
    share->keydef= (HP_KEYDEF*) (share + 1);
183
140
    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 */
 
141
    keyseg= (HA_KEYSEG*) (share->keydef + keys);
 
142
    init_block(&share->block, reclength + 1, min_records, max_records);
 
143
        /* Fix keys */
188
144
    memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys));
189
145
    for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++)
190
146
    {
192
148
      memcpy(keyseg, keydef[i].seg,
193
149
             (size_t) (sizeof(keyseg[0]) * keydef[i].keysegs));
194
150
      keyseg+= keydef[i].keysegs;
 
151
 
 
152
      if (keydef[i].algorithm == HA_KEY_ALG_BTREE)
 
153
      {
 
154
        /* additional HA_KEYTYPE_END keyseg */
 
155
        keyseg->type=     HA_KEYTYPE_END;
 
156
        keyseg->length=   sizeof(uchar*);
 
157
        keyseg->flag=     0;
 
158
        keyseg->null_bit= 0;
 
159
        keyseg++;
 
160
 
 
161
        init_tree(&keyinfo->rb_tree, 0, 0, sizeof(uchar*),
 
162
                  (qsort_cmp2)keys_compare, 1, NULL, NULL);
 
163
        keyinfo->delete_key= hp_rb_delete_key;
 
164
        keyinfo->write_key= hp_rb_write_key;
 
165
      }
 
166
      else
195
167
      {
196
168
        init_block(&keyinfo->block, sizeof(HASH_INFO), min_records,
197
169
                   max_records);
 
170
        keyinfo->delete_key= hp_delete_key;
 
171
        keyinfo->write_key= hp_write_key;
198
172
        keyinfo->hash_buckets= 0;
199
173
      }
200
174
      if ((keyinfo->flag & HA_AUTO_KEY) && create_info->with_auto_increment)
203
177
    share->min_records= min_records;
204
178
    share->max_records= max_records;
205
179
    share->max_table_size= create_info->max_table_size;
206
 
    share->index_length= 0;
 
180
    share->data_length= share->index_length= 0;
 
181
    share->reclength= reclength;
207
182
    share->blength= 1;
208
183
    share->keys= keys;
209
184
    share->max_key_length= max_length;
210
 
    share->column_count= columns;
211
185
    share->changed= 0;
212
186
    share->auto_key= create_info->auto_key;
213
187
    share->auto_key_type= create_info->auto_key_type;
214
188
    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
189
    /* Must be allocated separately for rename to work */
229
 
    share->name.append(name);
 
190
    if (!(share->name= my_strdup(name,MYF(0))))
 
191
    {
 
192
      my_free((uchar*) share,MYF(0));
 
193
      goto err;
 
194
    }
 
195
#ifdef THREAD
 
196
    thr_lock_init(&share->lock);
 
197
    VOID(pthread_mutex_init(&share->intern_lock,MY_MUTEX_INIT_FAST));
 
198
#endif
230
199
    if (!create_info->internal_table)
231
200
    {
232
 
      heap_share_list.push_front(share);
 
201
      share->open_list.data= (void*) share;
 
202
      heap_share_list= list_add(heap_share_list,&share->open_list);
233
203
    }
234
204
    else
235
205
      share->delete_on_close= 1;
236
206
  }
237
207
  if (!create_info->internal_table)
238
 
    THR_LOCK_heap.unlock();
 
208
    pthread_mutex_unlock(&THR_LOCK_heap);
239
209
 
240
210
  *res= share;
241
 
  return(0);
 
211
  DBUG_RETURN(0);
242
212
 
243
213
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);
 
214
  if (!create_info->internal_table)
 
215
    pthread_mutex_unlock(&THR_LOCK_heap);
 
216
  DBUG_RETURN(1);
253
217
} /* heap_create */
254
218
 
255
219
 
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;
 
220
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2)
 
221
{
 
222
  uint not_used[2];
 
223
  return ha_key_cmp(param->keyseg, key1, key2, param->key_length, 
 
224
                    param->search_flag, not_used);
 
225
}
 
226
 
 
227
static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
 
228
                       ulong max_records)
 
229
{
 
230
  uint i,recbuffer,records_in_block;
260
231
 
261
232
  max_records= max(min_records,max_records);
262
233
  if (!max_records)
263
234
    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);
 
235
  recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
267
236
  records_in_block= max_records / 10;
268
237
  if (records_in_block < 10 && max_records)
269
238
    records_in_block= 10;
270
239
  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) *
 
240
      (my_default_record_cache_size-sizeof(HP_PTRS)*HP_MAX_LEVELS))
 
241
    records_in_block= (my_default_record_cache_size - sizeof(HP_PTRS) *
273
242
                      HP_MAX_LEVELS) / recbuffer + 1;
274
243
  block->records_in_block= records_in_block;
275
244
  block->recbuffer= recbuffer;
276
245
  block->last_allocated= 0L;
277
246
 
278
 
  for (uint32_t i= 0; i <= HP_MAX_LEVELS; i++)
279
 
  {
 
247
  for (i= 0; i <= HP_MAX_LEVELS; i++)
280
248
    block->level_info[i].records_under_level=
281
249
      (!i ? 1 : i == 1 ? records_in_block :
282
250
       HP_PTRS_IN_NOD * block->level_info[i - 1].records_under_level);
283
 
  }
284
251
}
285
252
 
286
253
 
297
264
{
298
265
  int result;
299
266
  register HP_SHARE *share;
 
267
  DBUG_ENTER("heap_delete_table");
300
268
 
301
 
  THR_LOCK_heap.lock();
 
269
  pthread_mutex_lock(&THR_LOCK_heap);
302
270
  if ((share= hp_find_named_heap(name)))
303
271
  {
304
272
    heap_try_free(share);
306
274
  }
307
275
  else
308
276
  {
309
 
    result= errno=ENOENT;
 
277
    result= my_errno=ENOENT;
310
278
  }
311
 
  THR_LOCK_heap.unlock();
312
 
  return(result);
 
279
  pthread_mutex_unlock(&THR_LOCK_heap);
 
280
  DBUG_RETURN(result);
 
281
}
 
282
 
 
283
 
 
284
void heap_drop_table(HP_INFO *info)
 
285
{
 
286
  DBUG_ENTER("heap_drop_table");
 
287
  pthread_mutex_lock(&THR_LOCK_heap);
 
288
  heap_try_free(info->s);
 
289
  pthread_mutex_unlock(&THR_LOCK_heap);
 
290
  DBUG_VOID_RETURN;
313
291
}
314
292
 
315
293
 
316
294
void hp_free(HP_SHARE *share)
317
295
{
318
 
  heap_share_list.remove(share);        /* If not internal table */
 
296
  if (share->open_list.data)                    /* If not internal table */
 
297
    heap_share_list= list_delete(heap_share_list, &share->open_list);
319
298
  hp_clear(share);                      /* Remove blocks from memory */
320
 
  if (share->keydef)
321
 
    delete [] share->keydef->seg;
322
 
  delete [] share->keydef;
323
 
  delete share;
 
299
#ifdef THREAD
 
300
  thr_lock_delete(&share->lock);
 
301
  VOID(pthread_mutex_destroy(&share->intern_lock));
 
302
#endif
 
303
  my_free((uchar*) share->name, MYF(0));
 
304
  my_free((uchar*) share, MYF(0));
 
305
  return;
324
306
}