1
/* Copyright (C) 2000-2006 MySQL AB
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.
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.
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 */
16
/* Write a row to a MyISAM table */
21
#define MAX_POINTER_LENGTH 8
23
/* Functions declared in this file */
25
static int w_search(MI_INFO *info,MI_KEYDEF *keyinfo,
26
uint comp_flag, uchar *key,
27
uint key_length, my_off_t pos, uchar *father_buff,
28
uchar *father_keypos, my_off_t father_page,
30
static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
31
uchar *curr_buff,uchar *father_buff,
32
uchar *father_keypos,my_off_t father_page);
33
static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
34
uchar *key, uint *return_key_length,
36
int _mi_ck_write_tree(register MI_INFO *info, uint keynr,uchar *key,
38
int _mi_ck_write_btree(register MI_INFO *info, uint keynr,uchar *key,
41
/* Write new record to database */
43
int mi_write(MI_INFO *info, uchar *record)
45
MYISAM_SHARE *share=info->s;
50
my_bool lock_tree= share->concurrent_insert;
51
DBUG_ENTER("mi_write");
52
DBUG_PRINT("enter",("isam: %d data: %d",info->s->kfile,info->dfile));
54
DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage",
55
mi_print_error(info->s, HA_ERR_CRASHED);
56
DBUG_RETURN(my_errno= HA_ERR_CRASHED););
57
if (share->options & HA_OPTION_READ_ONLY_DATA)
59
DBUG_RETURN(my_errno=EACCES);
61
if (_mi_readinfo(info,F_WRLCK,1))
62
DBUG_RETURN(my_errno);
63
dont_break(); /* Dont allow SIGHUP or SIGINT */
64
#if !defined(NO_LOCKING) && defined(USE_RECORD_LOCK)
65
if (!info->locked && my_lock(info->dfile,F_WRLCK,0L,F_TO_EOF,
66
MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
69
filepos= ((share->state.dellink != HA_OFFSET_ERROR &&
70
!info->append_insert_at_end) ?
71
share->state.dellink :
72
info->state->data_file_length);
74
if (share->base.reloc == (ha_rows) 1 &&
75
share->base.records == (ha_rows) 1 &&
76
info->state->records == (ha_rows) 1)
78
my_errno=HA_ERR_RECORD_FILE_FULL;
81
if (info->state->key_file_length >= share->base.margin_key_file_length)
83
my_errno=HA_ERR_INDEX_FILE_FULL;
86
if (_mi_mark_file_changed(info))
89
/* Calculate and check all unique constraints */
90
for (i=0 ; i < share->state.header.uniques ; i++)
92
if (mi_check_unique(info,share->uniqueinfo+i,record,
93
mi_unique_hash(share->uniqueinfo+i,record),
98
/* Write all keys to indextree */
101
for (i=0 ; i < share->base.keys ; i++)
103
if (mi_is_key_active(share->state.key_map, i))
105
my_bool local_lock_tree= (lock_tree &&
106
!(info->bulk_insert &&
107
is_tree_inited(&info->bulk_insert[i])));
110
rw_wrlock(&share->key_root_lock[i]);
111
share->keyinfo[i].version++;
113
if (share->keyinfo[i].flag & HA_FULLTEXT )
115
if (_mi_ft_add(info,i, buff, record, filepos))
118
rw_unlock(&share->key_root_lock[i]);
119
DBUG_PRINT("error",("Got error: %d on write",my_errno));
125
if (share->keyinfo[i].ck_insert(info,i,buff,
126
_mi_make_key(info,i,buff,record,filepos)))
129
rw_unlock(&share->key_root_lock[i]);
130
DBUG_PRINT("error",("Got error: %d on write",my_errno));
135
/* The above changed info->lastkey2. Inform mi_rnext_same(). */
136
info->update&= ~HA_STATE_RNEXT_SAME;
139
rw_unlock(&share->key_root_lock[i]);
142
if (share->calc_checksum)
143
info->checksum=(*share->calc_checksum)(info,record);
144
if (!(info->opt_flag & OPT_NO_ROWS))
146
if ((*share->write_record)(info,record))
148
info->state->checksum+=info->checksum;
150
if (share->base.auto_key)
151
set_if_bigger(info->s->state.auto_increment,
152
retrieve_auto_increment(info, record));
153
info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
154
HA_STATE_ROW_CHANGED);
155
info->state->records++;
156
info->lastpos=filepos;
157
myisam_log_record(MI_LOG_WRITE,info,record,filepos,0);
158
VOID(_mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
159
if (info->invalidator != 0)
161
DBUG_PRINT("info", ("invalidator... '%s' (update)", info->filename));
162
(*info->invalidator)(info->filename);
167
Update status of the table. We need to do so after each row write
168
for the log tables, as we want the new row to become visible to
169
other threads as soon as possible. We don't lock mutex here
170
(as it is required by pthread memory visibility rules) as (1) it's
171
not critical to use outdated share->is_log_table value (2) locking
172
mutex here for every write is too expensive.
174
if (share->is_log_table)
175
mi_update_status((void*) info);
177
allow_break(); /* Allow SIGHUP & SIGINT */
182
if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL ||
183
my_errno == HA_ERR_NULL_IN_SPATIAL || my_errno == HA_ERR_OUT_OF_MEM)
185
if (info->bulk_insert)
188
for (j=0 ; j < share->base.keys ; j++)
189
mi_flush_bulk_insert(info, j);
191
info->errkey= (int) i;
194
if (mi_is_key_active(share->state.key_map, i))
196
my_bool local_lock_tree= (lock_tree &&
197
!(info->bulk_insert &&
198
is_tree_inited(&info->bulk_insert[i])));
200
rw_wrlock(&share->key_root_lock[i]);
201
if (share->keyinfo[i].flag & HA_FULLTEXT)
203
if (_mi_ft_del(info,i, buff,record,filepos))
206
rw_unlock(&share->key_root_lock[i]);
212
uint key_length=_mi_make_key(info,i,buff,record,filepos);
213
if (_mi_ck_delete(info,i,buff,key_length))
216
rw_unlock(&share->key_root_lock[i]);
221
rw_unlock(&share->key_root_lock[i]);
227
mi_print_error(info->s, HA_ERR_CRASHED);
228
mi_mark_crashed(info);
230
info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
234
myisam_log_record(MI_LOG_WRITE,info,record,filepos,my_errno);
235
VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
236
allow_break(); /* Allow SIGHUP & SIGINT */
237
DBUG_RETURN(my_errno=save_errno);
241
/* Write one key to btree */
243
int _mi_ck_write(MI_INFO *info, uint keynr, uchar *key, uint key_length)
245
DBUG_ENTER("_mi_ck_write");
247
if (info->bulk_insert && is_tree_inited(&info->bulk_insert[keynr]))
249
DBUG_RETURN(_mi_ck_write_tree(info, keynr, key, key_length));
253
DBUG_RETURN(_mi_ck_write_btree(info, keynr, key, key_length));
258
/**********************************************************************
259
* Normal insert code *
260
**********************************************************************/
262
int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
267
MI_KEYDEF *keyinfo=info->s->keyinfo+keynr;
268
my_off_t *root=&info->s->state.key_root[keynr];
269
DBUG_ENTER("_mi_ck_write_btree");
271
if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
272
comp_flag=SEARCH_BIGGER; /* Put after same key */
273
else if (keyinfo->flag & (HA_NOSAME|HA_FULLTEXT))
275
comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No duplicates */
276
if (keyinfo->flag & HA_NULL_ARE_EQUAL)
277
comp_flag|= SEARCH_NULL_ARE_EQUAL;
280
comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
282
error=_mi_ck_real_write_btree(info, keyinfo, key, key_length,
284
if (info->ft1_to_ft2)
287
error= _mi_ft_convert_to_ft2(info, keynr, key);
288
delete_dynamic(info->ft1_to_ft2);
289
my_free((uchar*)info->ft1_to_ft2, MYF(0));
293
} /* _mi_ck_write_btree */
295
int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
296
uchar *key, uint key_length, my_off_t *root, uint comp_flag)
299
DBUG_ENTER("_mi_ck_real_write_btree");
300
/* key_length parameter is used only if comp_flag is SEARCH_FIND */
301
if (*root == HA_OFFSET_ERROR ||
302
(error=w_search(info, keyinfo, comp_flag, key, key_length,
303
*root, (uchar *) 0, (uchar*) 0,
304
(my_off_t) 0, 1)) > 0)
305
error=_mi_enlarge_root(info,keyinfo,key,root);
307
} /* _mi_ck_real_write_btree */
310
/* Make a new root with key as only pointer */
312
int _mi_enlarge_root(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
315
uint t_length,nod_flag;
317
MYISAM_SHARE *share=info->s;
318
DBUG_ENTER("_mi_enlarge_root");
320
nod_flag= (*root != HA_OFFSET_ERROR) ? share->base.key_reflength : 0;
321
_mi_kpointer(info,info->buff+2,*root); /* if nod */
322
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar*) 0,
323
(uchar*) 0, (uchar*) 0, key,&s_temp);
324
mi_putint(info->buff,t_length+2+nod_flag,nod_flag);
325
(*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp);
326
info->buff_used=info->page_changed=1; /* info->buff is used */
327
if ((*root= _mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR ||
328
_mi_write_keypage(info,keyinfo,*root,DFLT_INIT_HITS,info->buff))
331
} /* _mi_enlarge_root */
335
Search after a position for a key and store it there
338
1 = key should be stored in higher tree
341
static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
342
uint comp_flag, uchar *key, uint key_length, my_off_t page,
343
uchar *father_buff, uchar *father_keypos,
344
my_off_t father_page, my_bool insert_last)
347
uint nod_flag, search_key_length;
348
uchar *temp_buff,*keypos;
349
uchar keybuff[MI_MAX_KEY_BUFF];
350
my_bool was_last_key;
351
my_off_t next_page, dupp_key_pos;
352
DBUG_ENTER("w_search");
353
DBUG_PRINT("enter",("page: %ld", (long) page));
355
search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
356
if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
359
if (!_mi_fetch_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff,0))
362
flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,search_key_length,
363
comp_flag, &keypos, keybuff, &was_last_key);
364
nod_flag=mi_test_if_nod(temp_buff);
368
/* get position to record with duplicated key */
369
tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff);
371
dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length);
373
dupp_key_pos= HA_OFFSET_ERROR;
375
if (keyinfo->flag & HA_FULLTEXT)
380
get_key_full_length_rdonly(off, keybuff);
381
subkeys=ft_sintXkorr(keybuff+off);
382
comp_flag=SEARCH_SAME;
385
/* normal word, one-level tree structure */
386
flag=(*keyinfo->bin_search)(info, keyinfo, temp_buff, key,
387
USE_WHOLE_KEY, comp_flag,
388
&keypos, keybuff, &was_last_key);
392
/* popular word. two-level tree. going down */
393
my_off_t root=dupp_key_pos;
394
keyinfo=&info->s->ft2_keyinfo;
395
get_key_full_length_rdonly(off, key);
397
keypos-=keyinfo->keylength+nod_flag; /* we'll modify key entry 'in vivo' */
398
error=_mi_ck_real_write_btree(info, keyinfo, key, 0,
400
_mi_dpointer(info, keypos+HA_FT_WLEN, root);
401
subkeys--; /* should there be underflow protection ? */
402
DBUG_ASSERT(subkeys < 0);
403
ft_intXstore(keypos, subkeys);
405
error=_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff);
406
my_afree((uchar*) temp_buff);
410
else /* not HA_FULLTEXT, normal HA_NOSAME key */
412
info->dupp_key_pos= dupp_key_pos;
413
my_afree((uchar*) temp_buff);
414
my_errno=HA_ERR_FOUND_DUPP_KEY;
418
if (flag == MI_FOUND_WRONG_KEY)
422
next_page=_mi_kpos(nod_flag,keypos);
423
if (next_page == HA_OFFSET_ERROR ||
424
(error=w_search(info, keyinfo, comp_flag, key, key_length, next_page,
425
temp_buff, keypos, page, insert_last)) >0)
427
error=_mi_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
428
father_keypos,father_page, insert_last);
429
if (_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff))
432
my_afree((uchar*) temp_buff);
435
my_afree((uchar*) temp_buff);
436
DBUG_PRINT("exit",("Error: %d",my_errno));
446
info Open table information.
447
keyinfo Key definition information.
449
anc_buff Key page (beginning).
450
key_pos Position in key page where to insert.
451
key_buff Copy of previous key.
452
father_buff parent key page for balancing.
453
father_key_pos position in parent key page for balancing.
454
father_page position of parent key page in file.
455
insert_last If to append at end of page.
458
Insert new key at right of key_pos.
461
2 if key contains key to upper level.
466
int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
467
uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
468
uchar *father_buff, uchar *father_key_pos, my_off_t father_page,
471
uint a_length,nod_flag;
473
uchar *endpos, *prev_key;
475
DBUG_ENTER("_mi_insert");
476
DBUG_PRINT("enter",("key_pos: 0x%lx", (long) key_pos));
477
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,USE_WHOLE_KEY););
479
nod_flag=mi_test_if_nod(anc_buff);
480
a_length=mi_getint(anc_buff);
481
endpos= anc_buff+ a_length;
482
prev_key=(key_pos == anc_buff+2+nod_flag ? (uchar*) 0 : key_buff);
483
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
484
(key_pos == endpos ? (uchar*) 0 : key_pos),
488
if (key_pos != anc_buff+2+nod_flag && (keyinfo->flag &
489
(HA_BINARY_PACK_KEY | HA_PACK_KEY)))
491
DBUG_DUMP("prev_key",(uchar*) key_buff,_mi_keylength(keyinfo,key_buff));
493
if (keyinfo->flag & HA_PACK_KEY)
495
DBUG_PRINT("test",("t_length: %d ref_len: %d",
496
t_length,s_temp.ref_length));
497
DBUG_PRINT("test",("n_ref_len: %d n_length: %d key_pos: 0x%lx",
498
s_temp.n_ref_length,s_temp.n_length, (long) s_temp.key));
503
if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
505
mi_print_error(info->s, HA_ERR_CRASHED);
506
my_errno=HA_ERR_CRASHED;
509
bmove_upp((uchar*) endpos+t_length,(uchar*) endpos,(uint) (endpos-key_pos));
513
if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
515
mi_print_error(info->s, HA_ERR_CRASHED);
516
my_errno=HA_ERR_CRASHED;
519
bmove(key_pos,key_pos-t_length,(uint) (endpos-key_pos)+t_length);
521
(*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
523
mi_putint(anc_buff,a_length,nod_flag);
524
if (a_length <= keyinfo->block_length)
526
if (keyinfo->block_length - a_length < 32 &&
527
keyinfo->flag & HA_FULLTEXT && key_pos == endpos &&
528
info->s->base.key_reflength <= info->s->base.rec_reflength &&
529
info->s->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))
532
Normal word. One-level tree. Page is almost full.
533
Let's consider converting.
534
We'll compare 'key' and the first key at anc_buff
536
uchar *a=key, *b=anc_buff+2+nod_flag;
537
uint alen, blen, ft2len=info->s->ft2_keyinfo.keylength;
538
/* the very first key on the page is always unpacked */
539
DBUG_ASSERT((*b & 128) == 0);
540
#if HA_FT_MAXLEN >= 127
541
blen= mi_uint2korr(b); b+=2;
545
get_key_length(alen,a);
546
DBUG_ASSERT(info->ft1_to_ft2==0);
548
ha_compare_text(keyinfo->seg->charset, a, alen, b, blen, 0, 0)==0)
550
/* yup. converting */
551
info->ft1_to_ft2=(DYNAMIC_ARRAY *)
552
my_malloc(sizeof(DYNAMIC_ARRAY), MYF(MY_WME));
553
my_init_dynamic_array(info->ft1_to_ft2, ft2len, 300, 50);
556
now, adding all keys from the page to dynarray
557
if the page is a leaf (if not keys will be deleted later)
561
/* let's leave the first key on the page, though, because
562
we cannot easily dispatch an empty page here */
564
for (a=anc_buff+a_length ; b < a ; b+=ft2len+2)
565
insert_dynamic(info->ft1_to_ft2, b);
567
/* fixing the page's length - it contains only one key now */
568
mi_putint(anc_buff,2+blen+ft2len+2,0);
570
/* the rest will be done when we're back from recursion */
573
DBUG_RETURN(0); /* There is room on page */
578
if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
579
father_buff && !insert_last)
580
DBUG_RETURN(_mi_balance_page(info,keyinfo,key,anc_buff,father_buff,
581
father_key_pos,father_page));
582
DBUG_RETURN(_mi_split_page(info,keyinfo,key,anc_buff,key_buff, insert_last));
586
/* split a full page in two and assign emerging item to key */
588
int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo,
589
uchar *key, uchar *buff, uchar *key_buff,
590
my_bool insert_last_key)
592
uint length,a_length,key_ref_length,t_length,nod_flag,key_length;
593
uchar *key_pos,*pos, *after_key= NULL;
596
DBUG_ENTER("mi_split_page");
597
DBUG_DUMP("buff",(uchar*) buff,mi_getint(buff));
599
if (info->s->keyinfo+info->lastinx == keyinfo)
600
info->page_changed=1; /* Info->buff is used */
602
nod_flag=mi_test_if_nod(buff);
603
key_ref_length=2+nod_flag;
605
key_pos=_mi_find_last_pos(keyinfo,buff,key_buff, &key_length, &after_key);
607
key_pos=_mi_find_half_pos(nod_flag,keyinfo,buff,key_buff, &key_length,
612
length=(uint) (key_pos-buff);
613
a_length=mi_getint(buff);
614
mi_putint(buff,length,nod_flag);
619
DBUG_PRINT("test",("Splitting nod"));
620
pos=key_pos-nod_flag;
621
memcpy((uchar*) info->buff+2,(uchar*) pos,(size_t) nod_flag);
624
/* Move middle item to key and pointer to new page */
625
if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
627
_mi_kpointer(info,_mi_move_key(keyinfo,key,key_buff),new_pos);
630
if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff))
633
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar *) 0,
634
(uchar*) 0, (uchar*) 0,
636
length=(uint) ((buff+a_length)-key_pos);
637
memcpy((uchar*) info->buff+key_ref_length+t_length,(uchar*) key_pos,
639
(*keyinfo->store_key)(keyinfo,info->buff+key_ref_length,&s_temp);
640
mi_putint(info->buff,length+t_length+key_ref_length,nod_flag);
642
if (_mi_write_keypage(info,keyinfo,new_pos,DFLT_INIT_HITS,info->buff))
644
DBUG_DUMP("key",(uchar*) key,_mi_keylength(keyinfo,key));
645
DBUG_RETURN(2); /* Middle key up */
646
} /* _mi_split_page */
650
Calculate how to much to move to split a page in two
651
Returns pointer to start of key.
652
key will contain the key.
653
return_key_length will contain the length of key
654
after_key will contain the position to where the next key starts
657
uchar *_mi_find_half_pos(uint nod_flag, MI_KEYDEF *keyinfo, uchar *page,
658
uchar *key, uint *return_key_length,
661
uint keys,length,key_ref_length;
663
DBUG_ENTER("_mi_find_half_pos");
665
key_ref_length=2+nod_flag;
666
length=mi_getint(page)-key_ref_length;
667
page+=key_ref_length;
668
if (!(keyinfo->flag &
669
(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
670
HA_BINARY_PACK_KEY)))
672
key_ref_length=keyinfo->keylength+nod_flag;
673
keys=length/(key_ref_length*2);
674
*return_key_length=keyinfo->keylength;
675
end=page+keys*key_ref_length;
676
*after_key=end+key_ref_length;
677
memcpy(key,end,key_ref_length);
681
end=page+length/2-key_ref_length; /* This is aprox. half */
686
if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key)))
688
} while (page < end);
689
*return_key_length=length;
691
DBUG_PRINT("exit",("returns: 0x%lx page: 0x%lx half: 0x%lx",
692
(long) lastpos, (long) page, (long) end));
693
DBUG_RETURN(lastpos);
694
} /* _mi_find_half_pos */
698
Split buffer at last key
699
Returns pointer to the start of the key before the last key
700
key will contain the last key
703
static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
704
uchar *key, uint *return_key_length,
707
uint keys, length, last_length, key_ref_length;
708
uchar *end, *lastpos, *prevpos= NULL;
709
uchar key_buff[MI_MAX_KEY_BUFF];
710
DBUG_ENTER("_mi_find_last_pos");
713
length=mi_getint(page)-key_ref_length;
714
page+=key_ref_length;
715
if (!(keyinfo->flag &
716
(HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
717
HA_BINARY_PACK_KEY)))
719
keys=length/keyinfo->keylength-2;
720
*return_key_length=length=keyinfo->keylength;
721
end=page+keys*length;
722
*after_key=end+length;
723
memcpy(key,end,length);
727
end= page + length - key_ref_length;
733
prevpos=lastpos; lastpos=page;
735
memcpy(key, key_buff, length); /* previous key */
736
if (!(length=(*keyinfo->get_key)(keyinfo,0,&page,key_buff)))
738
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
739
my_errno=HA_ERR_CRASHED;
743
*return_key_length=last_length;
745
DBUG_PRINT("exit",("returns: 0x%lx page: 0x%lx end: 0x%lx",
746
(long) prevpos,(long) page,(long) end));
747
DBUG_RETURN(prevpos);
748
} /* _mi_find_last_pos */
751
/* Balance page with not packed keys with page on right/left */
752
/* returns 0 if balance was done */
754
static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo,
755
uchar *key, uchar *curr_buff, uchar *father_buff,
756
uchar *father_key_pos, my_off_t father_page)
759
uint k_length,father_length,father_keylength,nod_flag,curr_keylength,
760
right_length,left_length,new_right_length,new_left_length,extra_length,
762
uchar *pos,*buff,*extra_buff;
763
my_off_t next_page,new_pos;
764
uchar tmp_part_key[MI_MAX_KEY_BUFF];
765
DBUG_ENTER("_mi_balance_page");
767
k_length=keyinfo->keylength;
768
father_length=mi_getint(father_buff);
769
father_keylength=k_length+info->s->base.key_reflength;
770
nod_flag=mi_test_if_nod(curr_buff);
771
curr_keylength=k_length+nod_flag;
772
info->page_changed=1;
774
if ((father_key_pos != father_buff+father_length &&
775
(info->state->records & 1)) ||
776
father_key_pos == father_buff+2+info->s->base.key_reflength)
779
next_page= _mi_kpos(info->s->base.key_reflength,
780
father_key_pos+father_keylength);
782
DBUG_PRINT("test",("use right page: %lu", (ulong) next_page));
787
father_key_pos-=father_keylength;
788
next_page= _mi_kpos(info->s->base.key_reflength,father_key_pos);
789
/* Fix that curr_buff is to left */
790
buff=curr_buff; curr_buff=info->buff;
791
DBUG_PRINT("test",("use left page: %lu", (ulong) next_page));
792
} /* father_key_pos ptr to parting key */
794
if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff,0))
796
DBUG_DUMP("next",(uchar*) info->buff,mi_getint(info->buff));
798
/* Test if there is room to share keys */
800
left_length=mi_getint(curr_buff);
801
right_length=mi_getint(buff);
802
keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;
804
if ((right ? right_length : left_length) + curr_keylength <=
805
keyinfo->block_length)
807
new_left_length=2+nod_flag+(keys/2)*curr_keylength;
808
new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
809
mi_putint(curr_buff,new_left_length,nod_flag);
810
mi_putint(buff,new_right_length,nod_flag);
812
if (left_length < new_left_length)
813
{ /* Move keys buff -> leaf */
814
pos=curr_buff+left_length;
815
memcpy((uchar*) pos,(uchar*) father_key_pos, (size_t) k_length);
816
memcpy((uchar*) pos+k_length, (uchar*) buff+2,
817
(size_t) (length=new_left_length - left_length - k_length));
819
memcpy((uchar*) father_key_pos,(uchar*) pos,(size_t) k_length);
820
bmove((uchar*) buff+2,(uchar*) pos+k_length,new_right_length);
823
{ /* Move keys -> buff */
825
bmove_upp((uchar*) buff+new_right_length,(uchar*) buff+right_length,
827
length=new_right_length-right_length-k_length;
828
memcpy((uchar*) buff+2+length,father_key_pos,(size_t) k_length);
829
pos=curr_buff+new_left_length;
830
memcpy((uchar*) father_key_pos,(uchar*) pos,(size_t) k_length);
831
memcpy((uchar*) buff+2,(uchar*) pos+k_length,(size_t) length);
834
if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff) ||
835
_mi_write_keypage(info,keyinfo,father_page,DFLT_INIT_HITS,father_buff))
840
/* curr_buff[] and buff[] are full, lets split and make new nod */
842
extra_buff=info->buff+info->s->base.max_key_block_length;
843
new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
844
if (keys == 5) /* Too few keys to balance */
845
new_left_length-=curr_keylength;
846
extra_length=nod_flag+left_length+right_length-
847
new_left_length-new_right_length-curr_keylength;
848
DBUG_PRINT("info",("left_length: %d right_length: %d new_left_length: %d new_right_length: %d extra_length: %d",
849
left_length, right_length,
850
new_left_length, new_right_length,
852
mi_putint(curr_buff,new_left_length,nod_flag);
853
mi_putint(buff,new_right_length,nod_flag);
854
mi_putint(extra_buff,extra_length+2,nod_flag);
856
/* move first largest keys to new page */
857
pos=buff+right_length-extra_length;
858
memcpy((uchar*) extra_buff+2,pos,(size_t) extra_length);
859
/* Save new parting key */
860
memcpy(tmp_part_key, pos-k_length,k_length);
861
/* Make place for new keys */
862
bmove_upp((uchar*) buff+new_right_length,(uchar*) pos-k_length,
863
right_length-extra_length-k_length-2);
864
/* Copy keys from left page */
865
pos= curr_buff+new_left_length;
866
memcpy((uchar*) buff+2,(uchar*) pos+k_length,
867
(size_t) (length=left_length-new_left_length-k_length));
868
/* Copy old parting key */
869
memcpy((uchar*) buff+2+length,father_key_pos,(size_t) k_length);
871
/* Move new parting keys up to caller */
872
memcpy((uchar*) (right ? key : father_key_pos),pos,(size_t) k_length);
873
memcpy((uchar*) (right ? father_key_pos : key),tmp_part_key, k_length);
875
if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
877
_mi_kpointer(info,key+k_length,new_pos);
878
if (_mi_write_keypage(info,keyinfo,(right ? new_pos : next_page),
879
DFLT_INIT_HITS,info->buff) ||
880
_mi_write_keypage(info,keyinfo,(right ? next_page : new_pos),
881
DFLT_INIT_HITS,extra_buff))
884
DBUG_RETURN(1); /* Middle key up */
888
} /* _mi_balance_page */
890
/**********************************************************************
892
**********************************************************************/
899
int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key,
903
DBUG_ENTER("_mi_ck_write_tree");
905
error= tree_insert(&info->bulk_insert[keynr], key,
906
key_length + info->s->rec_reflength,
907
info->bulk_insert[keynr].custom_arg) ? 0 : HA_ERR_OUT_OF_MEM ;
910
} /* _mi_ck_write_tree */
913
/* typeof(_mi_keys_compare)=qsort_cmp2 */
915
static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2)
918
return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
919
key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
924
static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
927
Probably I can use info->lastkey here, but I'm not sure,
928
and to be safe I'd better use local lastkey.
930
uchar lastkey[MI_MAX_KEY_BUFF];
936
if (param->info->s->concurrent_insert)
938
rw_wrlock(¶m->info->s->key_root_lock[param->keynr]);
939
param->info->s->keyinfo[param->keynr].version++;
943
keyinfo=param->info->s->keyinfo+param->keynr;
944
keylen=_mi_keylength(keyinfo, key);
945
memcpy(lastkey, key, keylen);
946
return _mi_ck_write_btree(param->info,param->keynr,lastkey,
947
keylen - param->info->s->rec_reflength);
949
if (param->info->s->concurrent_insert)
950
rw_unlock(¶m->info->s->key_root_lock[param->keynr]);
957
int mi_init_bulk_insert(MI_INFO *info, ulong cache_size, ha_rows rows)
959
MYISAM_SHARE *share=info->s;
960
MI_KEYDEF *key=share->keyinfo;
961
bulk_insert_param *params;
962
uint i, num_keys, total_keylength;
964
DBUG_ENTER("_mi_init_bulk_insert");
965
DBUG_PRINT("enter",("cache_size: %lu", cache_size));
967
DBUG_ASSERT(!info->bulk_insert &&
968
(!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT));
970
mi_clear_all_keys_active(key_map);
971
for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++)
973
if (! (key[i].flag & HA_NOSAME) && (share->base.auto_key != i + 1) &&
974
mi_is_key_active(share->state.key_map, i))
977
mi_set_key_active(key_map, i);
978
total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE;
983
num_keys * MI_MIN_SIZE_BULK_INSERT_TREE > cache_size)
986
if (rows && rows*total_keylength < cache_size)
987
cache_size= (ulong)rows;
989
cache_size/=total_keylength*16;
991
info->bulk_insert=(TREE *)
992
my_malloc((sizeof(TREE)*share->base.keys+
993
sizeof(bulk_insert_param)*num_keys),MYF(0));
995
if (!info->bulk_insert)
996
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
998
params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
999
for (i=0 ; i < share->base.keys ; i++)
1001
if (mi_is_key_active(key_map, i))
1005
/* Only allocate a 16'th of the buffer at a time */
1006
init_tree(&info->bulk_insert[i],
1007
cache_size * key[i].maxlength,
1008
cache_size * key[i].maxlength, 0,
1009
(qsort_cmp2)keys_compare, 0,
1010
(tree_element_free) keys_free, (void *)params++);
1013
info->bulk_insert[i].root=0;
1019
void mi_flush_bulk_insert(MI_INFO *info, uint inx)
1021
if (info->bulk_insert)
1023
if (is_tree_inited(&info->bulk_insert[inx]))
1024
reset_tree(&info->bulk_insert[inx]);
1028
void mi_end_bulk_insert(MI_INFO *info)
1030
if (info->bulk_insert)
1033
for (i=0 ; i < info->s->base.keys ; i++)
1035
if (is_tree_inited(& info->bulk_insert[i]))
1037
delete_tree(& info->bulk_insert[i]);
1040
my_free((void *)info->bulk_insert, MYF(0));
1041
info->bulk_insert=0;