~drizzle-trunk/drizzle/development

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