~drizzle-trunk/drizzle/development

1 by brian
clean slate
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
/* Write a row to a MyISAM table */
17
76 by Brian Aker
Next pass on fulltext.
18
#include "myisamdef.h"
492.1.7 by Monty Taylor
Moved test() to its own file.
19
#include <drizzled/util/test.h>
20
1 by brian
clean slate
21
22
#define MAX_POINTER_LENGTH 8
23
24
	/* Functions declared in this file */
25
26
static int w_search(MI_INFO *info,MI_KEYDEF *keyinfo,
482 by Brian Aker
Remove uint.
27
		    uint32_t comp_flag, unsigned char *key,
28
		    uint32_t key_length, my_off_t pos, unsigned char *father_buff,
481 by Brian Aker
Remove all of uchar.
29
		    unsigned char *father_keypos, my_off_t father_page,
281 by Brian Aker
Converted myisam away from my_bool
30
		    bool insert_last);
481 by Brian Aker
Remove all of uchar.
31
static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,unsigned char *key,
32
			    unsigned char *curr_buff,unsigned char *father_buff,
33
			    unsigned char *father_keypos,my_off_t father_page);
34
static unsigned char *_mi_find_last_pos(MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
35
				unsigned char *key, uint32_t *return_key_length,
481 by Brian Aker
Remove all of uchar.
36
				unsigned char **after_key);
482 by Brian Aker
Remove uint.
37
int _mi_ck_write_tree(register MI_INFO *info, uint32_t keynr,unsigned char *key,
38
		      uint32_t key_length);
39
int _mi_ck_write_btree(register MI_INFO *info, uint32_t keynr,unsigned char *key,
40
		       uint32_t key_length);
1 by brian
clean slate
41
42
	/* Write new record to database */
43
481 by Brian Aker
Remove all of uchar.
44
int mi_write(MI_INFO *info, unsigned char *record)
1 by brian
clean slate
45
{
46
  MYISAM_SHARE *share=info->s;
482 by Brian Aker
Remove uint.
47
  uint32_t i;
1 by brian
clean slate
48
  int save_errno;
49
  my_off_t filepos;
481 by Brian Aker
Remove all of uchar.
50
  unsigned char *buff;
281 by Brian Aker
Converted myisam away from my_bool
51
  bool lock_tree= share->concurrent_insert;
1 by brian
clean slate
52
53
  if (share->options & HA_OPTION_READ_ONLY_DATA)
54
  {
51.1.115 by Jay Pipes
DBUG symbol removal
55
    return(my_errno=EACCES);
1 by brian
clean slate
56
  }
57
  if (_mi_readinfo(info,F_WRLCK,1))
51.1.115 by Jay Pipes
DBUG symbol removal
58
    return(my_errno);
1 by brian
clean slate
59
  filepos= ((share->state.dellink != HA_OFFSET_ERROR &&
60
             !info->append_insert_at_end) ?
61
	    share->state.dellink :
62
	    info->state->data_file_length);
63
64
  if (share->base.reloc == (ha_rows) 1 &&
65
      share->base.records == (ha_rows) 1 &&
66
      info->state->records == (ha_rows) 1)
67
  {						/* System file */
68
    my_errno=HA_ERR_RECORD_FILE_FULL;
69
    goto err2;
70
  }
71
  if (info->state->key_file_length >= share->base.margin_key_file_length)
72
  {
73
    my_errno=HA_ERR_INDEX_FILE_FULL;
74
    goto err2;
75
  }
76
  if (_mi_mark_file_changed(info))
77
    goto err2;
78
79
  /* Calculate and check all unique constraints */
80
  for (i=0 ; i < share->state.header.uniques ; i++)
81
  {
82
    if (mi_check_unique(info,share->uniqueinfo+i,record,
83
		     mi_unique_hash(share->uniqueinfo+i,record),
84
		     HA_OFFSET_ERROR))
85
      goto err2;
86
  }
87
88
	/* Write all keys to indextree */
89
90
  buff=info->lastkey2;
91
  for (i=0 ; i < share->base.keys ; i++)
92
  {
93
    if (mi_is_key_active(share->state.key_map, i))
94
    {
281 by Brian Aker
Converted myisam away from my_bool
95
      bool local_lock_tree= (lock_tree &&
1 by brian
clean slate
96
                                !(info->bulk_insert &&
97
                                  is_tree_inited(&info->bulk_insert[i])));
98
      if (local_lock_tree)
99
      {
100
	rw_wrlock(&share->key_root_lock[i]);
101
	share->keyinfo[i].version++;
102
      }
103
      {
104
        if (share->keyinfo[i].ck_insert(info,i,buff,
105
			_mi_make_key(info,i,buff,record,filepos)))
106
        {
107
          if (local_lock_tree)
108
            rw_unlock(&share->key_root_lock[i]);
109
          goto err;
110
        }
111
      }
112
113
      /* The above changed info->lastkey2. Inform mi_rnext_same(). */
114
      info->update&= ~HA_STATE_RNEXT_SAME;
115
116
      if (local_lock_tree)
117
        rw_unlock(&share->key_root_lock[i]);
118
    }
119
  }
120
  if (share->calc_checksum)
121
    info->checksum=(*share->calc_checksum)(info,record);
122
  if (!(info->opt_flag & OPT_NO_ROWS))
123
  {
124
    if ((*share->write_record)(info,record))
125
      goto err;
126
    info->state->checksum+=info->checksum;
127
  }
128
  if (share->base.auto_key)
129
    set_if_bigger(info->s->state.auto_increment,
130
                  retrieve_auto_increment(info, record));
131
  info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
132
		 HA_STATE_ROW_CHANGED);
