00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "myisam_priv.h"
00019
00020 #include <drizzled/internal/m_string.h>
00021 #include <drizzled/util/test.h>
00022 #include <drizzled/tree.h>
00023
00024 using namespace drizzled;
00025
00026 #define MAX_POINTER_LENGTH 8
00027
00028
00029
00030 static int w_search(MI_INFO *info,MI_KEYDEF *keyinfo,
00031 uint32_t comp_flag, unsigned char *key,
00032 uint32_t key_length, internal::my_off_t pos, unsigned char *father_buff,
00033 unsigned char *father_keypos, internal::my_off_t father_page,
00034 bool insert_last);
00035 static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,unsigned char *key,
00036 unsigned char *curr_buff,unsigned char *father_buff,
00037 unsigned char *father_keypos,internal::my_off_t father_page);
00038 static unsigned char *_mi_find_last_pos(MI_KEYDEF *keyinfo, unsigned char *page,
00039 unsigned char *key, uint32_t *return_key_length,
00040 unsigned char **after_key);
00041 int _mi_ck_write_tree(register MI_INFO *info, uint32_t keynr,unsigned char *key,
00042 uint32_t key_length);
00043 int _mi_ck_write_btree(register MI_INFO *info, uint32_t keynr,unsigned char *key,
00044 uint32_t key_length);
00045
00046
00047
00048 int mi_write(MI_INFO *info, unsigned char *record)
00049 {
00050 MYISAM_SHARE *share=info->s;
00051 uint32_t i;
00052 int save_errno;
00053 internal::my_off_t filepos;
00054 unsigned char *buff;
00055 bool lock_tree= share->concurrent_insert;
00056
00057 if (share->options & HA_OPTION_READ_ONLY_DATA)
00058 {
00059 return(errno=EACCES);
00060 }
00061 if (_mi_readinfo(info,F_WRLCK,1))
00062 return(errno);
00063 filepos= ((share->state.dellink != HA_OFFSET_ERROR &&
00064 !info->append_insert_at_end) ?
00065 share->state.dellink :
00066 info->state->data_file_length);
00067
00068 if (share->base.reloc == (ha_rows) 1 &&
00069 share->base.records == (ha_rows) 1 &&
00070 info->state->records == (ha_rows) 1)
00071 {
00072 errno=HA_ERR_RECORD_FILE_FULL;
00073 goto err2;
00074 }
00075 if (info->state->key_file_length >= share->base.margin_key_file_length)
00076 {
00077 errno=HA_ERR_INDEX_FILE_FULL;
00078 goto err2;
00079 }
00080 if (_mi_mark_file_changed(info))
00081 goto err2;
00082
00083
00084 for (i=0 ; i < share->state.header.uniques ; i++)
00085 {
00086 if (mi_check_unique(info,share->uniqueinfo+i,record,
00087 mi_unique_hash(share->uniqueinfo+i,record),
00088 HA_OFFSET_ERROR))
00089 goto err2;
00090 }
00091
00092
00093
00094 buff=info->lastkey2;
00095 for (i=0 ; i < share->base.keys ; i++)
00096 {
00097 if (mi_is_key_active(share->state.key_map, i))
00098 {
00099 bool local_lock_tree= (lock_tree &&
00100 !(info->bulk_insert &&
00101 info->bulk_insert[i].is_inited()));
00102 if (local_lock_tree)
00103 {
00104 share->keyinfo[i].version++;
00105 }
00106 {
00107 if (share->keyinfo[i].ck_insert(info,i,buff,
00108 _mi_make_key(info,i,buff,record,filepos)))
00109 {
00110 goto err;
00111 }
00112 }
00113
00114
00115 info->update&= ~HA_STATE_RNEXT_SAME;
00116 }
00117 }
00118 if (share->calc_checksum)
00119 info->checksum=(*share->calc_checksum)(info,record);
00120 if (!(info->opt_flag & OPT_NO_ROWS))
00121 {
00122 if ((*share->write_record)(info,record))
00123 goto err;
00124 info->state->checksum+=info->checksum;
00125 }
00126 if (share->base.auto_key)
00127 set_if_bigger(info->s->state.auto_increment,
00128 retrieve_auto_increment(info, record));
00129 info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
00130 HA_STATE_ROW_CHANGED);
00131 info->state->records++;
00132 info->lastpos=filepos;
00133 _mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE);
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 if (share->is_log_table)
00144 assert(0);
00145
00146 return(0);
00147
00148 err:
00149 save_errno=errno;
00150 if (errno == HA_ERR_FOUND_DUPP_KEY || errno == HA_ERR_RECORD_FILE_FULL ||
00151 errno == HA_ERR_NULL_IN_SPATIAL || errno == HA_ERR_OUT_OF_MEM)
00152 {
00153 if (info->bulk_insert)
00154 {
00155 uint32_t j;
00156 for (j=0 ; j < share->base.keys ; j++)
00157 mi_flush_bulk_insert(info, j);
00158 }
00159 info->errkey= (int) i;
00160 while ( i-- > 0)
00161 {
00162 if (mi_is_key_active(share->state.key_map, i))
00163 {
00164 {
00165 uint32_t key_length=_mi_make_key(info,i,buff,record,filepos);
00166 if (_mi_ck_delete(info,i,buff,key_length))
00167 {
00168 break;
00169 }
00170 }
00171 }
00172 }
00173 }
00174 else
00175 {
00176 mi_print_error(info->s, HA_ERR_CRASHED);
00177 mi_mark_crashed(info);
00178 }
00179 info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
00180 errno=save_errno;
00181 err2:
00182 save_errno=errno;
00183 _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
00184 return(errno=save_errno);
00185 }
00186
00187
00188
00189
00190 int _mi_ck_write(MI_INFO *info, uint32_t keynr, unsigned char *key, uint32_t key_length)
00191 {
00192 if (info->bulk_insert && info->bulk_insert[keynr].is_inited())
00193 {
00194 return(_mi_ck_write_tree(info, keynr, key, key_length));
00195 }
00196 else
00197 {
00198 return(_mi_ck_write_btree(info, keynr, key, key_length));
00199 }
00200 }
00201
00202
00203
00204
00205
00206
00207 int _mi_ck_write_btree(register MI_INFO *info, uint32_t keynr, unsigned char *key,
00208 uint32_t key_length)
00209 {
00210 uint32_t error;
00211 uint32_t comp_flag;
00212 MI_KEYDEF *keyinfo=info->s->keyinfo+keynr;
00213 internal::my_off_t *root=&info->s->state.key_root[keynr];
00214
00215 if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
00216 comp_flag=SEARCH_BIGGER;
00217 else if (keyinfo->flag & (HA_NOSAME))
00218 {
00219 comp_flag=SEARCH_FIND | SEARCH_UPDATE;
00220 if (keyinfo->flag & HA_NULL_ARE_EQUAL)
00221 comp_flag|= SEARCH_NULL_ARE_EQUAL;
00222 }
00223 else
00224 comp_flag=SEARCH_SAME;
00225
00226 error=_mi_ck_real_write_btree(info, keyinfo, key, key_length,
00227 root, comp_flag);
00228 return(error);
00229 }
00230
00231 int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
00232 unsigned char *key, uint32_t key_length, internal::my_off_t *root, uint32_t comp_flag)
00233 {
00234 int error;
00235
00236 if (*root == HA_OFFSET_ERROR ||
00237 (error=w_search(info, keyinfo, comp_flag, key, key_length,
00238 *root, (unsigned char *) 0, (unsigned char*) 0,
00239 (internal::my_off_t) 0, 1)) > 0)
00240 error=_mi_enlarge_root(info,keyinfo,key,root);
00241 return(error);
00242 }
00243
00244
00245
00246
00247 int _mi_enlarge_root(MI_INFO *info, MI_KEYDEF *keyinfo, unsigned char *key,
00248 internal::my_off_t *root)
00249 {
00250 uint32_t t_length,nod_flag;
00251 MI_KEY_PARAM s_temp;
00252 MYISAM_SHARE *share=info->s;
00253
00254 nod_flag= (*root != HA_OFFSET_ERROR) ? share->base.key_reflength : 0;
00255 _mi_kpointer(info,info->buff+2,*root);
00256 t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(unsigned char*) 0,
00257 (unsigned char*) 0, (unsigned char*) 0, key,&s_temp);
00258 mi_putint(info->buff,t_length+2+nod_flag,nod_flag);
00259 (*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp);
00260 info->buff_used=info->page_changed=1;
00261 if ((*root= _mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR ||
00262 _mi_write_keypage(info,keyinfo,*root,DFLT_INIT_HITS,info->buff))
00263 return(-1);
00264 return(0);
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
00276 uint32_t comp_flag, unsigned char *key, uint32_t key_length, internal::my_off_t page,
00277 unsigned char *father_buff, unsigned char *father_keypos,
00278 internal::my_off_t father_page, bool insert_last)
00279 {
00280 int error,flag;
00281 uint32_t nod_flag, search_key_length;
00282 unsigned char *temp_buff,*keypos;
00283 unsigned char keybuff[MI_MAX_KEY_BUFF];
00284 bool was_last_key;
00285 internal::my_off_t next_page, dupp_key_pos;
00286
00287 search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
00288 if (!(temp_buff= (unsigned char*) malloc(keyinfo->block_length+
00289 MI_MAX_KEY_BUFF*2)))
00290 return(-1);
00291 if (!_mi_fetch_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff,0))
00292 goto err;
00293
00294 flag=(*keyinfo->bin_search)(info,keyinfo,temp_buff,key,search_key_length,
00295 comp_flag, &keypos, keybuff, &was_last_key);
00296 nod_flag=mi_test_if_nod(temp_buff);
00297 if (flag == 0)
00298 {
00299 uint32_t tmp_key_length;
00300
00301 tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff);
00302 if (tmp_key_length)
00303 dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length);
00304 else
00305 dupp_key_pos= HA_OFFSET_ERROR;
00306
00307 {
00308 info->dupp_key_pos= dupp_key_pos;
00309 free(temp_buff);
00310 errno=HA_ERR_FOUND_DUPP_KEY;
00311 return(-1);
00312 }
00313 }
00314 if (flag == MI_FOUND_WRONG_KEY)
00315 return(-1);
00316 if (!was_last_key)
00317 insert_last=0;
00318 next_page=_mi_kpos(nod_flag,keypos);
00319 if (next_page == HA_OFFSET_ERROR ||
00320 (error=w_search(info, keyinfo, comp_flag, key, key_length, next_page,
00321 temp_buff, keypos, page, insert_last)) >0)
00322 {
00323 error=_mi_insert(info,keyinfo,key,temp_buff,keypos,keybuff,father_buff,
00324 father_keypos,father_page, insert_last);
00325 if (_mi_write_keypage(info,keyinfo,page,DFLT_INIT_HITS,temp_buff))
00326 goto err;
00327 }
00328 free(temp_buff);
00329 return(error);
00330 err:
00331 free(temp_buff);
00332 return (-1);
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
00362 unsigned char *key, unsigned char *anc_buff, unsigned char *key_pos, unsigned char *key_buff,
00363 unsigned char *father_buff, unsigned char *father_key_pos, internal::my_off_t father_page,
00364 bool insert_last)
00365 {
00366 uint32_t a_length,nod_flag;
00367 int t_length;
00368 unsigned char *endpos, *prev_key;
00369 MI_KEY_PARAM s_temp;
00370
00371 nod_flag=mi_test_if_nod(anc_buff);
00372 a_length=mi_getint(anc_buff);
00373 endpos= anc_buff+ a_length;
00374 prev_key=(key_pos == anc_buff+2+nod_flag ? (unsigned char*) 0 : key_buff);
00375 t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,
00376 (key_pos == endpos ? (unsigned char*) 0 : key_pos),
00377 prev_key, prev_key,
00378 key,&s_temp);
00379
00380 if (t_length > 0)
00381 {
00382 if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
00383 {
00384 mi_print_error(info->s, HA_ERR_CRASHED);
00385 errno=HA_ERR_CRASHED;
00386 return(-1);
00387 }
00388 internal::bmove_upp((unsigned char*) endpos+t_length,(unsigned char*) endpos,(uint) (endpos-key_pos));
00389 }
00390 else
00391 {
00392 if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
00393 {
00394 mi_print_error(info->s, HA_ERR_CRASHED);
00395 errno=HA_ERR_CRASHED;
00396 return(-1);
00397 }
00398 memmove(key_pos, key_pos - t_length, endpos - key_pos + t_length);
00399 }
00400 (*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
00401 a_length+=t_length;
00402 mi_putint(anc_buff,a_length,nod_flag);
00403 if (a_length <= keyinfo->block_length)
00404 {
00405 return(0);
00406 }
00407
00408 if (nod_flag)
00409 insert_last=0;
00410 if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
00411 father_buff && !insert_last)
00412 return(_mi_balance_page(info,keyinfo,key,anc_buff,father_buff,
00413 father_key_pos,father_page));
00414 return(_mi_split_page(info,keyinfo,key,anc_buff,key_buff, insert_last));
00415 }
00416
00417
00418
00419
00420 int _mi_split_page(register MI_INFO *info, register MI_KEYDEF *keyinfo,
00421 unsigned char *key, unsigned char *buff, unsigned char *key_buff,
00422 bool insert_last_key)
00423 {
00424 uint32_t length,a_length,key_ref_length,t_length,nod_flag,key_length;
00425 unsigned char *key_pos,*pos, *after_key= NULL;
00426 internal::my_off_t new_pos;
00427 MI_KEY_PARAM s_temp;
00428
00429 if (info->s->keyinfo+info->lastinx == keyinfo)
00430 info->page_changed=1;
00431 info->buff_used=1;
00432 nod_flag=mi_test_if_nod(buff);
00433 key_ref_length=2+nod_flag;
00434 if (insert_last_key)
00435 key_pos=_mi_find_last_pos(keyinfo,buff,key_buff, &key_length, &after_key);
00436 else
00437 key_pos=_mi_find_half_pos(nod_flag,keyinfo,buff,key_buff, &key_length,
00438 &after_key);
00439 if (!key_pos)
00440 return(-1);
00441
00442 length=(uint) (key_pos-buff);
00443 a_length=mi_getint(buff);
00444 mi_putint(buff,length,nod_flag);
00445
00446 key_pos=after_key;
00447 if (nod_flag)
00448 {
00449 pos=key_pos-nod_flag;
00450 memcpy(info->buff + 2, pos, nod_flag);
00451 }
00452
00453
00454 if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
00455 return(-1);
00456 _mi_kpointer(info,_mi_move_key(keyinfo,key,key_buff),new_pos);
00457
00458
00459 if (!(*keyinfo->get_key)(keyinfo,nod_flag,&key_pos,key_buff))
00460 return(-1);
00461
00462 t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(unsigned char *) 0,
00463 (unsigned char*) 0, (unsigned char*) 0,
00464 key_buff, &s_temp);
00465 length=(uint) ((buff+a_length)-key_pos);
00466 memcpy(info->buff+key_ref_length+t_length, key_pos, length);
00467 (*keyinfo->store_key)(keyinfo,info->buff+key_ref_length,&s_temp);
00468 mi_putint(info->buff,length+t_length+key_ref_length,nod_flag);
00469
00470 if (_mi_write_keypage(info,keyinfo,new_pos,DFLT_INIT_HITS,info->buff))
00471 return(-1);
00472 return(2);
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 unsigned char *_mi_find_half_pos(uint32_t nod_flag, MI_KEYDEF *keyinfo, unsigned char *page,
00485 unsigned char *key, uint32_t *return_key_length,
00486 unsigned char **after_key)
00487 {
00488 uint32_t keys,length,key_ref_length;
00489 unsigned char *end,*lastpos;
00490
00491 key_ref_length=2+nod_flag;
00492 length=mi_getint(page)-key_ref_length;
00493 page+=key_ref_length;
00494 if (!(keyinfo->flag &
00495 (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
00496 HA_BINARY_PACK_KEY)))
00497 {
00498 key_ref_length=keyinfo->keylength+nod_flag;
00499 keys=length/(key_ref_length*2);
00500 *return_key_length=keyinfo->keylength;
00501 end=page+keys*key_ref_length;
00502 *after_key=end+key_ref_length;
00503 memcpy(key,end,key_ref_length);
00504 return(end);
00505 }
00506
00507 end=page+length/2-key_ref_length;
00508 *key='\0';
00509 do
00510 {
00511 lastpos=page;
00512 if (!(length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key)))
00513 return(0);
00514 } while (page < end);
00515 *return_key_length=length;
00516 *after_key=page;
00517 return(lastpos);
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527 static unsigned char *_mi_find_last_pos(MI_KEYDEF *keyinfo, unsigned char *page,
00528 unsigned char *key, uint32_t *return_key_length,
00529 unsigned char **after_key)
00530 {
00531 uint32_t keys;
00532 uint32_t length;
00533 uint32_t last_length= 0;
00534 uint32_t key_ref_length;
00535 unsigned char *end, *lastpos, *prevpos= NULL;
00536 unsigned char key_buff[MI_MAX_KEY_BUFF];
00537
00538 key_ref_length=2;
00539 length=mi_getint(page)-key_ref_length;
00540 page+=key_ref_length;
00541 if (!(keyinfo->flag &
00542 (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
00543 HA_BINARY_PACK_KEY)))
00544 {
00545 keys=length/keyinfo->keylength-2;
00546 *return_key_length=length=keyinfo->keylength;
00547 end=page+keys*length;
00548 *after_key=end+length;
00549 memcpy(key,end,length);
00550 return(end);
00551 }
00552
00553 end= page + length - key_ref_length;
00554 *key='\0';
00555 length=0;
00556 lastpos=page;
00557 while (page < end)
00558 {
00559 prevpos=lastpos; lastpos=page;
00560 last_length=length;
00561 memcpy(key, key_buff, length);
00562 if (!(length=(*keyinfo->get_key)(keyinfo,0,&page,key_buff)))
00563 {
00564 mi_print_error(keyinfo->share, HA_ERR_CRASHED);
00565 errno=HA_ERR_CRASHED;
00566 return(0);
00567 }
00568 }
00569 *return_key_length=last_length;
00570 *after_key=lastpos;
00571 return(prevpos);
00572 }
00573
00574
00575
00576
00577
00578 static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo,
00579 unsigned char *key, unsigned char *curr_buff, unsigned char *father_buff,
00580 unsigned char *father_key_pos, internal::my_off_t father_page)
00581 {
00582 bool right;
00583 uint32_t k_length,father_length,father_keylength,nod_flag,curr_keylength,
00584 right_length,left_length,new_right_length,new_left_length,extra_length,
00585 length,keys;
00586 unsigned char *pos,*buff,*extra_buff;
00587 internal::my_off_t next_page,new_pos;
00588 unsigned char tmp_part_key[MI_MAX_KEY_BUFF];
00589
00590 k_length=keyinfo->keylength;
00591 father_length=mi_getint(father_buff);
00592 father_keylength=k_length+info->s->base.key_reflength;
00593 nod_flag=mi_test_if_nod(curr_buff);
00594 curr_keylength=k_length+nod_flag;
00595 info->page_changed=1;
00596
00597 if ((father_key_pos != father_buff+father_length &&
00598 (info->state->records & 1)) ||
00599 father_key_pos == father_buff+2+info->s->base.key_reflength)
00600 {
00601 right=1;
00602 next_page= _mi_kpos(info->s->base.key_reflength,
00603 father_key_pos+father_keylength);
00604 buff=info->buff;
00605 }
00606 else
00607 {
00608 right=0;
00609 father_key_pos-=father_keylength;
00610 next_page= _mi_kpos(info->s->base.key_reflength,father_key_pos);
00611
00612 buff=curr_buff; curr_buff=info->buff;
00613 }
00614
00615 if (!_mi_fetch_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff,0))
00616 goto err;
00617
00618
00619
00620 left_length=mi_getint(curr_buff);
00621 right_length=mi_getint(buff);
00622 keys=(left_length+right_length-4-nod_flag*2)/curr_keylength;
00623
00624 if ((right ? right_length : left_length) + curr_keylength <=
00625 keyinfo->block_length)
00626 {
00627 new_left_length=2+nod_flag+(keys/2)*curr_keylength;
00628 new_right_length=2+nod_flag+((keys+1)/2)*curr_keylength;
00629 mi_putint(curr_buff,new_left_length,nod_flag);
00630 mi_putint(buff,new_right_length,nod_flag);
00631
00632 if (left_length < new_left_length)
00633 {
00634 pos=curr_buff+left_length;
00635 memcpy(pos, father_key_pos, k_length);
00636 length= new_left_length - left_length - k_length;
00637 memcpy(pos+k_length, buff+2, length);
00638 pos=buff+2+length;
00639 memcpy(father_key_pos, pos, k_length);
00640 memmove(buff+2, pos+k_length, new_right_length);
00641 }
00642 else
00643 {
00644
00645 internal::bmove_upp((unsigned char*) buff+new_right_length,(unsigned char*) buff+right_length,
00646 right_length-2);
00647 length=new_right_length-right_length-k_length;
00648 memcpy(buff+2+length,father_key_pos, k_length);
00649 pos=curr_buff+new_left_length;
00650 memcpy(father_key_pos, pos, k_length);
00651 memcpy(buff+2, pos+k_length, length);
00652 }
00653
00654 if (_mi_write_keypage(info,keyinfo,next_page,DFLT_INIT_HITS,info->buff) ||
00655 _mi_write_keypage(info,keyinfo,father_page,DFLT_INIT_HITS,father_buff))
00656 goto err;
00657 return(0);
00658 }
00659
00660
00661
00662 extra_buff=info->buff+info->s->base.max_key_block_length;
00663 new_left_length=new_right_length=2+nod_flag+(keys+1)/3*curr_keylength;
00664 if (keys == 5)
00665 new_left_length-=curr_keylength;
00666 extra_length=nod_flag+left_length+right_length-
00667 new_left_length-new_right_length-curr_keylength;
00668 mi_putint(curr_buff,new_left_length,nod_flag);
00669 mi_putint(buff,new_right_length,nod_flag);
00670 mi_putint(extra_buff,extra_length+2,nod_flag);
00671
00672
00673 pos=buff+right_length-extra_length;
00674 memcpy(extra_buff+2, pos, extra_length);
00675
00676 memcpy(tmp_part_key, pos-k_length,k_length);
00677
00678 internal::bmove_upp((unsigned char*) buff+new_right_length,(unsigned char*) pos-k_length,
00679 right_length-extra_length-k_length-2);
00680
00681 pos= curr_buff+new_left_length;
00682 length= left_length - new_left_length - k_length;
00683 memcpy(buff+2, pos+k_length, length);
00684
00685 memcpy(buff+2+length, father_key_pos, k_length);
00686
00687
00688 memcpy((right ? key : father_key_pos), pos, k_length);
00689 memcpy((right ? father_key_pos : key), tmp_part_key, k_length);
00690
00691 if ((new_pos=_mi_new(info,keyinfo,DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
00692 goto err;
00693 _mi_kpointer(info,key+k_length,new_pos);
00694 if (_mi_write_keypage(info,keyinfo,(right ? new_pos : next_page),
00695 DFLT_INIT_HITS,info->buff) ||
00696 _mi_write_keypage(info,keyinfo,(right ? next_page : new_pos),
00697 DFLT_INIT_HITS,extra_buff))
00698 goto err;
00699
00700 return(1);
00701
00702 err:
00703 return(-1);
00704 }
00705
00706
00707
00708
00709
00710 typedef struct {
00711 MI_INFO *info;
00712 uint32_t keynr;
00713 } bulk_insert_param;
00714
00715 int _mi_ck_write_tree(register MI_INFO *info, uint32_t keynr, unsigned char *key,
00716 uint32_t key_length)
00717 {
00718 int error;
00719
00720 error= info->bulk_insert[keynr].tree_insert(key,
00721 key_length + info->s->rec_reflength,
00722 info->bulk_insert[keynr].getCustomArg()) ? 0 : HA_ERR_OUT_OF_MEM ;
00723
00724 return(error);
00725 }
00726
00727
00728
00729
00730 static int keys_compare(bulk_insert_param *param, unsigned char *key1, unsigned char *key2)
00731 {
00732 uint32_t not_used[2];
00733 return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
00734 key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
00735 not_used);
00736 }
00737
00738
00739 static int keys_free(unsigned char *key, TREE_FREE mode, bulk_insert_param *param)
00740 {
00741
00742
00743
00744
00745 unsigned char lastkey[MI_MAX_KEY_BUFF];
00746 uint32_t keylen;
00747 MI_KEYDEF *keyinfo;
00748
00749 switch (mode) {
00750 case free_init:
00751 if (param->info->s->concurrent_insert)
00752 {
00753 param->info->s->keyinfo[param->keynr].version++;
00754 }
00755 return 0;
00756 case free_free:
00757 keyinfo=param->info->s->keyinfo+param->keynr;
00758 keylen=_mi_keylength(keyinfo, key);
00759 memcpy(lastkey, key, keylen);
00760 return _mi_ck_write_btree(param->info,param->keynr,lastkey,
00761 keylen - param->info->s->rec_reflength);
00762 case free_end:
00763 return 0;
00764 }
00765 return -1;
00766 }
00767
00768
00769 int mi_init_bulk_insert(MI_INFO *info, uint32_t cache_size, ha_rows rows)
00770 {
00771 MYISAM_SHARE *share=info->s;
00772 MI_KEYDEF *key=share->keyinfo;
00773 bulk_insert_param *params;
00774 uint32_t i, num_keys, total_keylength;
00775 uint64_t key_map;
00776
00777 assert(!info->bulk_insert &&
00778 (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT));
00779
00780 mi_clear_all_keys_active(key_map);
00781 for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++)
00782 {
00783 if (! (key[i].flag & HA_NOSAME) && (share->base.auto_key != i + 1) &&
00784 mi_is_key_active(share->state.key_map, i))
00785 {
00786 num_keys++;
00787 mi_set_key_active(key_map, i);
00788 total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE;
00789 }
00790 }
00791
00792 if (num_keys==0 ||
00793 num_keys * MI_MIN_SIZE_BULK_INSERT_TREE > cache_size)
00794 return(0);
00795
00796 if (rows && rows*total_keylength < cache_size)
00797 cache_size= (uint32_t)rows;
00798 else
00799 cache_size/=total_keylength*16;
00800
00801 info->bulk_insert=(Tree *) malloc((sizeof(Tree)*share->base.keys+
00802 sizeof(bulk_insert_param)*num_keys));
00803
00804 if (!info->bulk_insert)
00805 return(HA_ERR_OUT_OF_MEM);
00806
00807 params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
00808 for (i=0 ; i < share->base.keys ; i++)
00809 {
00810 if (mi_is_key_active(key_map, i))
00811 {
00812 params->info=info;
00813 params->keynr=i;
00814
00815 info->bulk_insert[i].init_tree(cache_size * key[i].maxlength,
00816 cache_size * key[i].maxlength, 0,
00817 (qsort_cmp2)keys_compare, false,
00818 (tree_element_free) keys_free, (void *)params++);
00819 }
00820 else
00821 info->bulk_insert[i].setRoot(0);
00822 }
00823
00824 return(0);
00825 }
00826
00827 void mi_flush_bulk_insert(MI_INFO *info, uint32_t inx)
00828 {
00829 if (info->bulk_insert)
00830 {
00831 if (info->bulk_insert[inx].is_inited())
00832 info->bulk_insert[inx].reset_tree();
00833 }
00834 }
00835
00836 void mi_end_bulk_insert(MI_INFO *info)
00837 {
00838 if (info->bulk_insert)
00839 {
00840 uint32_t i;
00841 for (i=0 ; i < info->s->base.keys ; i++)
00842 {
00843 if (info->bulk_insert[i].is_inited())
00844 {
00845 info->bulk_insert[i].delete_tree();
00846 }
00847 }
00848 free((void *)info->bulk_insert);
00849 info->bulk_insert=0;
00850 }
00851 }