~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/heap/hp_write.c

  • Committer: Jay Pipes
  • Date: 2008-07-18 20:20:47 UTC
  • mto: This revision was merged to the branch mainline in revision 182.
  • Revision ID: jay@mysql.com-20080718202047-1tnd4i9z3k3cvg9v
DBUG entirely removed from server and client

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
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 */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/* Write a record to heap-databas */
17
17
 
18
 
#include "heap_priv.h"
 
18
#include "heapdef.h"
19
19
#ifdef __WIN__
20
20
#include <fcntl.h>
21
21
#endif
25
25
#define HIGHFIND 4
26
26
#define HIGHUSED 8
27
27
 
28
 
using namespace drizzled;
29
 
 
 
28
static uchar *next_free_record_pos(HP_SHARE *info);
30
29
static HASH_INFO *hp_find_free_hash(HP_SHARE *info, HP_BLOCK *block,
31
 
                                     uint32_t records);
 
30
                                     ulong records);
32
31
 
33
 
int heap_write(HP_INFO *info, const unsigned char *record)
 
32
int heap_write(HP_INFO *info, const uchar *record)
34
33
{
35
34
  HP_KEYDEF *keydef, *end;
36
 
  unsigned char *pos;
37
 
  HP_SHARE *share=info->getShare();
38
 
 
39
 
  if ((share->records >= share->max_records && share->max_records) ||
40
 
    (share->recordspace.total_data_length + share->index_length >= share->max_table_size))
41
 
  {
42
 
    return(errno=HA_ERR_RECORD_FILE_FULL);
43
 
  }
44
 
 
45
 
  if (!(pos=hp_allocate_chunkset(&share->recordspace, 1)))
46
 
    return(errno);
 
35
  uchar *pos;
 
36
  HP_SHARE *share=info->s;
 
37
  if (!(pos=next_free_record_pos(share)))
 
38
    return(my_errno);
47
39
  share->changed=1;
48
40
 
49
41
  for (keydef = share->keydef, end = keydef + share->keys; keydef < end;
50
42
       keydef++)
51
43
  {
52
 
    if (hp_write_key(info, keydef, record, pos))
 
44
    if ((*keydef->write_key)(info, keydef, record, pos))
53
45
      goto err;
54
46
  }
55
47
 
56
 
  hp_copy_record_data_to_chunkset(share, record, pos);
57
 
 
 
48
  memcpy(pos,record,(size_t) share->reclength);
 
49
  pos[share->reclength]=1;              /* Mark record as not deleted */
58
50
  if (++share->records == share->blength)
59
51
    share->blength+= share->blength;
60
 
 
61
52
  info->current_ptr=pos;
62
53
  info->current_hash_ptr=0;
63
54
  info->update|=HA_STATE_AKTIV;
67
58
 
68
59
err:
69
60
  info->errkey= keydef - share->keydef;
 
61
  /*
 
62
    We don't need to delete non-inserted key from rb-tree.  Also, if
 
63
    we got ENOMEM, the key wasn't inserted, so don't try to delete it
 
64
    either.  Otherwise for HASH index on HA_ERR_FOUND_DUPP_KEY the key
 
65
    was inserted and we have to delete it.
 
66
  */
 
67
  if (keydef->algorithm == HA_KEY_ALG_BTREE || my_errno == ENOMEM)
 
68
  {
 
69
    keydef--;
 
70
  }
70
71
  while (keydef >= share->keydef)
71
72
  {
72
 
    if (hp_delete_key(info, keydef, record, pos, 0))
 
73
    if ((*keydef->delete_key)(info, keydef, record, pos, 0))
73
74
      break;
74
75
    keydef--;
75
 
  }
76
 
 
77
 
  hp_free_chunks(&share->recordspace, pos);
78
 
 
79
 
  return(errno);
 
76
  } 
 
77
 
 
78
  share->deleted++;
 
79
  *((uchar**) pos)=share->del_link;
 
80
  share->del_link=pos;
 
81
  pos[share->reclength]=0;                      /* Record deleted */
 
82
 
 
83
  return(my_errno);
80
84
} /* heap_write */
81
85
 
 
86
/* 
 
87
  Write a key to rb_tree-index 
 
88
*/
 
89
 
 
90
int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *record, 
 