133
  info->state->records++;
134
  info->lastpos=filepos;
398.1.10 by Monty Taylor
Actually removed VOID() this time.
135
  _mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE);
1 by brian
clean slate
136
  if (info->invalidator != 0)
137
  {
138
    (*info->invalidator)(info->filename);
139
    info->invalidator=0;
140
  }
141
142
  /*
143
    Update status of the table. We need to do so after each row write
144
    for the log tables, as we want the new row to become visible to
145
    other threads as soon as possible. We don't lock mutex here
146
    (as it is required by pthread memory visibility rules) as (1) it's
147
    not critical to use outdated share->is_log_table value (2) locking
148
    mutex here for every write is too expensive.
149
  */
150
  if (share->is_log_table)
151
    mi_update_status((void*) info);
152
51.1.115 by Jay Pipes
DBUG symbol removal
153
  return(0);
1 by brian
clean slate
154
155
err:
156
  save_errno=my_errno;
157
  if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL ||
158
      my_errno == HA_ERR_NULL_IN_SPATIAL || my_errno == HA_ERR_OUT_OF_MEM)
159
  {
160
    if (info->bulk_insert)
161
    {
482 by Brian Aker
Remove uint.
162
      uint32_t j;
1 by brian
clean slate
163
      for (j=0 ; j < share->base.keys ; j++)
164
        mi_flush_bulk_insert(info, j);
165
    }
166
    info->errkey= (int) i;
167
    while ( i-- > 0)
168
    {
169
      if (mi_is_key_active(share->state.key_map, i))
170
      {
281 by Brian Aker
Converted myisam away from my_bool
171
	bool local_lock_tree= (lock_tree &&
1 by brian
clean slate
172
                                  !(info->bulk_insert &&
173
                                    is_tree_inited(&info->bulk_insert[i])));
174
	if (local_lock_tree)
175
	  rw_wrlock(&share->key_root_lock[i]);
176
	{
482 by Brian Aker
Remove uint.
177
	  uint32_t key_length=_mi_make_key(info,i,buff,record,filepos);
1 by brian
clean slate
178
	  if (_mi_ck_delete(info,i,buff,key_length))
179
	  {
180
	    if (local_lock_tree)
181
	      rw_unlock(&share->key_root_lock[i]);
182
	    break;
183
	  }
184
	}
185
	if (local_lock_tree)
186
	  rw_unlock(&share->key_root_lock[i]);
187
      }
188
    }
189
  }
190
  else
191
  {
192
    mi_print_error(info->s, HA_ERR_CRASHED);
193
    mi_mark_crashed(info);
194
  }
195
  info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
196
  my_errno=save_errno;
197
err2:
198
  save_errno=my_errno;
398.1.10 by Monty Taylor
Actually removed VOID() this time.
199
  _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
51.1.115 by Jay Pipes
DBUG symbol removal
200
  return(my_errno=save_errno);
1 by brian
clean slate
201
} /* mi_write */
202
203
204
	/* Write one key to btree */
205
482 by Brian Aker
Remove uint.
206
int _mi_ck_write(MI_INFO *info, uint32_t keynr, unsigned char *key, uint32_t key_length)
1 by brian
clean slate
207
{
208
  if (info->bulk_insert && is_tree_inited(&info->bulk_insert[keynr]))
209
  {
51.1.115 by Jay Pipes
DBUG symbol removal
210
    return(_mi_ck_write_tree(info, keynr, key, key_length));
1 by brian
clean slate
211
  }
212
  else
213
  {
51.1.115 by Jay Pipes
DBUG symbol removal
214
    return(_mi_ck_write_btree(info, keynr, key, key_length));
1 by brian
clean slate
215
  }
216
} /* _mi_ck_write */
217
218
219
/**********************************************************************
220
 *                Normal insert code                                  *
221
 **********************************************************************/
222
482 by Brian Aker
Remove uint.
223
int _mi_ck_write_btree(register MI_INFO *info, uint32_t keynr, unsigned char *key,
224
		       uint32_t key_length)
1 by brian
clean slate
225
{
482 by Brian Aker
Remove uint.
226
  uint32_t error;
227
  uint32_t comp_flag;
1 by brian
clean slate
228
  MI_KEYDEF *keyinfo=info->s->keyinfo+keynr;
229
  my_off_t  *root=&info->s->state.key_root[keynr];
230
231
  if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
232
    comp_flag=SEARCH_BIGGER;			/* Put after same key */
75 by Brian Aker
Another round of cleanup of MyISAM
233
  else if (keyinfo->flag & (HA_NOSAME))
1 by brian
clean slate
234
  {
235
    comp_flag=SEARCH_FIND | SEARCH_UPDATE;	/* No duplicates */
236
    if (keyinfo->flag & HA_NULL_ARE_EQUAL)
237
      comp_flag|= SEARCH_NULL_ARE_EQUAL;
238
  }
239
  else
240
    comp_flag=SEARCH_SAME;			/* Keys in rec-pos order */
241
242
  error=_mi_ck_real_write_btree(info, keyinfo, key, key_length,
243
                                root, comp_flag);
51.1.115 by Jay Pipes
DBUG symbol removal
244
  return(error);
1 by brian
clean slate
245
} /* _mi_ck_write_btree */
246
247
int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
482 by Brian Aker
Remove uint.
248
    unsigned char *key, uint32_t key_length, my_off_t *root, uint32_t comp_flag)
