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

« back to all changes in this revision

Viewing changes to plugin/heap/hp_write.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-2002, 2004-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
 
/* Write a record to heap-databas */
17
 
 
18
 
#include "heap_priv.h"
19
 
#ifdef __WIN__
20
 
#include <fcntl.h>
21
 
#endif
22
 
 
23
 
#define LOWFIND 1
24
 
#define LOWUSED 2
25
 
#define HIGHFIND 4
26
 
#define HIGHUSED 8
27
 
 
28
 
using namespace drizzled;
29
 
 
30
 
static HASH_INFO *hp_find_free_hash(HP_SHARE *info, HP_BLOCK *block,
31
 
                                     uint32_t records);
32
 
 
33
 
int heap_write(HP_INFO *info, const unsigned char *record)
34
 
{
35
 
  HP_KEYDEF *keydef, *end;
36
 
  unsigned char *pos;
37
 
  HP_SHARE *share=info->s;
38
 
  uint32_t rec_length, chunk_count;
39
 
 
40
 
  if ((share->records >= share->max_records && share->max_records) ||
41
 
    (share->recordspace.total_data_length + share->index_length >= share->max_table_size))
42
 
  {
43
 
    return(errno=HA_ERR_RECORD_FILE_FULL);
44
 
  }
45
 
 
46
 
  rec_length = hp_get_encoded_data_length(share, record, &chunk_count);
47
 
 
48
 
  if (!(pos=hp_allocate_chunkset(&share->recordspace, chunk_count)))
49
 
    return(errno);
50
 
  share->changed=1;
51
 
 
52
 
  for (keydef = share->keydef, end = keydef + share->keys; keydef < end;
53
 
       keydef++)
54
 
  {
55
 
    if ((*keydef->write_key)(info, keydef, record, pos))
56
 
      goto err;
57
 
  }
58
 
 
59
 
  hp_copy_record_data_to_chunkset(share, record, pos);
60
 
 
61
 
  if (++share->records == share->blength)
62
 
    share->blength+= share->blength;
63
 
 
64
 
  info->current_ptr=pos;
65
 
  info->current_hash_ptr=0;
66
 
  info->update|=HA_STATE_AKTIV;
67
 
  if (share->auto_key)
68
 
    heap_update_auto_increment(info, record);
69
 
  return(0);
70
 
 
71
 
err:
72
 
  info->errkey= keydef - share->keydef;
73
 
  /*
74
 
    We don't need to delete non-inserted key from rb-tree.  Also, if
75
 
    we got ENOMEM, the key wasn't inserted, so don't try to delete it
76
 
    either.  Otherwise for HASH index on HA_ERR_FOUND_DUPP_KEY the key
77
 
    was inserted and we have to delete it.
78
 
  */
79
 
  if (keydef->algorithm == HA_KEY_ALG_BTREE || errno == ENOMEM)
80
 
  {
81
 
    keydef--;
82
 
  }
83
 
  while (keydef >= share->keydef)
84
 
  {
85
 
    if ((*keydef->delete_key)(info, keydef, record, pos, 0))
86
 
      break;
87
 
    keydef--;
88
 
  }
89
 
 
90
 
  hp_free_chunks(&share->recordspace, pos);
91
 
 
92
 
  return(errno);
93
 
} /* heap_write */
94
 
 
95
 
/*
96
 
  Write a key to rb_tree-index
97
 
*/
98
 
 
99
 
int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const unsigned char *record,
100
 
                    unsigned char *recpos)
101
 
{
102
 
  heap_rb_param custom_arg;
103
 
  uint32_t old_allocated;
104
 
 
105
 
  custom_arg.keyseg= keyinfo->seg;
106
 
  custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
107
 
  if (keyinfo->flag & HA_NOSAME)
108
 
  {
109
 
    custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE;
110
 
    keyinfo->rb_tree.flag= TREE_NO_DUPS;
111
 
  }
112
 
  else
113
 
  {
114
 
    custom_arg.search_flag= SEARCH_SAME;
115
 
    keyinfo->rb_tree.flag= 0;
116
 
  }
117
 
  old_allocated= keyinfo->rb_tree.allocated;
118
 
  if (!tree_insert(&keyinfo->rb_tree, (void*)info->recbuf,
119
 
                   custom_arg.key_length, &custom_arg))
120
 
  {
121
 
    errno= HA_ERR_FOUND_DUPP_KEY;
122
 
    return 1;
123
 
  }
124
 
  info->s->index_length+= (keyinfo->rb_tree.allocated-old_allocated);
125
 
  return 0;
126
 
}
127
 
 
128
 