91
                    uchar *recpos)
 
92
{
 
93
  heap_rb_param custom_arg;
 
94
  uint old_allocated;
 
95
 
 
96
  custom_arg.keyseg= keyinfo->seg;
 
97
  custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
 
98
  if (keyinfo->flag & HA_NOSAME)
 
99
  {
 
100
    custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE;
 
101
    keyinfo->rb_tree.flag= TREE_NO_DUPS;
 
102
  }
 
103
  else
 
104
  {
 
105
    custom_arg.search_flag= SEARCH_SAME;
 
106
    keyinfo->rb_tree.flag= 0;
 
107
  }
 
108
  old_allocated= keyinfo->rb_tree.allocated;
 
109
  if (!tree_insert(&keyinfo->rb_tree, (void*)info->recbuf,
 
110
                   custom_arg.key_length, &custom_arg))
 
111
  {
 
112
    my_errno= HA_ERR_FOUND_DUPP_KEY;
 
113
    return 1;
 
114
  }
 
115
  info->s->index_length+= (keyinfo->rb_tree.allocated-old_allocated);
 
116
  return 0;
 
117
}
 
118
 
 
119
        /* Find where to place new record */
 
120
 
 
121
static uchar *next_free_record_pos(HP_SHARE *info)
 
122
{
 
123
  int block_pos;
 
124
  uchar *pos;
 
125
  size_t length;
 
126
 
 
127
  if (info->del_link)
 
128
  {
 
129
    pos=info->del_link;
 
130
    info->del_link= *((uchar**) pos);
 
131
    info->deleted--;
 
132
    return(pos);
 
133
  }
 
134
  if (!(block_pos=(info->records % info->block.records_in_block)))
 
135
  {
 
136
    if ((info->records > info->max_records && info->max_records) ||
 
137
        (info->data_length + info->index_length >= info->max_table_size))
 
138
    {
 
139
      my_errno=HA_ERR_RECORD_FILE_FULL;
 
140
      return(NULL);
 
141
    }
 
142
    if (hp_get_new_block(&info->block,&length))
 
143
      return(NULL);
 
144
    info->data_length+=length;
 
145
  }
 
146
  return((uchar*) info->block.level_info[0].last_blocks+
 
147
              block_pos*info->block.recbuffer);
 
148
}
 
149
 
 
150
 
82
151
/*
83
152
  Write a hash-key to the hash-index
84
153
  SYNOPSIS
85
154
    info     Heap table info
86
155
    keyinfo  Key info
87
156
    record   Table record to added
88
 
    recpos   Memory buffer where the table record will be stored if added
 
157
    recpos   Memory buffer where the table record will be stored if added 
89
158
             successfully
90
159
  NOTE
91
 
    Hash index uses HP_BLOCK structure as a 'growable array' of HASH_INFO
 
160
    Hash index uses HP_BLOCK structure as a 'growable array' of HASH_INFO 
92
161
    structs. Array size == number of entries in hash index.
93
162
    hp_mask(hp_rec_hashnr()) maps hash entries values to hash array positions.
94
163
    If there are several hash entries with the same hash array position P,
95
 
    they are connected in a linked list via HASH_INFO::next_key. The first
96
 
    list element is located at position P, next elements are located at
 
164
    they are connected in a linked list via HASH_INFO::next_key. The first 
 
165
    list element is located at position P, next elements are located at 
97
166
    positions for which there is no record that should be located at that
98
167
    position. The order of elements in the list is arbitrary.
99
168
 
100
169
  RETURN
101
170
    0  - OK
102
171
    -1 - Out of memory
103
 
    HA_ERR_FOUND_DUPP_KEY - Duplicate record on unique key. The record was
 
172
    HA_ERR_FOUND_DUPP_KEY - Duplicate record on unique key. The record was 
104
173
    still added and the caller must call hp_delete_key for it.
105
174
*/
106
175
 
107
176
int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
108
 
                 const unsigned char *record, unsigned char *recpos)
 
177
                 const uchar *record, uchar *recpos)