1 by brian
clean slate
249
{
250
  int error;
251
  /* key_length parameter is used only if comp_flag is SEARCH_FIND */
252
  if (*root == HA_OFFSET_ERROR ||
253
      (error=w_search(info, keyinfo, comp_flag, key, key_length,
481 by Brian Aker
Remove all of uchar.
254
		      *root, (unsigned char *) 0, (unsigned char*) 0,
1 by brian
clean slate
255
		      (my_off_t) 0, 1)) > 0)
256
    error=_mi_enlarge_root(info,keyinfo,key,root);
51.1.115 by Jay Pipes
DBUG symbol removal
257
  return(error);
1 by brian
clean slate
258
} /* _mi_ck_real_write_btree */
259
260
261
	/* Make a new root with key as only pointer */
262
481 by Brian Aker
Remove all of uchar.
263
int _mi_enlarge_root(MI_INFO *info, MI_KEYDEF *keyinfo, unsigned char *key,
1 by brian
clean slate
264
                     my_off_t *root)
265
{
482 by Brian Aker
Remove uint.
266
  uint32_t t_length,nod_flag;
1 by brian
clean slate
267
  MI_KEY_PARAM s_temp;
268
  MYISAM_SHARE *share=info->s;
269
270
  nod_flag= (*root != HA_OFFSET_ERROR) ?  share->base.key_reflength : 0;
271
  _mi_kpointer(info,info->buff+2,*root); /* if nod */
481 by Brian Aker
Remove all of uchar.
272
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(unsigned char*) 0,
273
				(unsigned char*) 0, (unsigned char*) 0, key,&s_temp);
1 by brian
clean slate
274
  mi_putint(info->buff,t_length+2+nod_flag,nod_flag);
275
  (*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp);
276
  info->buff_used=info->page_changed=1;		/* info->buff is used */
277
  if ((*root= _mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR ||
278
      _mi_write_keypage(info,keyinfo,*root,DFLT_INIT_HITS,info->buff))
51.1.115 by Jay Pipes
DBUG symbol removal
279
    return(-1);
280
  return(0);
1 by brian
clean slate
281
} /* _mi_enlarge_root */
282
283
284
	/*
285
	  Search after a position for a key and store it there
286
	  Returns -1 = error
287
		   0  = ok
288
		   1  = key should be stored in higher tree
289
	*/
290
291
static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
482 by Brian Aker
Remove uint.
292
		    uint32_t comp_flag, unsigned char *key, uint32_t key_length, my_off_t page,
481 by Brian Aker
Remove all of uchar.
293
		    unsigned char *father_buff, unsigned char *father_keypos,
281 by Brian Aker
Converted myisam away from my_bool
294
		    my_off_t father_page, bool insert_last)
1 by brian
clean slate
295
{
296
  int error,flag;
482 by Brian Aker
Remove uint.
297
  uint32_t nod_flag, search_key_length;
481 by Brian Aker
Remove all of uchar.
298
  unsigned char *temp_buff,*keypos;
299
  unsigned char keybuff[MI_MAX_KEY_BUFF];
281 by Brian Aker
Converted myisam away from my_bool
300
  bool was_last_key;
1 by brian
clean slate
301
  my_off_t next_page, dupp_key_pos;
302
303
  search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
481 by Brian Aker
Remove all of uchar.
304
  if (!(temp_buff= (unsigned char*) my_alloca((uint) keyinfo->block_length+
1 by brian
clean slate
305
				      MI_MAX_KEY_BUFF*2)))
51.1.115 by Jay Pipes
DBUG symbol removal
306
    return(-1);
1 by brian
clean slate
307
  if (!_mi_fetch_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff,0))
308
    goto err;
309
310
  flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,search_key_length,
311
			      comp_flag, &keypos, keybuff, &was_last_key);
312
  nod_flag=mi_test_if_nod(temp_buff);
313
  if (flag == 0)
314
  {
482 by Brian Aker
Remove uint.
315
    uint32_t tmp_key_length;
1 by brian
clean slate
316
	/* get position to record with duplicated key */
317
    tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff);
318
    if (tmp_key_length)
319
      dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length);
320
    else
321
      dupp_key_pos= HA_OFFSET_ERROR;
322
323
    {
324
      info->dupp_key_pos= dupp_key_pos;
481 by Brian Aker
Remove all of uchar.
325
      my_afree((unsigned char*) temp_buff);
1 by brian
clean slate
326
      my_errno=HA_ERR_FOUND_DUPP_KEY;
51.1.115 by Jay Pipes
DBUG symbol removal
327
      return(-1);
1 by brian
clean slate
328
    }
329
  }
