1 : /* Copyright (C) 2004-2008 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 : Copyright (C) 2008-2009 Sun Microsystems, Inc.
3 :
4 : This program is free software; you can redistribute it and/or modify
5 : it under the terms of the GNU General Public License as published by
6 : the Free Software Foundation; version 2 of the License.
7 :
8 : This program is distributed in the hope that it will be useful,
9 : but WITHOUT ANY WARRANTY; without even the implied warranty of
10 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 : GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License
14 : along with this program; if not, write to the Free Software
15 : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16 :
17 : /* Write a row to a MARIA table */
18 :
19 : #include "ma_fulltext.h"
20 : #include "ma_rt_index.h"
21 : #include "trnman.h"
22 : #include "ma_key_recover.h"
23 : #include "ma_blockrec.h"
24 :
25 : #define MAX_POINTER_LENGTH 8
26 :
27 : /* Functions declared in this file */
28 :
29 : static int w_search(MARIA_HA *info, uint32 comp_flag,
30 : MARIA_KEY *key, my_off_t page,
31 : MARIA_PAGE *father_page, uchar *father_keypos,
32 : my_bool insert_last);
33 : static int _ma_balance_page(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
34 : MARIA_KEY *key, MARIA_PAGE *curr_page,
35 : MARIA_PAGE *father_page,
36 : uchar *father_key_pos, MARIA_KEY_PARAM *s_temp);
37 : static uchar *_ma_find_last_pos(MARIA_KEY *int_key,
38 : MARIA_PAGE *page, uchar **after_key);
39 : static my_bool _ma_ck_write_tree(register MARIA_HA *info, MARIA_KEY *key);
40 : static my_bool _ma_ck_write_btree(register MARIA_HA *info, MARIA_KEY *key);
41 : static my_bool _ma_ck_write_btree_with_log(MARIA_HA *, MARIA_KEY *, my_off_t *,
42 : uint32);
43 : static my_bool _ma_log_split(MARIA_PAGE *page, uint org_length,
44 : uint new_length,
45 : const uchar *key_pos,
46 : uint key_length, int move_length,
47 : enum en_key_op prefix_or_suffix,
48 : const uchar *data, uint data_length,
49 : uint changed_length);
50 : static my_bool _ma_log_del_prefix(MARIA_PAGE *page,
51 : uint org_length, uint new_length,
52 : const uchar *key_pos, uint key_length,
53 : int move_length);
54 : static my_bool _ma_log_key_middle(MARIA_PAGE *page,
55 : uint new_length,
56 : uint data_added_first,
57 : uint data_changed_first,
58 : uint data_deleted_last,
59 : const uchar *key_pos,
60 : uint key_length, int move_length);
61 :
62 : /*
63 : @brief Default handler for returing position to new row
64 :
65 : @note
66 : This is only called for non transactional tables and not for block format
67 : which is why we use info->state here.
68 : */
69 :
70 : MARIA_RECORD_POS _ma_write_init_default(MARIA_HA *info,
71 : const uchar *record
72 : __attribute__((unused)))
73 0 : {
74 0 : return ((info->s->state.dellink != HA_OFFSET_ERROR &&
75 : !info->append_insert_at_end) ?
76 : info->s->state.dellink :
77 : info->state->data_file_length);
78 : }
79 :
80 : my_bool _ma_write_abort_default(MARIA_HA *info __attribute__((unused)))
81 0 : {
82 0 : return 0;
83 : }
84 :
85 :
86 : /* Write new record to a table */
87 :
88 : int maria_write(MARIA_HA *info, uchar *record)
89 1917 : {
90 1917 : MARIA_SHARE *share= info->s;
91 : uint i;
92 : int save_errno;
93 : MARIA_RECORD_POS filepos;
94 : uchar *buff;
95 1917 : my_bool lock_tree= share->lock_key_trees;
96 : my_bool fatal_error;
97 : MARIA_KEYDEF *keyinfo;
98 1917 : DBUG_ENTER("maria_write");
99 1917 : DBUG_PRINT("enter",("index_file: %d data_file: %d",
100 : share->kfile.file, info->dfile.file));
101 :
102 1917 : DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
103 : maria_print_error(info->s, HA_ERR_CRASHED);
104 : DBUG_RETURN(my_errno= HA_ERR_CRASHED););
105 1917 : if (share->options & HA_OPTION_READ_ONLY_DATA)
106 : {
107 0 : DBUG_RETURN(my_errno=EACCES);
108 : }
109 1917 : if (_ma_readinfo(info,F_WRLCK,1))
110 0 : DBUG_RETURN(my_errno);
111 : dont_break(); /* Dont allow SIGHUP or SIGINT */
112 :
113 1917 : if (share->base.reloc == (ha_rows) 1 &&
114 : share->base.records == (ha_rows) 1 &&
115 : share->state.state.records == (ha_rows) 1)
116 : { /* System file */
117 0 : my_errno=HA_ERR_RECORD_FILE_FULL;
118 0 : goto err2;
119 : }
120 1917 : if (share->state.state.key_file_length >= share->base.margin_key_file_length)
121 : {
122 0 : my_errno=HA_ERR_INDEX_FILE_FULL;
123 0 : goto err2;
124 : }
125 1917 : if (_ma_mark_file_changed(info))
126 1917 : goto err2;
127 :
128 : /* Calculate and check all unique constraints */
129 1917 : for (i=0 ; i < share->state.header.uniques ; i++)
130 : {
131 0 : if (_ma_check_unique(info,share->uniqueinfo+i,record,
132 : _ma_unique_hash(share->uniqueinfo+i,record),
133 : HA_OFFSET_ERROR))
134 0 : goto err2;
135 : }
136 :
137 : /* Ensure we don't try to restore auto_increment if it doesn't change */
138 1917 : info->last_auto_increment= ~(ulonglong) 0;
139 :
140 1917 : if ((info->opt_flag & OPT_NO_ROWS))
141 0 : filepos= HA_OFFSET_ERROR;
142 : else
143 : {
144 : /*
145 : This may either calculate a record or, or write the record and return
146 : the record id
147 : */
148 1917 : if ((filepos= (*share->write_record_init)(info, record)) ==
149 : HA_OFFSET_ERROR)
150 1917 : goto err2;
151 : }
152 :
153 : /* Write all keys to indextree */
154 1917 : buff= info->lastkey_buff2;
155 1917 : for (i=0, keyinfo= share->keyinfo ; i < share->base.keys ; i++, keyinfo++)
156 : {
157 : MARIA_KEY int_key;
158 0 : if (maria_is_key_active(share->state.key_map, i))
159 : {
160 : my_bool local_lock_tree= (lock_tree &&
161 : !(info->bulk_insert &&
162 0 : is_tree_inited(&info->bulk_insert[i])));
163 0 : if (local_lock_tree)
164 : {
165 0 : rw_wrlock(&keyinfo->root_lock);
166 0 : keyinfo->version++;
167 : }
168 0 : if (keyinfo->flag & HA_FULLTEXT )
169 : {
170 0 : if (_ma_ft_add(info,i, buff,record,filepos))
171 : {
172 0 : if (local_lock_tree)
173 0 : rw_unlock(&keyinfo->root_lock);
174 0 : DBUG_PRINT("error",("Got error: %d on write",my_errno));
175 0 : goto err;
176 : }
177 : }
178 : else
179 : {
180 0 : while (keyinfo->ck_insert(info,
181 : (*keyinfo->make_key)(info, &int_key, i,
182 : buff, record, filepos,
183 : info->trn->trid)))
184 : {
185 : TRN *blocker;
186 0 : DBUG_PRINT("error",("Got error: %d on write",my_errno));
187 : /*
188 : explicit check to filter out temp tables, they aren't
189 : transactional and don't have a proper TRN so the code
190 : below doesn't work for them.
191 : Also, filter out non-thread maria use, and table modified in
192 : the same transaction.
193 : At last, filter out non-dup-unique errors.
194 : */
195 0 : if (!local_lock_tree)
196 0 : goto err;
197 0 : if (info->dup_key_trid == info->trn->trid ||
198 : my_errno != HA_ERR_FOUND_DUPP_KEY)
199 : {
200 0 : rw_unlock(&keyinfo->root_lock);
201 0 : goto err;
202 : }
203 : /* Different TrIDs: table must be transactional */
204 0 : DBUG_ASSERT(share->base.born_transactional);
205 : /*
206 : If transactions are disabled, and dup_key_trid is different from
207 : our TrID, it must be ALTER TABLE with dup_key_trid==0 (no
208 : transaction). ALTER TABLE does have MARIA_HA::TRN not dummy but
209 : puts TrID=0 in rows/keys.
210 : */
211 0 : DBUG_ASSERT(share->now_transactional ||
212 : (info->dup_key_trid == 0));
213 0 : blocker= trnman_trid_to_trn(info->trn, info->dup_key_trid);
214 : /*
215 : if blocker TRN was not found, it means that the conflicting
216 : transaction was committed long time ago. It could not be
217 : aborted, as it would have to wait on the key tree lock
218 : to remove the conflicting key it has inserted.
219 : */
220 0 : if (!blocker || blocker->commit_trid != ~(TrID)0)
221 : { /* committed */
222 0 : if (blocker)
223 0 : pthread_mutex_unlock(& blocker->state_lock);
224 0 : rw_unlock(&keyinfo->root_lock);
225 0 : goto err;
226 : }
227 0 : rw_unlock(&keyinfo->root_lock);
228 : {
229 : /* running. now we wait */
230 : WT_RESOURCE_ID rc;
231 : int res;
232 : const char *old_proc_info;
233 :
234 0 : rc.type= &ma_rc_dup_unique;
235 : /* TODO savepoint id when we'll have them */
236 0 : rc.value= (intptr)blocker;
237 0 : res= wt_thd_will_wait_for(info->trn->wt, blocker->wt, & rc);
238 0 : if (res != WT_OK)
239 : {
240 0 : pthread_mutex_unlock(& blocker->state_lock);
241 0 : my_errno= HA_ERR_LOCK_DEADLOCK;
242 0 : goto err;
243 : }
244 0 : old_proc_info= proc_info_hook(0,
245 : "waiting for a resource",
246 : __func__, __FILE__, __LINE__);
247 0 : res= wt_thd_cond_timedwait(info->trn->wt, & blocker->state_lock);
248 0 : proc_info_hook(0, old_proc_info, __func__, __FILE__, __LINE__);
249 :
250 0 : pthread_mutex_unlock(& blocker->state_lock);
251 0 : if (res != WT_OK)
252 : {
253 0 : my_errno= res == WT_TIMEOUT ? HA_ERR_LOCK_WAIT_TIMEOUT
254 : : HA_ERR_LOCK_DEADLOCK;
255 0 : goto err;
256 : }
257 : }
258 0 : rw_wrlock(&keyinfo->root_lock);
259 : #ifndef MARIA_CANNOT_ROLLBACK
260 : keyinfo->version++;
261 : #endif
262 : }
263 : }
264 :
265 : /* The above changed info->lastkey2. Inform maria_rnext_same(). */
266 0 : info->update&= ~HA_STATE_RNEXT_SAME;
267 :
268 0 : if (local_lock_tree)
269 0 : rw_unlock(&keyinfo->root_lock);
270 : }
271 : }
272 1917 : if (share->calc_write_checksum)
273 0 : info->cur_row.checksum= (*share->calc_write_checksum)(info,record);
274 1917 : if (filepos != HA_OFFSET_ERROR)
275 : {
276 1917 : if ((*share->write_record)(info,record))
277 1917 : goto err;
278 1917 : info->state->checksum+= info->cur_row.checksum;
279 : }
280 1917 : if (!share->now_transactional)
281 : {
282 1917 : if (share->base.auto_key != 0)
283 : {
284 0 : const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
285 0 : const uchar *key= record + keyseg->start;
286 0 : set_if_bigger(share->state.auto_increment,
287 : ma_retrieve_auto_increment(key, keyseg->type));
288 : }
289 : }
290 1917 : info->state->records++;
291 1917 : info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
292 : HA_STATE_ROW_CHANGED);
293 1917 : share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED;
294 1917 : info->state->changed= 1;
295 :
296 1917 : info->cur_row.lastpos= filepos;
297 1917 : VOID(_ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
298 1917 : if (info->invalidator != 0)
299 : {
300 0 : DBUG_PRINT("info", ("invalidator... '%s' (update)",
301 : share->open_file_name.str));
302 0 : (*info->invalidator)(share->open_file_name.str);
303 0 : info->invalidator=0;
304 : }
305 :
306 : /*
307 : Update status of the table. We need to do so after each row write
308 : for the log tables, as we want the new row to become visible to
309 : other threads as soon as possible. We don't lock mutex here
310 : (as it is required by pthread memory visibility rules) as (1) it's
311 : not critical to use outdated share->is_log_table value (2) locking
312 : mutex here for every write is too expensive.
313 : */
314 1917 : if (share->is_log_table)
315 0 : _ma_update_status((void*) info);
316 :
317 : allow_break(); /* Allow SIGHUP & SIGINT */
318 1917 : DBUG_RETURN(0);
319 :
320 0 : err:
321 0 : save_errno= my_errno;
322 0 : fatal_error= 0;
323 0 : if (my_errno == HA_ERR_FOUND_DUPP_KEY ||
324 : my_errno == HA_ERR_RECORD_FILE_FULL ||
325 : my_errno == HA_ERR_LOCK_DEADLOCK ||
326 : my_errno == HA_ERR_LOCK_WAIT_TIMEOUT ||
327 : my_errno == HA_ERR_NULL_IN_SPATIAL ||
328 : my_errno == HA_ERR_OUT_OF_MEM)
329 : {
330 0 : if (info->bulk_insert)
331 : {
332 : uint j;
333 0 : for (j=0 ; j < share->base.keys ; j++)
334 0 : maria_flush_bulk_insert(info, j);
335 : }
336 0 : info->errkey= (int) i;
337 : /*
338 : We delete keys in the reverse order of insertion. This is the order that
339 : a rollback would do and is important for CLR_ENDs generated by
340 : _ma_ft|ck_delete() and write_record_abort() to work (with any other
341 : order they would cause wrong jumps in the chain).
342 : */
343 0 : while ( i-- > 0)
344 : {
345 0 : if (maria_is_key_active(share->state.key_map, i))
346 : {
347 : my_bool local_lock_tree= (lock_tree &&
348 : !(info->bulk_insert &&
349 0 : is_tree_inited(&info->bulk_insert[i])));
350 0 : keyinfo= share->keyinfo + i;
351 0 : if (local_lock_tree)
352 0 : rw_wrlock(&keyinfo->root_lock);
353 : /**
354 : @todo RECOVERY BUG
355 : The key deletes below should generate CLR_ENDs
356 : */
357 0 : if (keyinfo->flag & HA_FULLTEXT)
358 : {
359 0 : if (_ma_ft_del(info,i,buff,record,filepos))
360 : {
361 0 : if (local_lock_tree)
362 0 : rw_unlock(&keyinfo->root_lock);
363 : break;
364 : }
365 : }
366 : else
367 : {
368 : MARIA_KEY key;
369 0 : if (_ma_ck_delete(info,
370 : (*keyinfo->make_key)(info, &key, i, buff, record,
371 : filepos, info->trn->trid)))
372 : {
373 0 : if (local_lock_tree)
374 0 : rw_unlock(&keyinfo->root_lock);
375 : break;
376 : }
377 : }
378 0 : if (local_lock_tree)
379 0 : rw_unlock(&keyinfo->root_lock);
380 : }
381 : }
382 : }
383 : else
384 0 : fatal_error= 1;
385 :
386 0 : if ((*share->write_record_abort)(info))
387 0 : fatal_error= 1;
388 0 : if (fatal_error)
389 : {
390 0 : maria_print_error(info->s, HA_ERR_CRASHED);
391 0 : maria_mark_crashed(info);
392 : }
393 :
394 0 : info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
395 0 : my_errno=save_errno;
396 0 : err2:
397 0 : save_errno=my_errno;
398 0 : DBUG_ASSERT(save_errno);
399 0 : if (!save_errno)
400 0 : save_errno= HA_ERR_INTERNAL_ERROR; /* Should never happen */
401 0 : DBUG_PRINT("error", ("got error: %d", save_errno));
402 0 : VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
403 : allow_break(); /* Allow SIGHUP & SIGINT */
404 0 : DBUG_RETURN(my_errno=save_errno);
405 : } /* maria_write */
406 :
407 :
408 : /*
409 : Write one key to btree
410 :
411 : TODO
412 : Remove this function and have bulk insert change keyinfo->ck_insert
413 : to point to the right function
414 : */
415 :
416 : my_bool _ma_ck_write(MARIA_HA *info, MARIA_KEY *key)
417 0 : {
418 0 : DBUG_ENTER("_ma_ck_write");
419 :
420 0 : if (info->bulk_insert &&
421 : is_tree_inited(&info->bulk_insert[key->keyinfo->key_nr]))
422 : {
423 0 : DBUG_RETURN(_ma_ck_write_tree(info, key));
424 : }
425 0 : DBUG_RETURN(_ma_ck_write_btree(info, key));
426 : } /* _ma_ck_write */
427 :
428 :
429 : /**********************************************************************
430 : Insert key into btree (normal case)
431 : **********************************************************************/
432 :
433 : static my_bool _ma_ck_write_btree(MARIA_HA *info, MARIA_KEY *key)
434 0 : {
435 : my_bool error;
436 0 : MARIA_KEYDEF *keyinfo= key->keyinfo;
437 0 : my_off_t *root= &info->s->state.key_root[keyinfo->key_nr];
438 0 : DBUG_ENTER("_ma_ck_write_btree");
439 :
440 0 : error= _ma_ck_write_btree_with_log(info, key, root,
441 : keyinfo->write_comp_flag | key->flag);
442 0 : if (info->ft1_to_ft2)
443 : {
444 0 : if (!error)
445 0 : error= _ma_ft_convert_to_ft2(info, key);
446 0 : delete_dynamic(info->ft1_to_ft2);
447 0 : my_free(info->ft1_to_ft2, MYF(0));
448 0 : info->ft1_to_ft2=0;
449 : }
450 0 : DBUG_RETURN(error);
451 : } /* _ma_ck_write_btree */
452 :
453 :
454 : /**
455 : @brief Write a key to the b-tree
456 :
457 : @retval 1 error
458 : @retval 0 ok
459 : */
460 :
461 : static my_bool _ma_ck_write_btree_with_log(MARIA_HA *info, MARIA_KEY *key,
462 : my_off_t *root, uint32 comp_flag)
463 0 : {
464 0 : MARIA_SHARE *share= info->s;
465 0 : LSN lsn= LSN_IMPOSSIBLE;
466 : int error;
467 0 : my_off_t new_root= *root;
468 : uchar key_buff[MARIA_MAX_KEY_BUFF];
469 : MARIA_KEY org_key;
470 0 : DBUG_ENTER("_ma_ck_write_btree_with_log");
471 :
472 0 : LINT_INIT_STRUCT(org_key);
473 0 : if (share->now_transactional)
474 : {
475 : /* Save original value as the key may change */
476 0 : org_key= *key;
477 0 : memcpy(key_buff, key->data, key->data_length + key->ref_length);
478 : }
479 :
480 0 : error= _ma_ck_real_write_btree(info, key, &new_root, comp_flag);
481 0 : if (!error && share->now_transactional)
482 : {
483 : /* Log the original value */
484 0 : *key= org_key;
485 0 : key->data= key_buff;
486 0 : error= _ma_write_undo_key_insert(info, key, root, new_root, &lsn);
487 : }
488 : else
489 : {
490 0 : *root= new_root;
491 0 : _ma_fast_unlock_key_del(info);
492 : }
493 0 : _ma_unpin_all_pages_and_finalize_row(info, lsn);
494 :
495 0 : DBUG_RETURN(error != 0);
496 : } /* _ma_ck_write_btree_with_log */
497 :
498 :
499 : /**
500 : @brief Write a key to the b-tree
501 :
502 : @retval 1 error
503 : @retval 0 ok
504 : */
505 :
506 : my_bool _ma_ck_real_write_btree(MARIA_HA *info, MARIA_KEY *key, my_off_t *root,
507 : uint32 comp_flag)
508 0 : {
509 : int error;
510 0 : DBUG_ENTER("_ma_ck_real_write_btree");
511 :
512 : /* key_length parameter is used only if comp_flag is SEARCH_FIND */
513 0 : if (*root == HA_OFFSET_ERROR ||
514 : (error= w_search(info, comp_flag, key, *root, (MARIA_PAGE *) 0,
515 : (uchar*) 0, 1)) > 0)
516 0 : error= _ma_enlarge_root(info, key, root);
517 0 : DBUG_RETURN(error != 0);
518 : } /* _ma_ck_real_write_btree */
519 :
520 :
521 : /**
522 : @brief Make a new root with key as only pointer
523 :
524 : @retval 1 error
525 : @retval 0 ok
526 : */
527 :
528 : my_bool _ma_enlarge_root(MARIA_HA *info, MARIA_KEY *key, my_off_t *root)
529 0 : {
530 : uint t_length, nod_flag;
531 : MARIA_KEY_PARAM s_temp;
532 0 : MARIA_SHARE *share= info->s;
533 0 : MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
534 0 : MARIA_KEYDEF *keyinfo= key->keyinfo;
535 : MARIA_PAGE page;
536 0 : my_bool res= 0;
537 0 : DBUG_ENTER("_ma_enlarge_root");
538 :
539 0 : page.info= info;
540 0 : page.keyinfo= keyinfo;
541 0 : page.buff= info->buff;
542 0 : page.flag= 0;
543 :
544 0 : nod_flag= (*root != HA_OFFSET_ERROR) ? share->base.key_reflength : 0;
545 : /* Store pointer to prev page if nod */
546 0 : _ma_kpointer(info, page.buff + share->keypage_header, *root);
547 0 : t_length= (*keyinfo->pack_key)(key, nod_flag, (uchar*) 0,
548 : (uchar*) 0, (uchar*) 0, &s_temp);
549 0 : page.size= share->keypage_header + t_length + nod_flag;
550 :
551 0 : bzero(page.buff, share->keypage_header);
552 0 : _ma_store_keynr(share, page.buff, keyinfo->key_nr);
553 0 : if (nod_flag)
554 0 : page.flag|= KEYPAGE_FLAG_ISNOD;
555 0 : if (key->flag & (SEARCH_USER_KEY_HAS_TRANSID | SEARCH_PAGE_KEY_HAS_TRANSID))
556 0 : page.flag|= KEYPAGE_FLAG_HAS_TRANSID;
557 0 : (*keyinfo->store_key)(keyinfo, page.buff + share->keypage_header +
558 : nod_flag, &s_temp);
559 :
560 : /* Mark that info->buff was used */
561 0 : info->keyread_buff_used= info->page_changed= 1;
562 0 : if ((page.pos= _ma_new(info, PAGECACHE_PRIORITY_HIGH, &page_link)) ==
563 : HA_OFFSET_ERROR)
564 0 : DBUG_RETURN(1);
565 0 : *root= page.pos;
566 :
567 0 : page_store_info(share, &page);
568 :
569 : /*
570 : Clear unitialized part of page to avoid valgrind/purify warnings
571 : and to get a clean page that is easier to compress and compare with
572 : pages generated with redo
573 : */
574 0 : bzero(page.buff + page.size, share->block_size - page.size);
575 :
576 0 : if (share->now_transactional && _ma_log_new(&page, 1))
577 0 : res= 1;
578 :
579 0 : if (_ma_write_keypage(&page, page_link->write_lock,
580 : PAGECACHE_PRIORITY_HIGH))
581 0 : res= 1;
582 :
583 0 : DBUG_RETURN(res);
584 : } /* _ma_enlarge_root */
585 :
586 :
587 : /*
588 : Search after a position for a key and store it there
589 :
590 : @return
591 : @retval -1 error
592 : @retval 0 ok
593 : @retval > 0 Key should be stored in higher tree
594 : */
595 :
596 : static int w_search(register MARIA_HA *info, uint32 comp_flag, MARIA_KEY *key,
597 : my_off_t page_pos,
598 : MARIA_PAGE *father_page, uchar *father_keypos,
599 : my_bool insert_last)
600 0 : {
601 : int error,flag;
602 : uchar *temp_buff,*keypos;
603 : uchar keybuff[MARIA_MAX_KEY_BUFF];
604 : my_bool was_last_key;
605 : my_off_t next_page, dup_key_pos;
606 0 : MARIA_SHARE *share= info->s;
607 0 : MARIA_KEYDEF *keyinfo= key->keyinfo;
608 : MARIA_PAGE page;
609 0 : DBUG_ENTER("w_search");
610 0 : DBUG_PRINT("enter",("page: %ld", (long) page_pos));
611 :
612 0 : if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
613 : MARIA_MAX_KEY_BUFF*2)))
614 0 : DBUG_RETURN(-1);
615 0 : if (_ma_fetch_keypage(&page, info, keyinfo, page_pos, PAGECACHE_LOCK_WRITE,
616 : DFLT_INIT_HITS, temp_buff, 0))
617 0 : goto err;
618 :
619 0 : flag= (*keyinfo->bin_search)(key, &page, comp_flag, &keypos,
620 : keybuff, &was_last_key);
621 0 : if (flag == 0)
622 : {
623 : MARIA_KEY tmp_key;
624 : /* get position to record with duplicated key */
625 :
626 0 : tmp_key.keyinfo= keyinfo;
627 0 : tmp_key.data= keybuff;
628 :
629 0 : if ((*keyinfo->get_key)(&tmp_key, page.flag, page.node, &keypos))
630 0 : dup_key_pos= _ma_row_pos_from_key(&tmp_key);
631 : else
632 0 : dup_key_pos= HA_OFFSET_ERROR;
633 :
634 0 : if (keyinfo->flag & HA_FULLTEXT)
635 : {
636 : uint off;
637 : int subkeys;
638 :
639 0 : get_key_full_length_rdonly(off, keybuff);
640 0 : subkeys=ft_sintXkorr(keybuff+off);
641 0 : comp_flag=SEARCH_SAME;
642 0 : if (subkeys >= 0)
643 : {
644 : /* normal word, one-level tree structure */
645 0 : flag=(*keyinfo->bin_search)(key, &page, comp_flag,
646 : &keypos, keybuff, &was_last_key);
647 : }
648 : else
649 : {
650 : /* popular word. two-level tree. going down */
651 0 : my_off_t root=dup_key_pos;
652 0 : keyinfo= &share->ft2_keyinfo;
653 0 : get_key_full_length_rdonly(off, key);
654 0 : key+=off;
655 : /* we'll modify key entry 'in vivo' */
656 0 : keypos-= keyinfo->keylength + page.node;
657 0 : error= _ma_ck_real_write_btree(info, key, &root, comp_flag);
658 0 : _ma_dpointer(share, keypos+HA_FT_WLEN, root);
659 0 : subkeys--; /* should there be underflow protection ? */
660 0 : DBUG_ASSERT(subkeys < 0);
661 0 : ft_intXstore(keypos, subkeys);
662 0 : if (!error)
663 : {
664 0 : page_mark_changed(info, &page);
665 0 : if (_ma_write_keypage(&page, PAGECACHE_LOCK_LEFT_WRITELOCKED,
666 : DFLT_INIT_HITS))
667 0 : goto err;
668 : }
669 : my_afree(temp_buff);
670 0 : DBUG_RETURN(error);
671 : }
672 : }
673 : else /* not HA_FULLTEXT, normal HA_NOSAME key */
674 : {
675 0 : DBUG_PRINT("warning", ("Duplicate key"));
676 : /*
677 : TODO
678 : When the index will support true versioning - with multiple
679 : identical values in the UNIQUE index, invisible to each other -
680 : the following should be changed to "continue inserting keys, at the
681 : end (of the row or statement) wait". We need to wait on *all*
682 : unique conflicts at once, not one-at-a-time, because we need to
683 : know all blockers in advance, otherwise we'll have incomplete wait-for
684 : graph.
685 : */
686 : /*
687 : transaction that has inserted the conflicting key may be in progress.
688 : the caller will wait for it to be committed or aborted.
689 : */
690 0 : info->dup_key_trid= _ma_trid_from_key(&tmp_key);
691 0 : info->dup_key_pos= dup_key_pos;
692 0 : my_errno= HA_ERR_FOUND_DUPP_KEY;
693 0 : goto err;
694 : }
695 : }
696 0 : if (flag == MARIA_FOUND_WRONG_KEY)
697 0 : goto err;
698 0 : if (!was_last_key)
699 0 : insert_last=0;
700 0 : next_page= _ma_kpos(page.node, keypos);
701 0 : if (next_page == HA_OFFSET_ERROR ||
702 : (error= w_search(info, comp_flag, key, next_page,
703 : &page, keypos, insert_last)) > 0)
704 : {
705 0 : error= _ma_insert(info, key, &page, keypos, keybuff,
706 : father_page, father_keypos, insert_last);
707 0 : page_mark_changed(info, &page);
708 0 : if (_ma_write_keypage(&page, PAGECACHE_LOCK_LEFT_WRITELOCKED,
709 : DFLT_INIT_HITS))
710 0 : goto err;
711 : }
712 : my_afree(temp_buff);
713 0 : DBUG_RETURN(error);
714 0 : err:
715 : my_afree(temp_buff);
716 0 : DBUG_PRINT("exit",("Error: %d",my_errno));
717 0 : DBUG_RETURN(-1);
718 : } /* w_search */
719 :
720 :
721 : /*
722 : Insert new key.
723 :
724 : SYNOPSIS
725 : _ma_insert()
726 : info Open table information.
727 : keyinfo Key definition information.
728 : key New key
729 : anc_page Key page (beginning)
730 : key_pos Position in key page where to insert.
731 : key_buff Copy of previous key if keys where packed.
732 : father_page position of parent key page in file.
733 : father_key_pos position in parent key page for balancing.
734 : insert_last If to append at end of page.
735 :
736 : DESCRIPTION
737 : Insert new key at right of key_pos.
738 : Note that caller must save anc_buff
739 :
740 : This function writes log records for all changed pages
741 : (Including anc_buff and father page)
742 :
743 : RETURN
744 : < 0 Error.
745 : 0 OK
746 : 1 If key contains key to upper level (from balance page)
747 : 2 If key contains key to upper level (from split space)
748 : */
749 :
750 : int _ma_insert(register MARIA_HA *info, MARIA_KEY *key,
751 : MARIA_PAGE *anc_page, uchar *key_pos, uchar *key_buff,
752 : MARIA_PAGE *father_page, uchar *father_key_pos,
753 : my_bool insert_last)
754 0 : {
755 : uint a_length, nod_flag, org_anc_length;
756 : int t_length;
757 : uchar *endpos, *prev_key, *anc_buff;
758 : MARIA_KEY_PARAM s_temp;
759 0 : MARIA_SHARE *share= info->s;
760 0 : MARIA_KEYDEF *keyinfo= key->keyinfo;
761 0 : DBUG_ENTER("_ma_insert");
762 0 : DBUG_PRINT("enter",("key_pos: 0x%lx", (ulong) key_pos));
763 0 : DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, key););
764 :
765 0 : org_anc_length= a_length= anc_page->size;
766 0 : nod_flag= anc_page->node;
767 :
768 0 : anc_buff= anc_page->buff;
769 0 : endpos= anc_buff+ a_length;
770 0 : prev_key= (key_pos == anc_buff + share->keypage_header + nod_flag ?
771 : (uchar*) 0 : key_buff);
772 0 : t_length= (*keyinfo->pack_key)(key, nod_flag,
773 : (key_pos == endpos ? (uchar*) 0 : key_pos),
774 : prev_key, prev_key, &s_temp);
775 : #ifndef DBUG_OFF
776 0 : if (prev_key && (keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
777 : {
778 0 : DBUG_DUMP("prev_key", prev_key, _ma_keylength(keyinfo,prev_key));
779 : }
780 0 : if (keyinfo->flag & HA_PACK_KEY)
781 : {
782 0 : DBUG_PRINT("test",("t_length: %d ref_len: %d",
783 : t_length,s_temp.ref_length));
784 0 : DBUG_PRINT("test",("n_ref_len: %d n_length: %d key_pos: 0x%lx",
785 : s_temp.n_ref_length, s_temp.n_length, (long) s_temp.key));
786 : }
787 : #endif
788 0 : if (t_length > 0)
789 : {
790 0 : if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
791 : {
792 0 : my_errno=HA_ERR_CRASHED;
793 0 : DBUG_RETURN(-1);
794 : }
795 0 : bmove_upp(endpos+t_length, endpos, (uint) (endpos-key_pos));
796 : }
797 : else
798 : {
799 0 : if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
800 : {
801 0 : my_errno=HA_ERR_CRASHED;
802 0 : DBUG_RETURN(-1);
803 : }
804 0 : bmove(key_pos,key_pos-t_length,(uint) (endpos-key_pos)+t_length);
805 : }
806 0 : (*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
807 0 : a_length+=t_length;
808 :
809 0 : if (key->flag & (SEARCH_USER_KEY_HAS_TRANSID | SEARCH_PAGE_KEY_HAS_TRANSID))
810 : {
811 0 : _ma_mark_page_with_transid(share, anc_page);
812 : }
813 0 : anc_page->size= a_length;
814 0 : page_store_size(share, anc_page);
815 :
816 : /*
817 : Check if the new key fits totally into the the page
818 : (anc_buff is big enough to contain a full page + one key)
819 : */
820 0 : if (a_length <= (uint) keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE)
821 : {
822 0 : if (keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE - a_length < 32 &&
823 : (keyinfo->flag & HA_FULLTEXT) && key_pos == endpos &&
824 : share->base.key_reflength <= share->base.rec_reflength &&
825 : share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))
826 : {
827 : /*
828 : Normal word. One-level tree. Page is almost full.
829 : Let's consider converting.
830 : We'll compare 'key' and the first key at anc_buff
831 : */
832 0 : const uchar *a= key->data;
833 0 : const uchar *b= anc_buff + share->keypage_header + nod_flag;
834 0 : uint alen, blen, ft2len= share->ft2_keyinfo.keylength;
835 : /* the very first key on the page is always unpacked */
836 0 : DBUG_ASSERT((*b & 128) == 0);
837 : #if HA_FT_MAXLEN >= 127
838 : blen= mi_uint2korr(b); b+=2;
839 : When you enable this code, as part of the MyISAM->Maria merge of
840 : ChangeSet@1.2562, 2008-04-09 07:41:40+02:00, serg@janus.mylan +9 -0
841 : restore ft2 functionality, fix bugs.
842 : Then this will enable two-level fulltext index, which is not totally
843 : recoverable yet.
844 : So remove this text and inform Guilhem so that he fixes the issue.
845 : #else
846 0 : blen= *b++;
847 : #endif
848 0 : get_key_length(alen,a);
849 0 : DBUG_ASSERT(info->ft1_to_ft2==0);
850 0 : if (alen == blen &&
851 : ha_compare_text(keyinfo->seg->charset, a, alen,
852 : b, blen, 0, 0) == 0)
853 : {
854 : /* Yup. converting */
855 0 : info->ft1_to_ft2=(DYNAMIC_ARRAY *)
856 : my_malloc(sizeof(DYNAMIC_ARRAY), MYF(MY_WME));
857 0 : my_init_dynamic_array(info->ft1_to_ft2, ft2len, 300, 50);
858 :
859 : /*
860 : Now, adding all keys from the page to dynarray
861 : if the page is a leaf (if not keys will be deleted later)
862 : */
863 0 : if (!nod_flag)
864 : {
865 : /*
866 : Let's leave the first key on the page, though, because
867 : we cannot easily dispatch an empty page here
868 : */
869 0 : b+=blen+ft2len+2;
870 0 : for (a=anc_buff+a_length ; b < a ; b+=ft2len+2)
871 0 : insert_dynamic(info->ft1_to_ft2, b);
872 :
873 : /* fixing the page's length - it contains only one key now */
874 0 : anc_page->size= share->keypage_header + blen + ft2len + 2;
875 0 : page_store_size(share, anc_page);
876 : }
877 : /* the rest will be done when we're back from recursion */
878 : }
879 : }
880 : else
881 : {
882 0 : if (share->now_transactional &&
883 : _ma_log_add(anc_page, org_anc_length,
884 : key_pos, s_temp.changed_length, t_length, 0))
885 0 : DBUG_RETURN(-1);
886 : }
887 0 : DBUG_RETURN(0); /* There is room on page */
888 : }
889 : /* Page is full */
890 0 : if (nod_flag)
891 0 : insert_last=0;
892 : /*
893 : TODO:
894 : Remove 'born_transactional' here.
895 : The only reason for having it here is that the current
896 : _ma_balance_page_ can't handle variable length keys.
897 : */
898 0 : if (!(keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)) &&
899 : father_page && !insert_last && !info->quick_mode &&
900 : !info->s->base.born_transactional)
901 : {
902 0 : s_temp.key_pos= key_pos;
903 0 : page_mark_changed(info, father_page);
904 0 : DBUG_RETURN(_ma_balance_page(info, keyinfo, key, anc_page,
905 : father_page, father_key_pos,
906 : &s_temp));
907 : }
908 0 : DBUG_RETURN(_ma_split_page(info, key, anc_page, org_anc_length,
909 : key_pos, s_temp.changed_length, t_length,
910 : key_buff, insert_last));
911 : } /* _ma_insert */
912 :
913 :
914 : /**
915 : @brief split a full page in two and assign emerging item to key
916 :
917 : @fn _ma_split_page()
918 : info Maria handler
919 : keyinfo Key handler
920 : key Buffer for middle key
921 : split_page Page that should be split
922 : org_split_length Original length of split_page before key was inserted
923 : inserted_key_pos Address in buffer where key was inserted
924 : changed_length Number of bytes changed at 'inserted_key_pos'
925 : move_length Number of bytes buffer was moved when key was inserted
926 : key_buff Key buffer to use for temporary storage of key
927 : insert_last_key If we are insert key on rightmost key page
928 :
929 : @note
930 : split_buff is not stored on disk (caller has to do this)
931 :
932 : @return
933 : @retval 2 ok (Middle key up from _ma_insert())
934 : @retval -1 error
935 : */
936 :
937 : int _ma_split_page(MARIA_HA *info, MARIA_KEY *key, MARIA_PAGE *split_page,
938 : uint org_split_length,
939 : uchar *inserted_key_pos, uint changed_length,
940 : int move_length,
941 : uchar *key_buff, my_bool insert_last_key)
942 0 : {
943 : uint length,a_length,key_ref_length,t_length,nod_flag,key_length;
944 : uint page_length, split_length, page_flag;
945 : uchar *key_pos,*pos, *after_key;
946 : MARIA_KEY_PARAM s_temp;
947 0 : MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
948 0 : MARIA_SHARE *share= info->s;
949 0 : MARIA_KEYDEF *keyinfo= key->keyinfo;
950 : MARIA_KEY tmp_key;
951 : MARIA_PAGE new_page;
952 : int res;
953 0 : DBUG_ENTER("_ma_split_page");
954 :
955 0 : LINT_INIT(after_key);
956 0 : DBUG_DUMP("buff", split_page->buff, split_page->size);
957 :
958 0 : info->page_changed=1; /* Info->buff is used */
959 0 : info->keyread_buff_used=1;
960 0 : page_flag= split_page->flag;
961 0 : nod_flag= split_page->node;
962 0 : key_ref_length= share->keypage_header + nod_flag;
963 :
964 0 : new_page.info= info;
965 0 : new_page.buff= info->buff;
966 0 : new_page.keyinfo= keyinfo;
967 :
968 0 : tmp_key.data= key_buff;
969 0 : tmp_key.keyinfo= keyinfo;
970 0 : if (insert_last_key)
971 0 : key_pos= _ma_find_last_pos(&tmp_key, split_page, &after_key);
972 : else
973 0 : key_pos= _ma_find_half_pos(&tmp_key, split_page, &after_key);
974 0 : if (!key_pos)
975 0 : DBUG_RETURN(-1);
976 :
977 0 : key_length= tmp_key.data_length + tmp_key.ref_length;
978 0 : split_length= (uint) (key_pos - split_page->buff);
979 0 : a_length= split_page->size;
980 0 : split_page->size= split_length;
981 0 : page_store_size(share, split_page);
982 :
983 0 : key_pos=after_key;
984 0 : if (nod_flag)
985 : {
986 0 : DBUG_PRINT("test",("Splitting nod"));
987 0 : pos=key_pos-nod_flag;
988 0 : memcpy(new_page.buff + share->keypage_header, pos, (size_t) nod_flag);
989 : }
990 :
991 : /* Move middle item to key and pointer to new page */
992 0 : if ((new_page.pos= _ma_new(info, PAGECACHE_PRIORITY_HIGH, &page_link)) ==
993 : HA_OFFSET_ERROR)
994 0 : DBUG_RETURN(-1);
995 :
996 0 : _ma_copy_key(key, &tmp_key);
997 0 : _ma_kpointer(info, key->data + key_length, new_page.pos);
998 :
999 : /* Store new page */
1000 0 : if (!(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &key_pos))
1001 0 : DBUG_RETURN(-1);
1002 :
1003 0 : t_length=(*keyinfo->pack_key)(&tmp_key, nod_flag, (uchar *) 0,
1004 : (uchar*) 0, (uchar*) 0, &s_temp);
1005 0 : length=(uint) ((split_page->buff + a_length) - key_pos);
1006 0 : memcpy(new_page.buff + key_ref_length + t_length, key_pos,
1007 : (size_t) length);
1008 0 : (*keyinfo->store_key)(keyinfo,new_page.buff+key_ref_length,&s_temp);
1009 0 : page_length= length + t_length + key_ref_length;
1010 :
1011 0 : bzero(new_page.buff, share->keypage_header);
1012 : /* Copy KEYFLAG_FLAG_ISNODE and KEYPAGE_FLAG_HAS_TRANSID from parent page */
1013 0 : new_page.flag= page_flag;
1014 0 : new_page.size= page_length;
1015 0 : page_store_info(share, &new_page);
1016 :
1017 : /* Copy key number */
1018 0 : new_page.buff[share->keypage_header - KEYPAGE_USED_SIZE -
1019 : KEYPAGE_KEYID_SIZE - KEYPAGE_FLAG_SIZE]=
1020 : split_page->buff[share->keypage_header - KEYPAGE_USED_SIZE -
1021 : KEYPAGE_KEYID_SIZE - KEYPAGE_FLAG_SIZE];
1022 :
1023 0 : res= 2; /* Middle key up */
1024 0 : if (share->now_transactional && _ma_log_new(&new_page, 0))
1025 0 : res= -1;
1026 :
1027 : /*
1028 : Clear unitialized part of page to avoid valgrind/purify warnings
1029 : and to get a clean page that is easier to compress and compare with
1030 : pages generated with redo
1031 : */
1032 0 : bzero(new_page.buff + page_length, share->block_size - page_length);
1033 :
1034 0 : if (_ma_write_keypage(&new_page, page_link->write_lock,
1035 : DFLT_INIT_HITS))
1036 0 : res= -1;
1037 :
1038 : /* Save changes to split pages */
1039 0 : if (share->now_transactional &&
1040 : _ma_log_split(split_page, org_split_length, split_length,
1041 : inserted_key_pos, changed_length, move_length,
1042 : KEY_OP_NONE, (uchar*) 0, 0, 0))
1043 0 : res= -1;
1044 :
1045 0 : DBUG_DUMP_KEY("middle_key", key);
1046 0 : DBUG_RETURN(res);
1047 : } /* _ma_split_page */
1048 :
1049 :
1050 : /*
1051 : Calculate how to much to move to split a page in two
1052 :
1053 : Returns pointer to start of key.
1054 : key will contain the key.
1055 : return_key_length will contain the length of key
1056 : after_key will contain the position to where the next key starts
1057 : */
1058 :
1059 : uchar *_ma_find_half_pos(MARIA_KEY *key, MARIA_PAGE *ma_page,
1060 : uchar **after_key)
1061 0 : {
1062 : uint keys, length, key_ref_length, page_flag, nod_flag;
1063 : uchar *page, *end, *lastpos;
1064 0 : MARIA_HA *info= ma_page->info;
1065 0 : MARIA_SHARE *share= info->s;
1066 0 : MARIA_KEYDEF *keyinfo= key->keyinfo;
1067 0 : DBUG_ENTER("_ma_find_half_pos");
1068 :
1069 0 : nod_flag= ma_page->node;
1070 0 : key_ref_length= share->keypage_header + nod_flag;
1071 0 : page_flag= ma_page->flag;
1072 0 : length= ma_page->size - key_ref_length;
1073 0 : page= ma_page->buff+ key_ref_length; /* Point to first key */
1074 :
1075 0 : if (!(keyinfo->flag &
1076 : (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
1077 : HA_BINARY_PACK_KEY)) && !(page_flag & KEYPAGE_FLAG_HAS_TRANSID))
1078 : {
1079 0 : key_ref_length= keyinfo->keylength+nod_flag;
1080 0 : key->data_length= keyinfo->keylength - info->s->rec_reflength;
1081 0 : key->ref_length= info->s->rec_reflength;
1082 0 : key->flag= 0;
1083 0 : keys=length/(key_ref_length*2);
1084 0 : end=page+keys*key_ref_length;
1085 0 : *after_key=end+key_ref_length;
1086 0 : memcpy(key->data, end, key_ref_length);
1087 0 : DBUG_RETURN(end);
1088 : }
1089 :
1090 0 : end=page+length/2-key_ref_length; /* This is aprox. half */
1091 0 : key->data[0]= 0; /* Safety */
1092 : do
1093 : {
1094 0 : lastpos=page;
1095 0 : if (!(length= (*keyinfo->get_key)(key, page_flag, nod_flag, &page)))
1096 0 : DBUG_RETURN(0);
1097 0 : } while (page < end);
1098 0 : *after_key= page;
1099 0 : DBUG_PRINT("exit",("returns: 0x%lx page: 0x%lx half: 0x%lx",
1100 : (long) lastpos, (long) page, (long) end));
1101 0 : DBUG_RETURN(lastpos);
1102 : } /* _ma_find_half_pos */
1103 :
1104 :
1105 : /**
1106 : Find second to last key on leaf page
1107 :
1108 : @notes
1109 : Used to split buffer at last key. In this case the next to last
1110 : key will be moved to parent page and last key will be on it's own page.
1111 :
1112 : @TODO
1113 : Add one argument for 'last key value' to get_key so that one can
1114 : do the loop without having to copy the found key the whole time
1115 :
1116 : @return
1117 : @retval Pointer to the start of the key before the last key
1118 : @retval int_key will contain the last key
1119 : */
1120 :
1121 : static uchar *_ma_find_last_pos(MARIA_KEY *int_key, MARIA_PAGE *ma_page,
1122 : uchar **after_key)
1123 0 : {
1124 : uint keys, length, key_ref_length, page_flag;
1125 : uchar *page, *end, *lastpos, *prevpos;
1126 : uchar key_buff[MARIA_MAX_KEY_BUFF];
1127 0 : MARIA_HA *info= ma_page->info;
1128 0 : MARIA_SHARE *share= info->s;
1129 0 : MARIA_KEYDEF *keyinfo= int_key->keyinfo;
1130 : MARIA_KEY tmp_key;
1131 0 : DBUG_ENTER("_ma_find_last_pos");
1132 :
1133 0 : key_ref_length= share->keypage_header;
1134 0 : page_flag= ma_page->flag;
1135 0 : length= ma_page->size - key_ref_length;
1136 0 : page= ma_page->buff + key_ref_length;
1137 :
1138 0 : if (!(keyinfo->flag &
1139 : (HA_PACK_KEY | HA_SPACE_PACK_USED | HA_VAR_LENGTH_KEY |
1140 : HA_BINARY_PACK_KEY)) && !(page_flag & KEYPAGE_FLAG_HAS_TRANSID))
1141 : {
1142 0 : keys= length / keyinfo->keylength - 2;
1143 0 : length= keyinfo->keylength;
1144 0 : int_key->data_length= length - info->s->rec_reflength;
1145 0 : int_key->ref_length= info->s->rec_reflength;
1146 0 : int_key->flag= 0;
1147 0 : end=page+keys*length;
1148 0 : *after_key=end+length;
1149 0 : memcpy(int_key->data, end, length);
1150 0 : DBUG_RETURN(end);
1151 : }
1152 :
1153 0 : end=page+length-key_ref_length;
1154 0 : lastpos=page;
1155 0 : tmp_key.data= key_buff;
1156 0 : tmp_key.keyinfo= int_key->keyinfo;
1157 0 : key_buff[0]= 0; /* Safety */
1158 :
1159 : /* We know that there are at least 2 keys on the page */
1160 :
1161 0 : if (!(length=(*keyinfo->get_key)(&tmp_key, page_flag, 0, &page)))
1162 : {
1163 0 : my_errno=HA_ERR_CRASHED;
1164 0 : DBUG_RETURN(0);
1165 : }
1166 :
1167 : do
1168 : {
1169 0 : prevpos=lastpos; lastpos=page;
1170 0 : int_key->data_length= tmp_key.data_length;
1171 0 : int_key->ref_length= tmp_key.ref_length;
1172 0 : int_key->flag= tmp_key.flag;
1173 0 : memcpy(int_key->data, key_buff, length); /* previous key */
1174 0 : if (!(length=(*keyinfo->get_key)(&tmp_key, page_flag, 0, &page)))
1175 : {
1176 0 : my_errno=HA_ERR_CRASHED;
1177 0 : DBUG_RETURN(0);
1178 : }
1179 0 : } while (page < end);
1180 :
1181 0 : *after_key=lastpos;
1182 0 : DBUG_PRINT("exit",("returns: 0x%lx page: 0x%lx end: 0x%lx",
1183 : (long) prevpos,(long) page,(long) end));
1184 0 : DBUG_RETURN(prevpos);
1185 : } /* _ma_find_last_pos */
1186 :
1187 :
1188 : /**
1189 : @brief Balance page with static size keys with page on right/left
1190 :
1191 : @param key Middle key will be stored here
1192 :
1193 : @notes
1194 : Father_buff will always be changed
1195 : Caller must handle saving of curr_buff
1196 :
1197 : @return
1198 : @retval 0 Balance was done (father buff is saved)
1199 : @retval 1 Middle key up (father buff is not saved)
1200 : @retval -1 Error
1201 : */
1202 :
1203 : static int _ma_balance_page(MARIA_HA *info, MARIA_KEYDEF *keyinfo,
1204 : MARIA_KEY *key, MARIA_PAGE *curr_page,
1205 : MARIA_PAGE *father_page,
1206 : uchar *father_key_pos, MARIA_KEY_PARAM *s_temp)
1207 0 : {
1208 0 : MARIA_PINNED_PAGE tmp_page_link, *new_page_link= &tmp_page_link;
1209 0 : MARIA_SHARE *share= info->s;
1210 : my_bool right;
1211 : uint k_length,father_length,father_keylength,nod_flag,curr_keylength;
1212 : uint right_length,left_length,new_right_length,new_left_length,extra_length;
1213 : uint keys, tmp_length, extra_buff_length;
1214 : uchar *pos, *extra_buff, *parting_key;
1215 : uchar tmp_part_key[MARIA_MAX_KEY_BUFF];
1216 : MARIA_PAGE next_page, extra_page, *left_page, *right_page;
1217 0 : DBUG_ENTER("_ma_balance_page");
1218 :
1219 0 : k_length= keyinfo->keylength;
1220 0 : father_length= father_page->size;
1221 0 : father_keylength= k_length + share->base.key_reflength;
1222 0 : nod_flag= curr_page->node;
1223 0 : curr_keylength= k_length+nod_flag;
1224 0 : info->page_changed=1;
1225 :
1226 0 : if ((father_key_pos != father_page->buff+father_length &&
1227 : (info->state->records & 1)) ||
1228 : father_key_pos == father_page->buff+ share->keypage_header +
1229 : share->base.key_reflength)
1230 : {
1231 0 : right=1;
1232 0 : next_page.pos= _ma_kpos(share->base.key_reflength,
1233 : father_key_pos+father_keylength);
1234 0 : left_page= curr_page;
1235 0 : right_page= &next_page;
1236 0 : DBUG_PRINT("info", ("use right page: %lu", (ulong) next_page.pos));
1237 : }
1238 : else
1239 : {
1240 0 : right=0;
1241 0 : father_key_pos-=father_keylength;
1242 0 : next_page.pos= _ma_kpos(share->base.key_reflength,father_key_pos);
1243 0 : left_page= &next_page;
1244 0 : right_page= curr_page;
1245 0 : DBUG_PRINT("info", ("use left page: %lu", (ulong) next_page.pos));
1246 : } /* father_key_pos ptr to parting key */
1247 :
1248 0 : if (_ma_fetch_keypage(&next_page, info, keyinfo, next_page.pos,
1249 : PAGECACHE_LOCK_WRITE,
1250 : DFLT_INIT_HITS, info->buff, 0))
1251 0 : goto err;
1252 0 : page_mark_changed(info, &next_page);
1253 0 : DBUG_DUMP("next", next_page.buff, next_page.size);
1254 :
1255 : /* Test if there is room to share keys */
1256 0 : left_length= left_page->size;
1257 0 : right_length= right_page->size;
1258 0 : keys= ((left_length+right_length-share->keypage_header*2-nod_flag*2)/
1259 : curr_keylength);
1260 :
1261 0 : if ((right ? right_length : left_length) + curr_keylength <=
1262 : (uint) keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE)
1263 : {
1264 : /* Enough space to hold all keys in the two buffers ; Balance bufferts */
1265 0 : new_left_length= share->keypage_header+nod_flag+(keys/2)*curr_keylength;
1266 0 : new_right_length=share->keypage_header+nod_flag+(((keys+1)/2)*
1267 : curr_keylength);
1268 0 : left_page->size= new_left_length;
1269 0 : page_store_size(share, left_page);
1270 0 : right_page->size= new_right_length;
1271 0 : page_store_size(share, right_page);
1272 :
1273 0 : DBUG_PRINT("info", ("left_length: %u -> %u right_length: %u -> %u",
1274 : left_length, new_left_length,
1275 : right_length, new_right_length));
1276 0 : if (left_length < new_left_length)
1277 : {
1278 : uint length;
1279 0 : DBUG_PRINT("info", ("move keys to end of buff"));
1280 :
1281 : /* Move keys right_page -> left_page */
1282 0 : pos= left_page->buff+left_length;
1283 0 : memcpy(pos,father_key_pos, (size_t) k_length);
1284 0 : memcpy(pos+k_length, right_page->buff + share->keypage_header,
1285 : (size_t) (length=new_left_length - left_length - k_length));
1286 0 : pos= right_page->buff + share->keypage_header + length;
1287 0 : memcpy(father_key_pos, pos, (size_t) k_length);
1288 0 : bmove(right_page->buff + share->keypage_header,
1289 : pos + k_length, new_right_length);
1290 :
1291 0 : if (share->now_transactional)
1292 : {
1293 0 : if (right)
1294 : {
1295 : /*
1296 : Log changes to page on left
1297 : The original page is on the left and stored in left_page->buff
1298 : We have on the page the newly inserted key and data
1299 : from buff added last on the page
1300 : */
1301 0 : if (_ma_log_split(curr_page,
1302 : left_length - s_temp->move_length,
1303 : new_left_length,
1304 : s_temp->key_pos, s_temp->changed_length,
1305 : s_temp->move_length,
1306 : KEY_OP_ADD_SUFFIX,
1307 : curr_page->buff + left_length,
1308 : new_left_length - left_length,
1309 : new_left_length - left_length+ k_length))
1310 0 : goto err;
1311 : /*
1312 : Log changes to page on right
1313 : This contains the original data with some keys deleted from
1314 : start of page
1315 : */
1316 0 : if (_ma_log_prefix(&next_page, 0,
1317 : ((int) new_right_length - (int) right_length)))
1318 : goto err;
1319 : }
1320 : else
1321 : {
1322 : /*
1323 : Log changes to page on right (the original page) which is in buff
1324 : Data is removed from start of page
1325 : The inserted key may be in buff or moved to curr_buff
1326 : */
1327 0 : if (_ma_log_del_prefix(curr_page,
1328 : right_length - s_temp->changed_length,
1329 : new_right_length,
1330 : s_temp->key_pos, s_temp->changed_length,
1331 : s_temp->move_length))
1332 0 : goto err;
1333 : /*
1334 : Log changes to page on left, which has new data added last
1335 : */
1336 0 : if (_ma_log_suffix(&next_page, left_length, new_left_length))
1337 : goto err;
1338 : }
1339 : }
1340 : }
1341 : else
1342 : {
1343 : uint length;
1344 0 : DBUG_PRINT("info", ("move keys to start of right_page"));
1345 :
1346 0 : bmove_upp(right_page->buff + new_right_length,
1347 : right_page->buff + right_length,
1348 : right_length - share->keypage_header);
1349 0 : length= new_right_length -right_length - k_length;
1350 0 : memcpy(right_page->buff + share->keypage_header + length, father_key_pos,
1351 : (size_t) k_length);
1352 0 : pos= left_page->buff + new_left_length;
1353 0 : memcpy(father_key_pos, pos, (size_t) k_length);
1354 0 : memcpy(right_page->buff + share->keypage_header, pos+k_length,
1355 : (size_t) length);
1356 :
1357 0 : if (share->now_transactional)
1358 : {
1359 0 : if (right)
1360 : {
1361 : /*
1362 : Log changes to page on left
1363 : The original page is on the left and stored in curr_buff
1364 : The page is shortened from end and the key may be on the page
1365 : */
1366 0 : if (_ma_log_split(curr_page,
1367 : left_length - s_temp->move_length,
1368 : new_left_length,
1369 : s_temp->key_pos, s_temp->changed_length,
1370 : s_temp->move_length,
1371 : KEY_OP_NONE, (uchar*) 0, 0, 0))
1372 0 : goto err;
1373 : /*
1374 : Log changes to page on right
1375 : This contains the original data, with some data from cur_buff
1376 : added first
1377 : */
1378 0 : if (_ma_log_prefix(&next_page,
1379 : (uint) (new_right_length - right_length),
1380 : (int) (new_right_length - right_length)))
1381 : goto err;
1382 : }
1383 : else
1384 : {
1385 : /*
1386 : Log changes to page on right (the original page) which is in buff
1387 : We have on the page the newly inserted key and data
1388 : from buff added first on the page
1389 : */
1390 0 : uint diff_length= new_right_length - right_length;
1391 0 : if (_ma_log_split(curr_page,
1392 : left_length - s_temp->move_length,
1393 : new_right_length,
1394 : s_temp->key_pos + diff_length,
1395 : s_temp->changed_length,
1396 : s_temp->move_length,
1397 : KEY_OP_ADD_PREFIX,
1398 : curr_page->buff + share->keypage_header,
1399 : diff_length, diff_length + k_length))
1400 0 : goto err;
1401 : /*
1402 : Log changes to page on left, which is shortened from end
1403 : */
1404 0 : if (_ma_log_suffix(&next_page, left_length, new_left_length))
1405 0 : goto err;
1406 : }
1407 : }
1408 : }
1409 :
1410 : /* Log changes to father (one level up) page */
1411 :
1412 0 : if (share->now_transactional &&
1413 : _ma_log_change(father_page, father_key_pos, k_length))
1414 0 : goto err;
1415 :
1416 : /*
1417 : next_page_link->changed is marked as true above and fathers
1418 : page_link->changed is marked as true in caller
1419 : */
1420 0 : if (_ma_write_keypage(&next_page, PAGECACHE_LOCK_LEFT_WRITELOCKED,
1421 : DFLT_INIT_HITS) ||
1422 : _ma_write_keypage(father_page,
1423 : PAGECACHE_LOCK_LEFT_WRITELOCKED, DFLT_INIT_HITS))
1424 : goto err;
1425 0 : DBUG_RETURN(0);
1426 : }
1427 :
1428 : /* left_page and right_page are full, lets split and make new nod */
1429 :
1430 0 : extra_buff= info->buff+share->base.max_key_block_length;
1431 0 : new_left_length= new_right_length= (share->keypage_header + nod_flag +
1432 : (keys+1) / 3 * curr_keylength);
1433 0 : extra_page.info= info;
1434 0 : extra_page.keyinfo= keyinfo;
1435 0 : extra_page.buff= extra_buff;
1436 :
1437 : /*
1438 : 5 is the minum number of keys we can have here. This comes from
1439 : the fact that each full page can store at least 2 keys and in this case
1440 : we have a 'split' key, ie 2+2+1 = 5
1441 : */
1442 0 : if (keys == 5) /* Too few keys to balance */
1443 0 : new_left_length-=curr_keylength;
1444 0 : extra_length= (nod_flag + left_length + right_length -
1445 : new_left_length - new_right_length - curr_keylength);
1446 0 : extra_buff_length= extra_length + share->keypage_header;
1447 0 : DBUG_PRINT("info",("left_length: %d right_length: %d new_left_length: %d new_right_length: %d extra_length: %d",
1448 : left_length, right_length,
1449 : new_left_length, new_right_length,
1450 : extra_length));
1451 :
1452 0 : left_page->size= new_left_length;
1453 0 : page_store_size(share, left_page);
1454 0 : right_page->size= new_right_length;
1455 0 : page_store_size(share, right_page);
1456 :
1457 0 : bzero(extra_buff, share->keypage_header);
1458 0 : extra_page.flag= nod_flag ? KEYPAGE_FLAG_ISNOD : 0;
1459 0 : extra_page.size= extra_buff_length;
1460 0 : page_store_info(share, &extra_page);
1461 :
1462 : /* Copy key number */
1463 0 : extra_buff[share->keypage_header - KEYPAGE_USED_SIZE - KEYPAGE_KEYID_SIZE -
1464 : KEYPAGE_FLAG_SIZE]= keyinfo->key_nr;
1465 :
1466 : /* move first largest keys to new page */
1467 0 : pos= right_page->buff + right_length-extra_length;
1468 0 : memcpy(extra_buff + share->keypage_header, pos, extra_length);
1469 : /* Zero old data from buffer */
1470 0 : bzero(extra_buff + extra_buff_length,
1471 : share->block_size - extra_buff_length);
1472 :
1473 : /* Save new parting key between buff and extra_buff */
1474 0 : memcpy(tmp_part_key, pos-k_length,k_length);
1475 : /* Make place for new keys */
1476 0 : bmove_upp(right_page->buff + new_right_length, pos - k_length,
1477 : right_length - extra_length - k_length - share->keypage_header);
1478 : /* Copy keys from left page */
1479 0 : pos= left_page->buff + new_left_length;
1480 0 : memcpy(right_page->buff + share->keypage_header, pos + k_length,
1481 : (size_t) (tmp_length= left_length - new_left_length - k_length));
1482 : /* Copy old parting key */
1483 0 : parting_key= right_page->buff + share->keypage_header + tmp_length;
1484 0 : memcpy(parting_key, father_key_pos, (size_t) k_length);
1485 :
1486 : /* Move new parting keys up to caller */
1487 0 : memcpy((right ? key->data : father_key_pos),pos,(size_t) k_length);
1488 0 : memcpy((right ? father_key_pos : key->data),tmp_part_key, k_length);
1489 :
1490 0 : if ((extra_page.pos= _ma_new(info, DFLT_INIT_HITS, &new_page_link))
1491 : == HA_OFFSET_ERROR)
1492 0 : goto err;
1493 0 : _ma_kpointer(info,key->data+k_length, extra_page.pos);
1494 : /* This is safe as long we are using not keys with transid */
1495 0 : key->data_length= k_length - info->s->rec_reflength;
1496 0 : key->ref_length= info->s->rec_reflength;
1497 :
1498 0 : if (right)
1499 : {
1500 : /*
1501 : Page order according to key values:
1502 : orignal_page (curr_page = left_page), next_page (buff), extra_buff
1503 :
1504 : Move page positions so that we store data in extra_page where
1505 : next_page was and next_page will be stored at the new position
1506 : */
1507 0 : swap_variables(my_off_t, extra_page.pos, next_page.pos);
1508 : }
1509 :
1510 0 : if (share->now_transactional)
1511 : {
1512 0 : if (right)
1513 : {
1514 : /*
1515 : left_page is shortened,
1516 : right_page is getting new keys at start and shortened from end.
1517 : extra_page is new page
1518 :
1519 : Note that extra_page (largest key parts) will be stored at the
1520 : place of the original 'right' page (next_page) and right page
1521 : will be stored at the new page position
1522 :
1523 : This makes the log entries smaller as right_page contains all
1524 : data to generate the data extra_buff
1525 : */
1526 :
1527 : /*
1528 : Log changes to page on left (page shortened page at end)
1529 : */
1530 0 : if (_ma_log_split(curr_page,
1531 : left_length - s_temp->move_length, new_left_length,
1532 : s_temp->key_pos, s_temp->changed_length,
1533 : s_temp->move_length,
1534 : KEY_OP_NONE, (uchar*) 0, 0, 0))
1535 0 : goto err;
1536 : /*
1537 : Log changes to right page (stored at next page)
1538 : This contains the last 'extra_buff' from 'buff'
1539 : */
1540 0 : if (_ma_log_prefix(&extra_page,
1541 : 0, (int) (extra_buff_length - right_length)))
1542 0 : goto err;
1543 :
1544 : /*
1545 : Log changes to middle page, which is stored at the new page
1546 : position
1547 : */
1548 0 : if (_ma_log_new(&next_page, 0))
1549 : goto err;
1550 : }
1551 : else
1552 : {
1553 : /*
1554 : Log changes to page on right (the original page) which is in buff
1555 : This contains the original data, with some data from curr_buff
1556 : added first and shortened at end
1557 : */
1558 0 : int data_added_first= left_length - new_left_length;
1559 0 : if (_ma_log_key_middle(right_page,
1560 : new_right_length,
1561 : data_added_first,
1562 : data_added_first,
1563 : extra_length,
1564 : s_temp->key_pos,
1565 : s_temp->changed_length,
1566 : s_temp->move_length))
1567 0 : goto err;
1568 :
1569 : /* Log changes to page on left, which is shortened from end */
1570 0 : if (_ma_log_suffix(left_page, left_length, new_left_length))
1571 0 : goto err;
1572 :
1573 : /* Log change to rightmost (new) page */
1574 0 : if (_ma_log_new(&extra_page, 0))
1575 0 : goto err;
1576 : }
1577 :
1578 : /* Log changes to father (one level up) page */
1579 0 : if (share->now_transactional &&
1580 : _ma_log_change(father_page, father_key_pos, k_length))
1581 0 : goto err;
1582 : }
1583 :
1584 0 : if (_ma_write_keypage(&next_page,
1585 : (right ? new_page_link->write_lock :
1586 : PAGECACHE_LOCK_LEFT_WRITELOCKED),
1587 : DFLT_INIT_HITS) ||
1588 : _ma_write_keypage(&extra_page,
1589 : (!right ? new_page_link->write_lock :
1590 : PAGECACHE_LOCK_LEFT_WRITELOCKED),
1591 : DFLT_INIT_HITS))
1592 : goto err;
1593 :
1594 0 : DBUG_RETURN(1); /* Middle key up */
1595 :
1596 0 : err:
1597 0 : DBUG_RETURN(-1);
1598 : } /* _ma_balance_page */
1599 :
1600 :
1601 : /**********************************************************************
1602 : * Bulk insert code *
1603 : **********************************************************************/
1604 :
1605 : typedef struct {
1606 : MARIA_HA *info;
1607 : uint keynr;
1608 : } bulk_insert_param;
1609 :
1610 :
1611 : static my_bool _ma_ck_write_tree(register MARIA_HA *info, MARIA_KEY *key)
1612 0 : {
1613 : my_bool error;
1614 0 : uint keynr= key->keyinfo->key_nr;
1615 0 : DBUG_ENTER("_ma_ck_write_tree");
1616 :
1617 : /* Store ref_length as this is always constant */
1618 0 : info->bulk_insert_ref_length= key->ref_length;
1619 0 : error= tree_insert(&info->bulk_insert[keynr], key->data,
1620 : key->data_length + key->ref_length,
1621 : info->bulk_insert[keynr].custom_arg) == 0;
1622 0 : DBUG_RETURN(error);
1623 : } /* _ma_ck_write_tree */
1624 :
1625 :
1626 : /* typeof(_ma_keys_compare)=qsort_cmp2 */
1627 :
1628 : static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2)
1629 0 : {
1630 : uint not_used[2];
1631 0 : return ha_key_cmp(param->info->s->keyinfo[param->keynr].seg,
1632 : key1, key2, USE_WHOLE_KEY, SEARCH_SAME,
1633 : not_used);
1634 : }
1635 :
1636 :
1637 : static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param)
1638 0 : {
1639 : /*
1640 : Probably I can use info->lastkey here, but I'm not sure,
1641 : and to be safe I'd better use local lastkey.
1642 : */
1643 0 : MARIA_SHARE *share= param->info->s;
1644 : uchar lastkey[MARIA_MAX_KEY_BUFF];
1645 : uint keylen;
1646 0 : MARIA_KEYDEF *keyinfo= share->keyinfo + param->keynr;
1647 : MARIA_KEY tmp_key;
1648 :
1649 0 : switch (mode) {
1650 : case free_init:
1651 0 : if (share->lock_key_trees)
1652 : {
1653 0 : rw_wrlock(&keyinfo->root_lock);
1654 0 : keyinfo->version++;
1655 : }
1656 0 : return 0;
1657 : case free_free:
1658 : /* Note: keylen doesn't contain transid lengths */
1659 0 : keylen= _ma_keylength(keyinfo, key);
1660 0 : tmp_key.data= lastkey;
1661 0 : tmp_key.keyinfo= keyinfo;
1662 0 : tmp_key.data_length= keylen - share->rec_reflength;
1663 0 : tmp_key.ref_length= param->info->bulk_insert_ref_length;
1664 0 : tmp_key.flag= (param->info->bulk_insert_ref_length ==
1665 : share->rec_reflength ? 0 : SEARCH_USER_KEY_HAS_TRANSID);
1666 : /*
1667 : We have to copy key as ma_ck_write_btree may need the buffer for
1668 : copying middle key up if tree is growing
1669 : */
1670 0 : memcpy(lastkey, key, tmp_key.data_length + tmp_key.ref_length);
1671 0 : return _ma_ck_write_btree(param->info, &tmp_key);
1672 : case free_end:
1673 0 : if (share->lock_key_trees)
1674 0 : rw_unlock(&keyinfo->root_lock);
1675 0 : return 0;
1676 : }
1677 0 : return 1;
1678 : }
1679 :
1680 :
1681 : int maria_init_bulk_insert(MARIA_HA *info, ulong cache_size, ha_rows rows)
1682 0 : {
1683 0 : MARIA_SHARE *share= info->s;
1684 0 : MARIA_KEYDEF *key=share->keyinfo;
1685 : bulk_insert_param *params;
1686 : uint i, num_keys, total_keylength;
1687 : ulonglong key_map;
1688 0 : DBUG_ENTER("_ma_init_bulk_insert");
1689 0 : DBUG_PRINT("enter",("cache_size: %lu", cache_size));
1690 :
1691 0 : DBUG_ASSERT(!info->bulk_insert &&
1692 : (!rows || rows >= MARIA_MIN_ROWS_TO_USE_BULK_INSERT));
1693 :
1694 0 : maria_clear_all_keys_active(key_map);
1695 0 : for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++)
1696 : {
1697 0 : if (! (key[i].flag & HA_NOSAME) && (share->base.auto_key != i + 1) &&
1698 : maria_is_key_active(share->state.key_map, i))
1699 : {
1700 0 : num_keys++;
1701 0 : maria_set_key_active(key_map, i);
1702 0 : total_keylength+=key[i].maxlength+TREE_ELEMENT_EXTRA_SIZE;
1703 : }
1704 : }
1705 :
1706 0 : if (num_keys==0 ||
1707 : num_keys * MARIA_MIN_SIZE_BULK_INSERT_TREE > cache_size)
1708 0 : DBUG_RETURN(0);
1709 :
1710 0 : if (rows && rows*total_keylength < cache_size)
1711 0 : cache_size= (ulong)rows;
1712 : else
1713 0 : cache_size/=total_keylength*16;
1714 :
1715 0 : info->bulk_insert=(TREE *)
1716 : my_malloc((sizeof(TREE)*share->base.keys+
1717 : sizeof(bulk_insert_param)*num_keys),MYF(0));
1718 :
1719 0 : if (!info->bulk_insert)
1720 0 : DBUG_RETURN(HA_ERR_OUT_OF_MEM);
1721 :
1722 0 : params=(bulk_insert_param *)(info->bulk_insert+share->base.keys);
1723 0 : for (i=0 ; i < share->base.keys ; i++)
1724 : {
1725 0 : if (maria_is_key_active(key_map, i))
1726 : {
1727 0 : params->info=info;
1728 0 : params->keynr=i;
1729 : /* Only allocate a 16'th of the buffer at a time */
1730 0 : init_tree(&info->bulk_insert[i],
1731 : cache_size * key[i].maxlength,
1732 : cache_size * key[i].maxlength, 0,
1733 : (qsort_cmp2)keys_compare, 0,
1734 : (tree_element_free) keys_free, (void *)params++);
1735 : }
1736 : else
1737 0 : info->bulk_insert[i].root=0;
1738 : }
1739 :
1740 0 : DBUG_RETURN(0);
1741 : }
1742 :
1743 : void maria_flush_bulk_insert(MARIA_HA *info, uint inx)
1744 0 : {
1745 0 : if (info->bulk_insert)
1746 : {
1747 0 : if (is_tree_inited(&info->bulk_insert[inx]))
1748 0 : reset_tree(&info->bulk_insert[inx]);
1749 : }
1750 : }
1751 :
1752 : void maria_end_bulk_insert(MARIA_HA *info, my_bool abort)
1753 0 : {
1754 0 : DBUG_ENTER("maria_end_bulk_insert");
1755 0 : if (info->bulk_insert)
1756 : {
1757 : uint i;
1758 0 : for (i=0 ; i < info->s->base.keys ; i++)
1759 : {
1760 0 : if (is_tree_inited(&info->bulk_insert[i]))
1761 : {
1762 0 : if (abort)
1763 0 : reset_free_element(&info->bulk_insert[i]);
1764 0 : delete_tree(&info->bulk_insert[i]);
1765 : }
1766 : }
1767 0 : my_free(info->bulk_insert, MYF(0));
1768 0 : info->bulk_insert= 0;
1769 : }
1770 0 : DBUG_VOID_RETURN;
1771 : }
1772 :
1773 :
1774 : /****************************************************************************
1775 : Dedicated functions that generate log entries
1776 : ****************************************************************************/
1777 :
1778 :
1779 : int _ma_write_undo_key_insert(MARIA_HA *info, const MARIA_KEY *key,
1780 : my_off_t *root, my_off_t new_root, LSN *res_lsn)
1781 0 : {
1782 0 : MARIA_SHARE *share= info->s;
1783 0 : MARIA_KEYDEF *keyinfo= key->keyinfo;
1784 : uchar log_data[LSN_STORE_SIZE + FILEID_STORE_SIZE +
1785 : KEY_NR_STORE_SIZE];
1786 : const uchar *key_value;
1787 : LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
1788 : struct st_msg_to_write_hook_for_undo_key msg;
1789 : uint key_length;
1790 :
1791 : /* Save if we need to write a clr record */
1792 0 : lsn_store(log_data, info->trn->undo_lsn);
1793 0 : key_nr_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
1794 : keyinfo->key_nr);
1795 0 : key_length= key->data_length + key->ref_length;
1796 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
1797 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
1798 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key->data;
1799 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].length= key_length;
1800 :
1801 0 : msg.root= root;
1802 0 : msg.value= new_root;
1803 0 : msg.auto_increment= 0;
1804 0 : key_value= key->data;
1805 0 : if (share->base.auto_key == ((uint) keyinfo->key_nr + 1))
1806 : {
1807 0 : const HA_KEYSEG *keyseg= keyinfo->seg;
1808 : uchar reversed[MARIA_MAX_KEY_BUFF];
1809 0 : if (keyseg->flag & HA_SWAP_KEY)
1810 : {
1811 : /* We put key from log record to "data record" packing format... */
1812 0 : const uchar *key_ptr= key->data, *key_end= key->data + keyseg->length;
1813 0 : uchar *to= reversed + keyseg->length;
1814 : do
1815 : {
1816 0 : *--to= *key_ptr++;
1817 0 : } while (key_ptr != key_end);
1818 0 : key_value= to;
1819 : }
1820 : /* ... so that we can read it with: */
1821 0 : msg.auto_increment=
1822 : ma_retrieve_auto_increment(key_value, keyseg->type);
1823 : /* and write_hook_for_undo_key_insert() will pick this. */
1824 : }
1825 :
1826 0 : return translog_write_record(res_lsn, LOGREC_UNDO_KEY_INSERT,
1827 : info->trn, info,
1828 : (translog_size_t)
1829 : log_array[TRANSLOG_INTERNAL_PARTS + 0].length +
1830 : key_length,
1831 : TRANSLOG_INTERNAL_PARTS + 2, log_array,
1832 : log_data + LSN_STORE_SIZE, &msg) ? -1 : 0;
1833 : }
1834 :
1835 :
1836 : /**
1837 : @brief Log creation of new page
1838 :
1839 : @note
1840 : We don't have to store the page_length into the log entry as we can
1841 : calculate this from the length of the log entry
1842 :
1843 : @retval 1 error
1844 : @retval 0 ok
1845 : */
1846 :
1847 : my_bool _ma_log_new(MARIA_PAGE *ma_page, my_bool root_page)
1848 0 : {
1849 : LSN lsn;
1850 : uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2 + KEY_NR_STORE_SIZE
1851 : +1];
1852 : uint page_length;
1853 : LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
1854 0 : MARIA_HA *info= ma_page->info;
1855 0 : MARIA_SHARE *share= info->s;
1856 : my_off_t page;
1857 0 : DBUG_ENTER("_ma_log_new");
1858 0 : DBUG_PRINT("enter", ("page: %lu", (ulong) ma_page->pos));
1859 :
1860 0 : DBUG_ASSERT(share->now_transactional);
1861 :
1862 : /* Store address of new root page */
1863 0 : page= ma_page->pos / share->block_size;
1864 0 : page_store(log_data + FILEID_STORE_SIZE, page);
1865 :
1866 : /* Store link to next unused page */
1867 0 : if (info->key_del_used == 2)
1868 0 : page= 0; /* key_del not changed */
1869 : else
1870 0 : page= ((share->key_del_current == HA_OFFSET_ERROR) ? IMPOSSIBLE_PAGE_NO :
1871 : share->key_del_current / share->block_size);
1872 :
1873 0 : page_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, page);
1874 0 : key_nr_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE*2,
1875 : ma_page->keyinfo->key_nr);
1876 0 : log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE*2 + KEY_NR_STORE_SIZE]=
1877 : (uchar) root_page;
1878 :
1879 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
1880 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
1881 :
1882 0 : page_length= ma_page->size - LSN_STORE_SIZE;
1883 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].str= ma_page->buff + LSN_STORE_SIZE;
1884 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].length= page_length;
1885 :
1886 0 : if (translog_write_record(&lsn, LOGREC_REDO_INDEX_NEW_PAGE,
1887 : info->trn, info,
1888 : (translog_size_t)
1889 : (sizeof(log_data) + page_length),
1890 : TRANSLOG_INTERNAL_PARTS + 2, log_array,
1891 : log_data, NULL))
1892 0 : DBUG_RETURN(1);
1893 0 : DBUG_RETURN(0);
1894 : }
1895 :
1896 :
1897 : /**
1898 : @brief
1899 : Log when some part of the key page changes
1900 : */
1901 :
1902 : my_bool _ma_log_change(MARIA_PAGE *ma_page,
1903 : const uchar *key_pos, uint length)
1904 0 : {
1905 : LSN lsn;
1906 : uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 6 + 7], *log_pos;
1907 : LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 3];
1908 0 : uint offset= (uint) (key_pos - ma_page->buff), translog_parts;
1909 0 : uint extra_length= 0;
1910 : my_off_t page;
1911 0 : MARIA_HA *info= ma_page->info;
1912 0 : DBUG_ENTER("_ma_log_change");
1913 0 : DBUG_PRINT("enter", ("page: %lu length: %u", (ulong) ma_page->pos, length));
1914 :
1915 0 : DBUG_ASSERT(info->s->now_transactional);
1916 :
1917 : /* Store address of new root page */
1918 0 : page= ma_page->pos / info->s->block_size;
1919 0 : page_store(log_data + FILEID_STORE_SIZE, page);
1920 0 : log_pos= log_data+ FILEID_STORE_SIZE + PAGE_STORE_SIZE;
1921 0 : log_pos[0]= KEY_OP_OFFSET;
1922 0 : int2store(log_pos+1, offset);
1923 0 : log_pos[3]= KEY_OP_CHANGE;
1924 0 : int2store(log_pos+4, length);
1925 :
1926 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
1927 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data) - 7;
1928 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key_pos;
1929 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].length= length;
1930 0 : translog_parts= 2;
1931 :
1932 : #ifdef EXTRA_DEBUG_KEY_CHANGES
1933 : {
1934 0 : int page_length= ma_page->size;
1935 : ha_checksum crc;
1936 0 : crc= my_checksum(0, ma_page->buff + LSN_STORE_SIZE,
1937 : page_length - LSN_STORE_SIZE);
1938 0 : log_pos+= 6;
1939 0 : log_pos[0]= KEY_OP_CHECK;
1940 0 : int2store(log_pos+1, page_length);
1941 0 : int4store(log_pos+3, crc);
1942 0 : log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= log_pos;
1943 0 : log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= 7;
1944 0 : extra_length+= 7;
1945 0 : translog_parts++;
1946 : }
1947 : #endif
1948 :
1949 0 : if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
1950 : info->trn, info,
1951 : (translog_size_t) (sizeof(log_data) - 7 + length +
1952 : extra_length),
1953 : TRANSLOG_INTERNAL_PARTS + translog_parts,
1954 : log_array, log_data, NULL))
1955 0 : DBUG_RETURN(1);
1956 0 : DBUG_RETURN(0);
1957 : }
1958 :
1959 :
1960 : /**
1961 : @brief Write log entry for page splitting
1962 :
1963 : @note
1964 : Write log entry for page that has got a key added to the page under
1965 : one and only one of the following senarios:
1966 : - Page is shortened from end
1967 : - Data is added to end of page
1968 : - Data added at front of page
1969 :
1970 : @param prefix_or_suffix KEY_OP_NONE Ignored
1971 : KEY_OP_ADD_PREFIX Add data to start of page
1972 : KEY_OP_ADD_SUFFIX Add data to end of page
1973 :
1974 : */
1975 :
1976 : static my_bool _ma_log_split(MARIA_PAGE *ma_page,
1977 : uint org_length, uint new_length,
1978 : const uchar *key_pos, uint key_length,
1979 : int move_length, enum en_key_op prefix_or_suffix,
1980 : const uchar *data, uint data_length,
1981 : uint changed_length)
1982 0 : {
1983 : LSN lsn;
1984 : uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 3+3+3+3+3+2];
1985 : uchar *log_pos;
1986 : LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 3];
1987 0 : uint offset= (uint) (key_pos - ma_page->buff);
1988 : uint translog_parts, extra_length;
1989 0 : MARIA_HA *info= ma_page->info;
1990 : my_off_t page;
1991 0 : DBUG_ENTER("_ma_log_split");
1992 0 : DBUG_PRINT("enter", ("page: %lu org_length: %u new_length: %u",
1993 : (ulong) ma_page->pos, org_length, new_length));
1994 :
1995 0 : log_pos= log_data + FILEID_STORE_SIZE;
1996 0 : page= ma_page->pos / info->s->block_size;
1997 0 : page_store(log_pos, page);
1998 0 : log_pos+= PAGE_STORE_SIZE;
1999 :
2000 0 : if (new_length <= offset || !key_pos)
2001 : {
2002 : /*
2003 : Page was split before inserted key. Write redo entry where
2004 : we just cut current page at page_length
2005 : */
2006 0 : uint length_offset= org_length - new_length;
2007 0 : log_pos[0]= KEY_OP_DEL_SUFFIX;
2008 0 : int2store(log_pos+1, length_offset);
2009 0 : log_pos+= 3;
2010 0 : translog_parts= 1;
2011 0 : extra_length= 0;
2012 : }
2013 : else
2014 : {
2015 : /* Key was added to page which was split after the inserted key */
2016 : uint max_key_length;
2017 :
2018 : /*
2019 : Handle case when split happened directly after the newly inserted key.
2020 : */
2021 0 : max_key_length= new_length - offset;
2022 0 : extra_length= min(key_length, max_key_length);
2023 :
2024 0 : if ((int) new_length < (int) (org_length + move_length + data_length))
2025 : {
2026 : /* Shorten page */
2027 0 : uint diff= org_length + move_length + data_length - new_length;
2028 0 : log_pos[0]= KEY_OP_DEL_SUFFIX;
2029 0 : int2store(log_pos + 1, diff);
2030 0 : log_pos+= 3;
2031 : }
2032 : else
2033 : {
2034 0 : DBUG_ASSERT(new_length == org_length + move_length + data_length);
2035 : }
2036 :
2037 0 : log_pos[0]= KEY_OP_OFFSET;
2038 0 : int2store(log_pos+1, offset);
2039 0 : log_pos+= 3;
2040 :
2041 0 : if (move_length)
2042 : {
2043 0 : log_pos[0]= KEY_OP_SHIFT;
2044 0 : int2store(log_pos+1, move_length);
2045 0 : log_pos+= 3;
2046 : }
2047 :
2048 0 : log_pos[0]= KEY_OP_CHANGE;
2049 0 : int2store(log_pos+1, extra_length);
2050 0 : log_pos+= 3;
2051 :
2052 : /* Point to original inserted key data */
2053 0 : if (prefix_or_suffix == KEY_OP_ADD_PREFIX)
2054 0 : key_pos+= data_length;
2055 :
2056 0 : translog_parts= 2;
2057 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key_pos;
2058 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].length= extra_length;
2059 : }
2060 :
2061 0 : if (data_length)
2062 : {
2063 : /* Add prefix or suffix */
2064 0 : log_pos[0]= prefix_or_suffix;
2065 0 : int2store(log_pos+1, data_length);
2066 0 : log_pos+= 3;
2067 0 : if (prefix_or_suffix == KEY_OP_ADD_PREFIX)
2068 : {
2069 0 : int2store(log_pos+1, changed_length);
2070 0 : log_pos+= 2;
2071 0 : data_length= changed_length;
2072 : }
2073 0 : log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].str= data;
2074 0 : log_array[TRANSLOG_INTERNAL_PARTS + translog_parts].length= data_length;
2075 0 : translog_parts++;
2076 0 : extra_length+= data_length;
2077 : }
2078 :
2079 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
2080 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
2081 : log_data);
2082 0 : DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
2083 : info->trn, info,
2084 : (translog_size_t)
2085 : log_array[TRANSLOG_INTERNAL_PARTS +
2086 : 0].length + extra_length,
2087 : TRANSLOG_INTERNAL_PARTS + translog_parts,
2088 : log_array, log_data, NULL));
2089 : }
2090 :
2091 :
2092 : /**
2093 : @brief
2094 : Write log entry for page that has got a key added to the page
2095 : and page is shortened from start of page
2096 :
2097 : @fn _ma_log_del_prefix()
2098 : @param info Maria handler
2099 : @param page Page number
2100 : @param buff Page buffer
2101 : @param org_length Length of buffer when read
2102 : @param new_length Final length
2103 : @param key_pos Where on page buffer key was added. This is position
2104 : before prefix was removed
2105 : @param key_length How many bytes was changed at 'key_pos'
2106 : @param move_length How many bytes was moved up when key was added
2107 :
2108 : @return
2109 : @retval 0 ok
2110 : @retval 1 error
2111 : */
2112 :
2113 : static my_bool _ma_log_del_prefix(MARIA_PAGE *ma_page,
2114 : uint org_length, uint new_length,
2115 : const uchar *key_pos, uint key_length,
2116 : int move_length)
2117 0 : {
2118 : LSN lsn;
2119 : uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 12], *log_pos;
2120 : LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
2121 0 : uint offset= (uint) (key_pos - ma_page->buff);
2122 0 : uint diff_length= org_length + move_length - new_length;
2123 : uint translog_parts, extra_length;
2124 0 : MARIA_HA *info= ma_page->info;
2125 : my_off_t page;
2126 0 : DBUG_ENTER("_ma_log_del_prefix");
2127 0 : DBUG_PRINT("enter", ("page: %lu org_length: %u new_length: %u",
2128 : (ulong) ma_page->pos, org_length, new_length));
2129 :
2130 0 : DBUG_ASSERT((int) diff_length > 0);
2131 :
2132 0 : log_pos= log_data + FILEID_STORE_SIZE;
2133 0 : page= ma_page->pos / info->s->block_size;
2134 0 : page_store(log_pos, page);
2135 0 : log_pos+= PAGE_STORE_SIZE;
2136 :
2137 0 : translog_parts= 1;
2138 0 : extra_length= 0;
2139 :
2140 0 : if (offset < diff_length + info->s->keypage_header)
2141 : {
2142 : /*
2143 : Key is not anymore on page. Move data down, but take into account that
2144 : the original page had grown with 'move_length bytes'
2145 : */
2146 0 : DBUG_ASSERT(offset + key_length <= diff_length + info->s->keypage_header);
2147 :
2148 0 : log_pos[0]= KEY_OP_DEL_PREFIX;
2149 0 : int2store(log_pos+1, diff_length - move_length);
2150 0 : log_pos+= 3;
2151 : }
2152 : else
2153 : {
2154 : /*
2155 : Correct position to key, as data before key has been delete and key
2156 : has thus been moved down
2157 : */
2158 0 : offset-= diff_length;
2159 0 : key_pos-= diff_length;
2160 :
2161 : /* Move data down */
2162 0 : log_pos[0]= KEY_OP_DEL_PREFIX;
2163 0 : int2store(log_pos+1, diff_length);
2164 0 : log_pos+= 3;
2165 :
2166 0 : log_pos[0]= KEY_OP_OFFSET;
2167 0 : int2store(log_pos+1, offset);
2168 0 : log_pos+= 3;
2169 :
2170 0 : if (move_length)
2171 : {
2172 0 : log_pos[0]= KEY_OP_SHIFT;
2173 0 : int2store(log_pos+1, move_length);
2174 0 : log_pos+= 3;
2175 : }
2176 0 : log_pos[0]= KEY_OP_CHANGE;
2177 0 : int2store(log_pos+1, key_length);
2178 0 : log_pos+= 3;
2179 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].str= key_pos;
2180 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].length= key_length;
2181 0 : translog_parts= 2;
2182 0 : extra_length= key_length;
2183 : }
2184 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
2185 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
2186 : log_data);
2187 0 : DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
2188 : info->trn, info,
2189 : (translog_size_t)
2190 : log_array[TRANSLOG_INTERNAL_PARTS +
2191 : 0].length + extra_length,
2192 : TRANSLOG_INTERNAL_PARTS + translog_parts,
2193 : log_array, log_data, NULL));
2194 : }
2195 :
2196 :
2197 : /**
2198 : @brief
2199 : Write log entry for page that has got data added first and
2200 : data deleted last. Old changed key may be part of page
2201 : */
2202 :
2203 : static my_bool _ma_log_key_middle(MARIA_PAGE *ma_page,
2204 : uint new_length,
2205 : uint data_added_first,
2206 : uint data_changed_first,
2207 : uint data_deleted_last,
2208 : const uchar *key_pos,
2209 : uint key_length, int move_length)
2210 0 : {
2211 : LSN lsn;
2212 : uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 3+5+3+3+3];
2213 : uchar *log_pos;
2214 : LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 4];
2215 : uint key_offset;
2216 : uint translog_parts, extra_length;
2217 : my_off_t page;
2218 0 : MARIA_HA *info= ma_page->info;
2219 0 : DBUG_ENTER("_ma_log_key_middle");
2220 0 : DBUG_PRINT("enter", ("page: %lu", (ulong) ma_page->pos));
2221 :
2222 : /* new place of key after changes */
2223 0 : key_pos+= data_added_first;
2224 0 : key_offset= (uint) (key_pos - ma_page->buff);
2225 0 : if (key_offset < new_length)
2226 : {
2227 : /* key is on page; Calculate how much of the key is there */
2228 0 : uint max_key_length= new_length - key_offset;
2229 0 : if (max_key_length < key_length)
2230 : {
2231 : /* Key is last on page */
2232 0 : key_length= max_key_length;
2233 0 : move_length= 0;
2234 : }
2235 : /*
2236 : Take into account that new data was added as part of original key
2237 : that also needs to be removed from page
2238 : */
2239 0 : data_deleted_last+= move_length;
2240 : }
2241 :
2242 0 : page= ma_page->pos / info->s->block_size;
2243 :
2244 : /* First log changes to page */
2245 0 : log_pos= log_data + FILEID_STORE_SIZE;
2246 0 : page_store(log_pos, page);
2247 0 : log_pos+= PAGE_STORE_SIZE;
2248 :
2249 0 : log_pos[0]= KEY_OP_DEL_SUFFIX;
2250 0 : int2store(log_pos+1, data_deleted_last);
2251 0 : log_pos+= 3;
2252 :
2253 0 : log_pos[0]= KEY_OP_ADD_PREFIX;
2254 0 : int2store(log_pos+1, data_added_first);
2255 0 : int2store(log_pos+3, data_changed_first);
2256 0 : log_pos+= 5;
2257 :
2258 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
2259 0 : log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
2260 : log_data);
2261 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].str= (ma_page->buff +
2262 : info->s->keypage_header);
2263 0 : log_array[TRANSLOG_INTERNAL_PARTS + 1].length= data_changed_first;
2264 0 : translog_parts= 2;
2265 0 : extra_length= data_changed_first;
2266 :
2267 : /* If changed key is on page, log those changes too */
2268 :
2269 0 : if (key_offset < new_length)
2270 : {
2271 0 : uchar *start_log_pos= log_pos;
2272 :
2273 0 : log_pos[0]= KEY_OP_OFFSET;
2274 0 : int2store(log_pos+1, key_offset);
2275 0 : log_pos+= 3;
2276 0 : if (move_length)
2277 : {
2278 0 : log_pos[0]= KEY_OP_SHIFT;
2279 0 : int2store(log_pos+1, move_length);
2280 0 : log_pos+= 3;
2281 : }
2282 0 : log_pos[0]= KEY_OP_CHANGE;
2283 0 : int2store(log_pos+1, key_length);
2284 0 : log_pos+= 3;
2285 :
2286 0 : log_array[TRANSLOG_INTERNAL_PARTS + 2].str= start_log_pos;
2287 0 : log_array[TRANSLOG_INTERNAL_PARTS + 2].length= (uint) (log_pos -
2288 : start_log_pos);
2289 :
2290 0 : log_array[TRANSLOG_INTERNAL_PARTS + 3].str= key_pos;
2291 0 : log_array[TRANSLOG_INTERNAL_PARTS + 3].length= key_length;
2292 0 : translog_parts+=2;
2293 0 : extra_length+= (uint) (log_array[TRANSLOG_INTERNAL_PARTS + 2].length +
2294 : key_length);
2295 : }
2296 :
2297 0 : DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
2298 : info->trn, info,
2299 : (translog_size_t)
2300 : (log_array[TRANSLOG_INTERNAL_PARTS +
2301 : 0].length + extra_length),
2302 : TRANSLOG_INTERNAL_PARTS + translog_parts,
2303 : log_array, log_data, NULL));
2304 : }
2305 :
2306 :
2307 : #ifdef NOT_NEEDED
2308 :
2309 : /**
2310 : @brief
2311 : Write log entry for page that has got data added first and
2312 : data deleted last
2313 : */
2314 :
2315 : static my_bool _ma_log_middle(MARIA_PAGE *ma_page,
2316 : uint data_added_first, uint data_changed_first,
2317 : uint data_deleted_last)
2318 : {
2319 : LSN lsn;
2320 : LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
2321 : uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 3 + 5], *log_pos;
2322 : MARIA_HA *info= ma_page->info;
2323 : my_off_t page;
2324 : DBUG_ENTER("_ma_log_middle");
2325 : DBUG_PRINT("enter", ("page: %lu", (ulong) page));
2326 :
2327 : page= ma_page->page / info->s->block_size;
2328 :
2329 : log_pos= log_data + FILEID_STORE_SIZE;
2330 : page_store(log_pos, page);
2331 : log_pos+= PAGE_STORE_SIZE;
2332 :
2333 : log_pos[0]= KEY_OP_DEL_PREFIX;
2334 : int2store(log_pos+1, data_deleted_last);
2335 : log_pos+= 3;
2336 :
2337 : log_pos[0]= KEY_OP_ADD_PREFIX;
2338 : int2store(log_pos+1, data_added_first);
2339 : int2store(log_pos+3, data_changed_first);
2340 : log_pos+= 5;
2341 :
2342 : log_array[TRANSLOG_INTERNAL_PARTS + 0].str= log_data;
2343 : log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
2344 : log_data);
2345 :
2346 : log_array[TRANSLOG_INTERNAL_PARTS + 1].str= ((char*) buff +
2347 : info->s->keypage_header);
2348 : log_array[TRANSLOG_INTERNAL_PARTS + 1].length= data_changed_first;
2349 : DBUG_RETURN(translog_write_record(&lsn, LOGREC_REDO_INDEX,
2350 : info->trn, info,
2351 : (translog_size_t)
2352 : log_array[TRANSLOG_INTERNAL_PARTS +
2353 : 0].length + data_changed_first,
2354 : TRANSLOG_INTERNAL_PARTS + 2,
2355 : log_array, log_data, NULL));
2356 : }
2357 : #endif
|