109
178
{
110
 
  HP_SHARE *share = info->getShare();
 
179
  HP_SHARE *share = info->s;
111
180
  int flag;
112
 
  uint32_t halfbuff,hashnr,first_index;
113
 
  unsigned char *ptr_to_rec= NULL,*ptr_to_rec2= NULL;
 
181
  ulong halfbuff,hashnr,first_index;
 
182
  uchar *ptr_to_rec= NULL,*ptr_to_rec2= NULL;
114
183
  HASH_INFO *empty, *gpos= NULL, *gpos2= NULL, *pos;
115
184
 
116
185
  flag=0;
118
187
    return(-1);                         /* No more memory */
119
188
  halfbuff= (long) share->blength >> 1;
120
189
  pos= hp_find_hash(&keyinfo->block,(first_index=share->records-halfbuff));
121
 
 
 
190
  
122
191
  /*
123
192
    We're about to add one more hash array position, with hash_mask=#records.
124
 
    The number of hash positions will change and some entries might need to
125
 
    be relocated to the newly added position. Those entries are currently
126
 
    members of the list that starts at #first_index position (this is
 
193
    The number of hash positions will change and some entries might need to 
 
194
    be relocated to the newly added position. Those entries are currently 
 
195
    members of the list that starts at #first_index position (this is 
127
196
    guaranteed by properties of hp_mask(hp_rec_hashnr(X)) mapping function)
128
197
    At #first_index position currently there may be either:
129
198
    a) An entry with hashnr != first_index. We don't need to move it.
130
199
    or
131
200
    b) A list of items with hash_mask=first_index. The list contains entries
132
201
       of 2 types:
133
 
       1) entries that should be relocated to the list that starts at new
 
202
       1) entries that should be relocated to the list that starts at new 
134
203
          position we're adding ('uppper' list)
135
 
       2) entries that should be left in the list starting at #first_index
 
204
       2) entries that should be left in the list starting at #first_index 
136
205
          position ('lower' list)
137
206
  */
138
207
  if (pos != empty)                             /* If some records */
142
211
      hashnr = hp_rec_hashnr(keyinfo, pos->ptr_to_rec);
143
212
      if (flag == 0)
144
213
      {
145
 
        /*
146
 
          First loop, bail out if we're dealing with case a) from above
 
214
        /* 
 
215
          First loop, bail out if we're dealing with case a) from above 
147
216
          comment
148
217
        */
149
218
        if (hp_mask(hashnr, share->blength, share->records) != first_index)
161
230
        ptr_to_rec2 - same for upper list.
162
231
      */
163
232
      if (!(hashnr & halfbuff))
164
 
      {
 
233
      {                                         
165
234
        /* Key should be put into 'lower' list */
166
235
        if (!(flag & LOWFIND))
167
236
        {
177
246
          else
178
247
          {
179
248
            /*
180
 
              We can only get here at first iteration: key is at 'lower'
 
249
              We can only get here at first iteration: key is at 'lower' 
181
250
              position pos and should be left here.
182
251
            */
183
252
            flag=LOWFIND | LOWUSED;
225
294
      }
226
295
    }
227
296
    while ((pos=pos->next_key));
228
 
 
 
297
    
229
298
    if ((flag & (LOWFIND | HIGHFIND)) == (LOWFIND | HIGHFIND))
230
299
    {
231
300
      /*
286
355
      {
287
356
        if (! hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 1))
288
357
        {
289
 
          return(errno=HA_ERR_FOUND_DUPP_KEY);
 
358
          return(my_errno=HA_ERR_FOUND_DUPP_KEY);
290
359
        }
291
360
      } while ((pos=pos->next_key));
292
361
    }
297
366
        /* Returns ptr to block, and allocates block if neaded */
298
367
 
299
368
static HASH_INFO *hp_find_free_hash(HP_SHARE *info,
300
 
                                     HP_BLOCK *block, uint32_t records)
 
369
                                     HP_BLOCK *block, ulong records)
301
370
{
302
 
  uint32_t block_pos;
 
371
  uint block_pos;
303
372
  size_t length;
304
373
 
305
374
  if (records < block->last_allocated)
311
380
    info->index_length+=length;
312
381
  }
313
382
  block->last_allocated=records+1;
314
 
  return((HASH_INFO*) ((unsigned char*) block->level_info[0].last_blocks+
 
383
  return((HASH_INFO*) ((uchar*) block->level_info[0].last_blocks+
315
384
                       block_pos*block->recbuffer));
316
385
}