330
  if (flag == MI_FOUND_WRONG_KEY)
51.1.115 by Jay Pipes
DBUG symbol removal
331
    return(-1);
1 by brian
clean slate
332
  if (!was_last_key)
333
    insert_last=0;
334
  next_page=_mi_kpos(nod_flag,keypos);
335
  if (next_page == HA_OFFSET_ERROR ||
336
      (error=w_search(info, keyinfo, comp_flag, key, key_length, next_page,
337
		      temp_buff, keypos, page, insert_last)) >0)
338
  {
339
    error=_mi_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
340
		     father_keypos,father_page, insert_last);
341
    if (_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff))
342
      goto err;
343
  }
481 by Brian Aker
Remove all of uchar.
344
  my_afree((unsigned char*) temp_buff);
51.1.115 by Jay Pipes
DBUG symbol removal
345
  return(error);
1 by brian
clean slate
346
err:
481 by Brian Aker
Remove all of uchar.
347
  my_afree((unsigned char*) temp_buff);
51.1.115 by Jay Pipes
DBUG symbol removal
348
  return (-1);
1 by brian
clean slate
349
} /* w_search */
350
351
352
/*
353
  Insert new key.
354
355
  SYNOPSIS
356
    _mi_insert()
357
    info                        Open table information.
358
    keyinfo                     Key definition information.
359
    key                         New key.
360
    anc_buff                    Key page (beginning).
361
    key_pos                     Position in key page where to insert.
362
    key_buff                    Copy of previous key.
363
    father_buff                 parent key page for balancing.
364
    father_key_pos              position in parent key page for balancing.
365
    father_page                 position of parent key page in file.
366
    insert_last                 If to append at end of page.
367
368
  DESCRIPTION
369
    Insert new key at right of key_pos.
370
371
  RETURN
372
    2           if key contains key to upper level.
373
    0           OK.
374
    < 0         Error.
375
*/
376
377
int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
481 by Brian Aker
Remove all of uchar.
378
	       unsigned char *key, unsigned char *anc_buff, unsigned char *key_pos, unsigned char *key_buff,
379
               unsigned char *father_buff, unsigned char *father_key_pos, my_off_t father_page,
281 by Brian Aker
Converted myisam away from my_bool
380
	       bool insert_last)
1 by brian
clean slate
381
{
482 by Brian Aker
Remove uint.
382
  uint32_t a_length,nod_flag;
1 by brian
clean slate
383
  int t_length;
481 by Brian Aker
Remove all of uchar.
384
  unsigned char *endpos, *prev_key;
1 by brian
clean slate
385
  MI_KEY_PARAM s_temp;
386
387
  nod_flag=mi_test_if_nod(anc_buff);
388
  a_length=mi_getint(anc_buff);
389
  endpos= anc_buff+ a_length;
481 by Brian Aker
Remove all of uchar.
390
  prev_key=(key_pos == anc_buff+2+nod_flag ? (unsigned char*) 0 : key_buff);
1 by brian
clean slate
391
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
481 by Brian Aker
Remove all of uchar.
392
				(key_pos == endpos ? (unsigned char*) 0 : key_pos),
1 by brian
clean slate
393
				prev_key, prev_key,
394
				key,&s_temp);
51.1.115 by Jay Pipes
DBUG symbol removal
395
1 by brian
clean slate
396
  if (t_length > 0)
397
  {
398
    if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
399
    {
400
      mi_print_error(info->s, HA_ERR_CRASHED);
401
      my_errno=HA_ERR_CRASHED;
51.1.115 by Jay Pipes
DBUG symbol removal
402
      return(-1);
1 by brian
clean slate
403
    }
481 by Brian Aker
Remove all of uchar.
404
    bmove_upp((unsigned char*) endpos+t_length,(unsigned char*) endpos,(uint) (endpos-key_pos));
1 by brian
clean slate
405
  }
406
  else
407
  {
408
    if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
409
    {
410
      mi_print_error(info->s, HA_ERR_CRASHED);
411
      my_errno=HA_ERR_CRASHED;
51.1.115 by Jay Pipes
DBUG symbol removal
412
      return(-1);
1 by brian
clean slate
413
    }
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
414
    memcpy(key_pos, key_pos - t_length, endpos - key_pos + t_length);
1 by brian
clean slate
415
  }
416
  (*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
417
  a_length+=t_length;
418
  mi_putint(anc_buff,a_length,nod_flag);
419
  if (a_length <= keyinfo->block_length)
420
  {
51.1.115 by Jay Pipes
DBUG symbol removal
421
    return(0);				/* There is room on page */
1 by brian
clean slate
422
  }
423
  /* Page is full */
424
  if (nod_flag)
425
    insert_last=0;
426
  if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
427
      father_buff && !insert_last)
51.1.115 by Jay Pipes
DBUG symbol removal
428
    return(_mi_balance_page(info,keyinfo,key,anc_buff,father_buff,
1 by brian
clean slate
429
				 father_key_pos,father_page));
51.1.115 by Jay Pipes
DBUG symbol removal
430
  return(_mi_split_page(info,keyinfo,key,anc_buff,key_buff, insert_last));
1 by brian
clean slate
431
} /* _mi_insert */
432
433
434
	/* split a full page in two and assign emerging item to key */