/*
129
 
  Write a hash-key to the hash-index
130
 
  SYNOPSIS
131
 
    info     Heap table info
132
 
    keyinfo  Key info
133
 
    record   Table record to added
134
 
    recpos   Memory buffer where the table record will be stored if added
135
 
             successfully
136
 
  NOTE
137
 
    Hash index uses HP_BLOCK structure as a 'growable array' of HASH_INFO
138
 
    structs. Array size == number of entries in hash index.
139
 
    hp_mask(hp_rec_hashnr()) maps hash entries values to hash array positions.
140
 
    If there are several hash entries with the same hash array position P,
141
 
    they are connected in a linked list via HASH_INFO::next_key. The first
142
 
    list element is located at position P, next elements are located at
143
 
    positions for which there is no record that should be located at that
144
 
    position. The order of elements in the list is arbitrary.
145
 
 
146
 
  RETURN
147
 
    0  - OK
148
 
    -1 - Out of memory
149
 
    HA_ERR_FOUND_DUPP_KEY - Duplicate record on unique key. The record was
150
 
    still added and the caller must call hp_delete_key for it.
151
 
*/
152
 
 
153
 
int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo,
154
 
                 const unsigned char *record, unsigned char *recpos)
155
 
{
156
 
  HP_SHARE *share = info->s;
157
 
  int flag;
158
 
  uint32_t halfbuff,hashnr,first_index;
159
 
  unsigned char *ptr_to_rec= NULL,*ptr_to_rec2= NULL;
160
 
  HASH_INFO *empty, *gpos= NULL, *gpos2= NULL, *pos;
161
 
 
162
 
  flag=0;
163
 
  if (!(empty= hp_find_free_hash(share,&keyinfo->block,share->records)))
164
 
    return(-1);                         /* No more memory */
165
 
  halfbuff= (long) share->blength >> 1;
166
 
  pos= hp_find_hash(&keyinfo->block,(first_index=share->records-halfbuff));
167
 
 
168
 
  /*
169
 
    We're about to add one more hash array position, with hash_mask=#records.
170
 
    The number of hash positions will change and some entries might need to
171
 
    be relocated to the newly added position. Those entries are currently
172
 
    members of the list that starts at #first_index position (this is
173
 
    guaranteed by properties of hp_mask(hp_rec_hashnr(X)) mapping function)
174
 
    At #first_index position currently there may be either:
175
 
    a) An entry with hashnr != first_index. We don't need to move it.
176
 
    or
177
 
    b) A list of items with hash_mask=first_index. The list contains entries
178
 
       of 2 types:
179
 
       1) entries that should be relocated to the list that starts at new
180
 
          position we're adding ('uppper' list)
181
 
       2) entries that should be left in the list starting at #first_index
182
 
          position ('lower' list)
183
 
  */
184
 
  if (pos != empty)                             /* If some records */
185
 
  {
186
 
    do
187
 
    {
188
 
      hashnr = hp_rec_hashnr(keyinfo, pos->ptr_to_rec);
189
 
      if (flag == 0)
190
 
      {
191
 
        /*
192
 
          First loop, bail out if we're dealing with case a) from above
193
 
          comment
194
 
        */
195
 
        if (hp_mask(hashnr, share->blength, share->records) != first_index)
196
 
          break;
197
 
      }
198
 
      /*
199
 
        flag & LOWFIND - found a record that should be put into lower position
200
 
        flag & LOWUSED - lower position occupied by the record
201
 
        Same for HIGHFIND and HIGHUSED and 'upper' position
202
 
 
203
 
        gpos  - ptr to last element in lower position's list
204
 
        gpos2 - ptr to last element in upper position's list
205
 
 
206
 
        ptr_to_rec - ptr to last entry that should go into lower list.
207
 
        ptr_to_rec2 - same for upper list.
208
 
      */
209
 
      if (!(hashnr & halfbuff))
210
 
      {
211
 
        /* Key should be put into 'lower' list */
212
 
        if (!(flag & LOWFIND))
213
 
        {
214
 
          /* key is the first element to go into lower position */
215
 
          if (flag & HIGHFIND)
216
 
          {
217
 
            flag=LOWFIND | HIGHFIND;
218
 
            /* key shall be moved to the current empty position */
219
 
            gpos=empty;
220
 
            ptr_to_rec=pos->ptr_to_rec;
221
 
            empty=pos;                          /* This place is now free */
222
 
          }
223
 
          else
224
 
          {
225
 
            /*
226
 
              We can only get here at first iteration: key is at 'lower'
227
 
              position pos and should be left here.
228
 
            */
229
 
            flag=LOWFIND | LOWUSED;
230
 
            gpos=pos;
231
 
            ptr_to_rec=pos->ptr_to_rec;
232
 
          }
233
 
        }
234
 
        else
235
 
        {
236
 
          /* Already have another key for lower position */
237
 
          if (!(flag & LOWUSED))
238
 
          {
239
 
            /* Change link of previous lower-list key */
240
 
            gpos->ptr_to_rec=ptr_to_rec;
241
 
            gpos->next_key=pos;
242
 
            flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
243
 
          }
244
 
          gpos=pos;
245
 
          ptr_to_rec=pos->ptr_to_rec;
246
 
        }
247
 
      }
248
 
      else
249
 
      {
250
 
        /* key will be put into 'higher' list */
251
 
        if (!(flag & HIGHFIND))
252
 
        {
253
 
          flag= (flag & LOWFIND) | HIGHFIND;
254
 
          /* key shall be moved to the last (empty) position */
255
 
          gpos2= empty;
256
 
          empty= pos;
257
 
          ptr_to_rec2=pos->ptr_to_rec;
258
 
        }
259
 
        else
260
 
        {
261
 
          if (!(flag & HIGHUSED))
262
 
          {
263
 
            /* Change link of previous upper-list key and save */
264
 
            gpos2->ptr_to_rec=ptr_to_rec2;
265
 
            gpos2->next_key=pos;
266
 
            flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
267
 
          }
268
 
          gpos2=pos;
269
 
          ptr_to_rec2=pos->ptr_to_rec;
270
 
        }
271
 
      }
272
 
    }
273
 
    while ((pos=pos->next_key));
274
 
 
275
 
    if ((flag & (LOWFIND | HIGHFIND)) == (LOWFIND | HIGHFIND))
276
 
    {
277
 
      /*
278
 
        If both 'higher' and 'lower' list have at least one element, now
279
 
        there are two hash buckets instead of one.
280
 
      */
281
 
      keyinfo->hash_buckets++;
282
 
    }
283
 
 
284
 
    if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
285
 
    {
286
 
      gpos->ptr_to_rec=ptr_to_rec;
287
 
      gpos->next_key=0;
288
 
    }
289
 
    if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
290
 
    {
291
 
      gpos2->ptr_to_rec=ptr_to_rec2;
292
 
      gpos2->next_key=0;
293
 
    }
294
 
  }
295
 
  /* Check if we are at the empty position */
296
 
 
297
 
  pos=hp_find_hash(&keyinfo->block, hp_mask(hp_rec_hashnr(keyinfo, record),
298
 
                                         share->blength, share->records + 1));
299
 
  if (pos == empty)
300
 
  {
301
 
    pos->ptr_to_rec=recpos;
302
 
    pos->next_key=0;
303
 
    keyinfo->hash_buckets++;
304
 
  }
305
 
  else
306
 
  {
307
 
    /* Check if more records in same hash-nr family */
308
 
    empty[0]=pos[0];
309
 
    gpos=hp_find_hash(&keyinfo->block,
310
 
                      hp_mask(hp_rec_hashnr(keyinfo, pos->ptr_to_rec),
311
 
                              share->blength, share->records + 1));
312
 
    if (pos == gpos)
313
 
    {
314
 
      pos->ptr_to_rec=recpos;
315
 
      pos->next_key=empty;
316
 
    }
317
 
    else
318
 
    {
319
 
      keyinfo->hash_buckets++;
320
 
      pos->ptr_to_rec=recpos;
321
 
      pos->next_key=0;
322
 
      hp_movelink(pos, gpos, empty);
323
 
    }
324
 
 
325
 
    /* Check if duplicated keys */
326
 
    if ((keyinfo->flag & HA_NOSAME) && pos == gpos &&
327
 
        (!(keyinfo->flag & HA_NULL_PART_KEY) ||
328
 
         !hp_if_null_in_key(keyinfo, record)))
329
 
    {
330
 
      pos=empty;
331
 
      do
332
 
      {
333
 
        if (! hp_rec_key_cmp(keyinfo, record, pos->ptr_to_rec, 1))
334
 
        {
335
 
          return(errno=HA_ERR_FOUND_DUPP_KEY);
336
 
        }
337
 
      } while ((pos=pos->next_key));
338
 
    }
339
 
  }
340
 
  return(0);
341
 
}
342
 
 
343
 
        /* Returns ptr to block, and allocates block if neaded */
344
 
 
345
 
static HASH_INFO *hp_find_free_hash(HP_SHARE *info,
346
 
                                     HP_BLOCK *block, uint32_t records)
347
 
{
348
 
  uint32_t block_pos;
349
 
  size_t length;
350
 
 
351
 
  if (records < block->last_allocated)
352
 
    return hp_find_hash(block,records);
353
 
  if (!(block_pos=(records % block->records_in_block)))
354
 
  {
355
 
    if (hp_get_new_block(block,&length))
356
 
      return(NULL);
357
 
    info->index_length+=length;
358
 
  }
359
 
  block->last_allocated=records+1;
360
 
  return((HASH_INFO*) ((unsigned char*) block->level_info[0].last_blocks+
361
 
                       block_pos*block->recbuffer));
362
 
}