435
436
int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo,
481 by Brian Aker
Remove all of uchar.
437
		   unsigned char *key, unsigned char *buff, unsigned char *key_buff,
281 by Brian Aker
Converted myisam away from my_bool
438
		   bool insert_last_key)
1 by brian
clean slate
439
{
482 by Brian Aker
Remove uint.
440
  uint32_t length,a_length,key_ref_length,t_length,nod_flag,key_length;
481 by Brian Aker
Remove all of uchar.
441
  unsigned char *key_pos,*pos, *after_key= NULL;
1 by brian
clean slate
442
  my_off_t new_pos;
443
  MI_KEY_PARAM s_temp;
444
445
  if (info->s->keyinfo+info->lastinx == keyinfo)
446
    info->page_changed=1;			/* Info->buff is used */
447
  info->buff_used=1;
448
  nod_flag=mi_test_if_nod(buff);
449
  key_ref_length=2+nod_flag;
450
  if (insert_last_key)
451
    key_pos=_mi_find_last_pos(keyinfo,buff,key_buff, &key_length, &after_key);
452
  else
453
    key_pos=_mi_find_half_pos(nod_flag,keyinfo,buff,key_buff, &key_length,
454
			      &after_key);
455
  if (!key_pos)
51.1.115 by Jay Pipes
DBUG symbol removal
456
    return(-1);
1 by brian
clean slate
457
458
  length=(uint) (key_pos-buff);
459
  a_length=mi_getint(buff);
460
  mi_putint(buff,length,nod_flag);
461
462
  key_pos=after_key;
463
  if (nod_flag)
464
  {
465
    pos=key_pos-nod_flag;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
466
    memcpy(info->buff + 2, pos, nod_flag);
1 by brian
clean slate
467
  }
468
469
	/* Move middle item to key and pointer to new page */
470
  if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
51.1.115 by Jay Pipes
DBUG symbol removal
471
    return(-1);
1 by brian
clean slate
472
  _mi_kpointer(info,_mi_move_key(keyinfo,key,key_buff),new_pos);
473
474
	/* Store new page */
475
  if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff))
51.1.115 by Jay Pipes
DBUG symbol removal
476
    return(-1);
1 by brian
clean slate
477
481 by Brian Aker
Remove all of uchar.
478
  t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(unsigned char *) 0,
479
				(unsigned char*) 0, (unsigned char*) 0,
1 by brian
clean slate
480
				key_buff, &s_temp);
481
  length=(uint) ((buff+a_length)-key_pos);
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
482
  memcpy(info->buff+key_ref_length+t_length, key_pos, length);
1 by brian
clean slate
483
  (*keyinfo->store_key)(keyinfo,info->buff+key_ref_length,&s_temp);
484
  mi_putint(info->buff,length+t_length+key_ref_length,nod_flag);
485
486
  if (_mi_write_keypage(info,keyinfo,new_pos,DFLT_INIT_HITS,info->buff))
51.1.115 by Jay Pipes
DBUG symbol removal
487
    return(-1);
488
  return(2);				/* Middle key up */
1 by brian
clean slate
489
} /* _mi_split_page */
490
491
492
	/*
493
	  Calculate how to much to move to split a page in two
494
	  Returns pointer to start of key.
495
	  key will contain the key.
496
	  return_key_length will contain the length of key
497
	  after_key will contain the position to where the next key starts
498
	*/
499
482 by Brian Aker
Remove uint.
500
unsigned char *_mi_find_half_pos(uint32_t nod_flag, MI_KEYDEF *keyinfo, unsigned char *page,
501
			 unsigned char *key, uint32_t *return_key_length,
481 by Brian Aker
Remove all of uchar.
502
			 unsigned char **after_key)
1 by brian
clean slate
503
{
482 by Brian Aker
Remove uint.
504
  uint32_t keys,length,key_ref_length;
481 by Brian Aker
Remove all of uchar.
505
  unsigned char *end,*lastpos;
1 by brian
clean slate
506
507
  key_ref_length=2+nod_flag;
508
  length=mi_getint(page)-key_ref_length;
509
  page+=key_ref_length;
510
  if (!(keyinfo->flag &
511
	(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
512
	 HA_BINARY_PACK_KEY)))
513
  {
514
    key_ref_length=keyinfo->keylength+nod_flag;
515
    keys=length/(key_ref_length*2);
516
    *return_key_length=keyinfo->keylength;
517
    end=page+keys*key_ref_length;
518
    *after_key=end+key_ref_length;
519
    memcpy(key,end,key_ref_length);
51.1.115 by Jay Pipes
DBUG symbol removal
520
    return(end);
1 by brian
clean slate
521
  }
522
523
  end=page+length/2-key_ref_length;		/* This is aprox. half */
524
  *key='\0';
525
  do
526
  {
527
    lastpos=page;
528
    if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key)))
51.1.115 by Jay Pipes
DBUG symbol removal
529
      return(0);
1 by brian
clean slate
530
  } while (page < end);
531
  *return_key_length=length;
532
  *after_key=page;
51.1.115 by Jay Pipes
DBUG symbol removal
533
  return(lastpos);
1 by brian
clean slate
534
} /* _mi_find_half_pos */
535
536
537
	/*
538
	  Split buffer at last key
539
	  Returns pointer to the start of the key before the last key
540
	  key will contain the last key
541
	*/
542
481 by Brian Aker
Remove all of uchar.
543
static unsigned char *_mi_find_last_pos(MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
544
				unsigned char *key, uint32_t *return_key_length,
481 by Brian Aker
Remove all of uchar.
545
				unsigned char **after_key)
1 by brian
clean slate
546
{
482 by Brian Aker
Remove uint.
547
  uint32_t keys;
548
  uint32_t length;
549
  uint32_t last_length= 0;
550
  uint32_t key_ref_length;
481 by Brian Aker
Remove all of uchar.
551
  unsigned char *end, *lastpos, *prevpos= NULL;
552
  unsigned char key_buff[MI_MAX_KEY_BUFF];
1 by brian
clean slate
553
554
  key_ref_length=2;
555
  length=mi_getint(page)-key_ref_length;
556
  page+=key_ref_length;
557
  if (!(keyinfo->flag &
558
	(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
559
	 HA_BINARY_PACK_KEY)))
560
  {
561
    keys=length/keyinfo->keylength-2;
562
    *return_key_length=length=keyinfo->keylength;
563
    end=page+keys*length;
564
    *after_key=end+length;
565
    memcpy(key,end,length);
51.1.115 by Jay Pipes
DBUG symbol removal
566
    return(end);
1 by brian
clean slate
567
  }
568
569
  end= page + length - key_ref_length;
570
  *key='\0';
571
  length=0;
572
  lastpos=page;
573
  while (page < end)
574
  {
575
    prevpos=lastpos; lastpos=page;
576
    last_length=length;
577
    memcpy(key, key_buff, length);		/* previous key */
578
    if (!(length=(*keyinfo->get_key)(keyinfo,0,&page,key_buff)))
579
    {
580
      mi_print_error(keyinfo->share, HA_ERR_CRASHED);
581
      my_errno=HA_ERR_CRASHED;
51.1.115 by Jay Pipes
DBUG symbol removal
582
      return(0);
1 by brian
clean slate
583
    }
584
  }
585
  *return_key_length=last_length;
586
  *after_key=lastpos;
51.1.115 by Jay Pipes
DBUG symbol removal
587
  return(prevpos);
1 by brian
clean slate
588
} /* _mi_find_last_pos */
589
590
591
	/* Balance page with not packed keys with page on right/left */
592
	/* returns 0 if balance was done */
593
594
static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo,
481 by Brian Aker
Remove all of uchar.
595
			    unsigned char *key, unsigned char *curr_buff, unsigned char *father_buff,
596
			    unsigned char *father_key_pos, my_off_t father_page)
1 by brian
clean slate
597
{
281 by Brian Aker
Converted myisam away from my_bool
598
  bool right;
482 by Brian Aker
Remove uint.
599
  uint32_t k_length,father_length,father_keylength,nod_flag,curr_keylength,
1 by brian
clean slate
600
       right_length,left_length,new_right_length,new_left_length,extra_length,
601
       length,keys;
481 by Brian Aker
Remove all of uchar.
602
  unsigned char *pos,*buff,*extra_buff;
1 by brian
clean slate
603
  my_off_t next_page,new_pos;
481 by Brian Aker
Remove all of uchar.
604
  unsigned char tmp_part_key[MI_MAX_KEY_BUFF];
1 by brian
clean slate
605
606
  k_length=keyinfo->keylength;
607
  father_length=mi_getint(father_buff);
608
  father_keylength=k_length+info->s->base.key_reflength;
609
  nod_flag=mi_test_if_nod(curr_buff);
610
  curr_keylength=k_length+nod_flag;
611
  info->page_changed=1;
612
613
  if ((father_key_pos != father_buff+father_length &&
614
       (info->state->records & 1)) ||
615
      father_key_pos == father_buff+2+info->s->base.key_reflength)
616
  {
617
    right=1;
618
    next_page= _mi_kpos(info->s->base.key_reflength,
619
			father_key_pos+father_keylength);
620
    buff=info->buff;
621
  }
622
  else
623
  {
624
    right=0;
625
    father_key_pos-=father_keylength;
626
    next_page= _mi_kpos(info->s->base.key_reflength,father_key_pos);
627
					/* Fix that curr_buff is to left */
628
    buff=curr_buff; curr_buff=info->buff;
629
  }					/* father_key_pos ptr to parting key */
630
631
  if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff,0))
632
    goto err;
633
634
	/* Test if there is room to share keys */
635
636
  left_length=mi_getint(curr_buff);
637
  right_length=mi_getint(buff);
638
  keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;
639
640
  if ((right ? right_length : left_length) + curr_keylength <=
641
      keyinfo->block_length)
642
  {						/* Merge buffs */
643
    new_left_length=2+nod_flag+(keys/2)*curr_keylength;
644
    new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
645
    mi_putint(curr_buff,new_left_length,nod_flag);
646
    mi_putint(buff,new_right_length,nod_flag);
647
648
    if (left_length < new_left_length)
649
    {						/* Move keys buff -> leaf */
650
      pos=curr_buff+left_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
651
      memcpy(pos, father_key_pos, k_length);
652
      length= new_left_length - left_length - k_length;
653
      memcpy(pos+k_length, buff+2, length);
1 by brian
clean slate
654
      pos=buff+2+length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
655
      memcpy(father_key_pos, pos, k_length);
656
      memcpy(buff+2, pos+k_length, new_right_length);
1 by brian
clean slate
657
    }
658
    else
659
    {						/* Move keys -> buff */
660
481 by Brian Aker
Remove all of uchar.
661
      bmove_upp((unsigned char*) buff+new_right_length,(unsigned char*) buff+right_length,
1 by brian
clean slate
662
		right_length-2);
663
      length=new_right_length-right_length-k_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
664
      memcpy(buff+2+length,father_key_pos, k_length);
1 by brian
clean slate
665
      pos=curr_buff+new_left_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
666
      memcpy(father_key_pos, pos, k_length);
667
      memcpy(buff+2, pos+k_length, length);
1 by brian
clean slate
668
    }
669
670
    if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff) ||
671
	_mi_write_keypage(info,keyinfo,father_page,DFLT_INIT_HITS,father_buff))
672
      goto err;
51.1.115 by Jay Pipes
DBUG symbol removal
673
    return(0);
1 by brian
clean slate
674
  }
675
676
	/* curr_buff[] and buff[] are full, lets split and make new nod */
677
678
  extra_buff=info->buff+info->s->base.max_key_block_length;
679
  new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
680
  if (keys == 5)				/* Too few keys to balance */
681
    new_left_length-=curr_keylength;
682
  extra_length=nod_flag+left_length+right_length-
683
    new_left_length-new_right_length-curr_keylength;
684
  mi_putint(curr_buff,new_left_length,nod_flag);
685
  mi_putint(buff,new_right_length,nod_flag);
686
  mi_putint(extra_buff,extra_length+2,nod_flag);
687
688
  /* move first largest keys to new page  */
689
  pos=buff+right_length-extra_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
690
  memcpy(extra_buff+2, pos, extra_length);
1 by brian
clean slate
691
  /* Save new parting key */
692
  memcpy(tmp_part_key, pos-k_length,k_length);
693
  /* Make place for new keys */
481 by Brian Aker
Remove all of uchar.
694
  bmove_upp((unsigned char*) buff+new_right_length,(unsigned char*) pos-k_length,
1 by brian
clean slate
695
	    right_length-extra_length-k_length-2);
696
  /* Copy keys from left page */
697
  pos= curr_buff+new_left_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
698
  length= left_length - new_left_length - k_length;
699
  memcpy(buff+2, pos+k_length, length);
1 by brian
clean slate
700
  /* Copy old parting key */
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
701
  memcpy(buff+2+length, father_key_pos, k_length);
1 by brian
clean slate
702
703
  /* Move new parting keys up to caller */
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
704
  memcpy((right ? key : father_key_pos), pos, k_length);
705
  memcpy((right ? father_key_pos : key), tmp_part_key, k_length);
1 by brian
clean slate
706
707
  if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
708
    goto err;
709
  _mi_kpointer(info,key+k_length,new_pos);
710
  if (_mi_write_keypage(info,keyinfo,(right ? new_pos : next_page),
711
			DFLT_INIT_HITS,info->buff) ||
712
      _mi_write_keypage(info,keyinfo,(right ? next_page : new_pos),
713
                        DFLT_INIT_HITS,extra_buff))
714
    goto err;
715
51.1.115 by Jay Pipes
DBUG symbol removal
716
  return(1);				/* Middle key up */
1 by brian
clean slate
717
718
err:
51.1.115 by Jay Pipes
DBUG symbol removal
719
  return(-1);
1 by brian
clean slate
720
} /* _mi_balance_page */
721
722
/**********************************************************************
723
 *                Bulk insert code                                    *
724
 **********************************************************************/
725
726
typedef struct {
727
  MI_INFO *info;
482 by Brian Aker
Remove uint.
728
  uint32_t keynr;
1 by brian
clean slate
729
} bulk_insert_param;
730
482 by Brian Aker
Remove uint.
731
int _mi_ck_write_tree(register MI_INFO *info, uint32_t keynr, unsigned char *key,
732
		      uint32_t key_length)
1 by brian
clean slate
733
{
734
  int error;
735
736
  error= tree_insert(&info->bulk_insert[keynr], key,
737
         key_length + info->s->rec_reflength,
738
         info->bulk_insert[keynr].custom_arg) ? 0 : HA_ERR_OUT_OF_MEM ;
739
51.1.115 by Jay Pipes
DBUG symbol removal
740
  return(error);
1 by brian
clean slate
741
} /* _mi_ck_write_tree */
742
743
744
/* typeof(_mi_keys_compare)=qsort_cmp2 */
745
481 by Brian Aker
Remove all of uchar.
746
static int keys_compare(bulk_insert_param *param, unsigned char *key1, unsigned char *key2)
1 by brian
clean slate
747
{
482 by Brian Aker
Remove uint.
748
  uint32_t not_used[2];
1 by brian
clean slate
749
  return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
750
                    key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
751
                    not_used);
752
}
753
754
481 by Brian Aker
Remove all of uchar.
755
static int keys_free(unsigned char *key, TREE_FREE mode, bulk_insert_param *param)
1 by brian
clean slate
756
{
757
  /*
758
    Probably I can use info->lastkey here, but I'm not sure,
759
    and to be safe I'd better use local lastkey.
760
  */
481 by Brian Aker
Remove all of uchar.
761
  unsigned char lastkey[MI_MAX_KEY_BUFF];
482 by Brian Aker
Remove uint.
762
  uint32_t keylen;
1 by brian
clean slate
763
  MI_KEYDEF *keyinfo;
764
765
  switch (mode) {
766
  case free_init:
767
    if (param->info->s->concurrent_insert)
768
    {
769
      rw_wrlock(&param->info->s->key_root_lock[param->keynr]);
770
      param->info->s->keyinfo[param->keynr].version++;
771
    }
772
    return 0;
773
  case free_free:
774
    keyinfo=param->info->s->keyinfo+param->keynr;
775
    keylen=_mi_keylength(keyinfo, key);
776
    memcpy(lastkey, key, keylen);
777
    return _mi_ck_write_btree(param->info,param->keynr,lastkey,
778
			      keylen - param->info->s->rec_reflength);
779
  case free_end:
780
    if (param->info->s->concurrent_insert)
781
      rw_unlock(&param->info->s->key_root_lock[param->keynr]);
782
    return 0;
783
  }
784
  return -1;
785
}
786
787
303 by Brian Aker
First pass in removing ulong from MyISAM
788
int mi_init_bulk_insert(MI_INFO *info, uint32_t cache_size, ha_rows rows)
1 by brian
clean slate
789
{
790
  MYISAM_SHARE *share=info->s;
791
  MI_KEYDEF *key=share->keyinfo;
792
  bulk_insert_param *params;
482 by Brian Aker
Remove uint.
793
  uint32_t i, num_keys, total_keylength;
151 by Brian Aker
Ulonglong to uint64_t
794
  uint64_t key_map;
1 by brian
clean slate
795
51.1.115 by Jay Pipes
DBUG symbol removal
796
  assert(!info->bulk_insert &&
1 by brian
clean slate
797
	      (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT));
798
799
  mi_clear_all_keys_active(key_map);
800
  for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++)
801
  {
802
    if (! (key[i].flag & HA_NOSAME) && (share->base.auto_key != i + 1) &&
803
        mi_is_key_active(share->state.key_map, i))
804
    {
805
      num_keys++;
806
      mi_set_key_active(key_map, i);
807
      total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE;
808
    }
809
  }
810
811
  if (num_keys==0 ||
812
      num_keys * MI_MIN_SIZE_BULK_INSERT_TREE > cache_size)
51.1.115 by Jay Pipes
DBUG symbol removal
813
    return(0);
1 by brian
clean slate
814
815
  if (rows && rows*total_keylength < cache_size)
303 by Brian Aker
First pass in removing ulong from MyISAM
816
    cache_size= (uint32_t)rows;
1 by brian
clean slate
817
  else
818
    cache_size/=total_keylength*16;
819
820
  info->bulk_insert=(TREE *)
821
    my_malloc((sizeof(TREE)*share->base.keys+
822
               sizeof(bulk_insert_param)*num_keys),MYF(0));
823
824
  if (!info->bulk_insert)
51.1.115 by Jay Pipes
DBUG symbol removal
825
    return(HA_ERR_OUT_OF_MEM);
1 by brian
clean slate
826
827
  params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
828
  for (i=0 ; i < share->base.keys ; i++)
829
  {
830
    if (mi_is_key_active(key_map, i))
831
    {
832
      params->info=info;
833
      params->keynr=i;
834
      /* Only allocate a 16'th of the buffer at a time */
835
      init_tree(&info->bulk_insert[i],
836
                cache_size * key[i].maxlength,
837
                cache_size * key[i].maxlength, 0,
838
		(qsort_cmp2)keys_compare, 0,
839
		(tree_element_free) keys_free, (void *)params++);
840
    }
841
    else
842
     info->bulk_insert[i].root=0;
843
  }
844
51.1.115 by Jay Pipes
DBUG symbol removal
845
  return(0);
1 by brian
clean slate
846
}
847
482 by Brian Aker
Remove uint.
848
void mi_flush_bulk_insert(MI_INFO *info, uint32_t inx)
1 by brian
clean slate
849
{
850
  if (info->bulk_insert)
851
  {
852
    if (is_tree_inited(&info->bulk_insert[inx]))
853
      reset_tree(&info->bulk_insert[inx]);
854
  }
855
}
856
857
void mi_end_bulk_insert(MI_INFO *info)
858
{
859
  if (info->bulk_insert)
860
  {
482 by Brian Aker
Remove uint.
861
    uint32_t i;
1 by brian
clean slate
862
    for (i=0 ; i < info->s->base.keys ; i++)
863
    {
864
      if (is_tree_inited(& info->bulk_insert[i]))
865
      {
866
        delete_tree(& info->bulk_insert[i]);
867
      }
868
    }
477 by Monty Taylor
Removed my_free(). It turns out that it had been def'd to ignore the flags passed to it in the second arg anyway. Gotta love that.
869
    free((void *)info->bulk_insert);
1 by brian
clean slate
870
    info->bulk_insert=0;
871
  }
872
}