LTP GCOV extension - code coverage report
Current view: directory - storage/maria - ma_write.c
Test: mtr_and_unit.info
Date: 2009-03-05 Instrumented lines: 876
Code covered: 57.5 % Executed lines: 504

       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           81580 : {
      74           81580 :   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           35849 : {
      82           35849 :   return 0;
      83                 : }
      84                 : 
      85                 : 
      86                 : /* Write new record to a table */
      87                 : 
      88                 : int maria_write(MARIA_HA *info, uchar *record)
      89          357861 : {
      90          357861 :   MARIA_SHARE *share= info->s;
      91                 :   uint i;
      92                 :   int save_errno;
      93                 :   MARIA_RECORD_POS filepos;
      94                 :   uchar *buff;
      95          357861 :   my_bool lock_tree= share->lock_key_trees;
      96                 :   my_bool fatal_error;
      97                 :   MARIA_KEYDEF *keyinfo;
      98          357861 :   DBUG_ENTER("maria_write");
      99          357861 :   DBUG_PRINT("enter",("index_file: %d  data_file: %d",
     100                 :                       share->kfile.file, info->dfile.file));
     101                 : 
     102          357861 :   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          357861 :   if (share->options & HA_OPTION_READ_ONLY_DATA)
     106                 :   {
     107               0 :     DBUG_RETURN(my_errno=EACCES);
     108                 :   }
     109          357861 :   if (_ma_readinfo(info,F_WRLCK,1))
     110               0 :     DBUG_RETURN(my_errno);
     111                 :   dont_break();                         /* Dont allow SIGHUP or SIGINT */
     112                 : 
     113          357861 :   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          357861 :   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          357861 :   if (_ma_mark_file_changed(info))
     126          357861 :     goto err2;
     127                 : 
     128                 :   /* Calculate and check all unique constraints */
     129          358881 :   for (i=0 ; i < share->state.header.uniques ; i++)
     130                 :   {
     131            1060 :     if (_ma_check_unique(info,share->uniqueinfo+i,record,
     132                 :                          _ma_unique_hash(share->uniqueinfo+i,record),
     133                 :                          HA_OFFSET_ERROR))
     134            1020 :       goto err2;
     135                 :   }
     136                 : 
     137                 :   /* Ensure we don't try to restore auto_increment if it doesn't change */
     138          357821 :   info->last_auto_increment= ~(ulonglong) 0;
     139                 : 
     140          357821 :   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          357821 :     if ((filepos= (*share->write_record_init)(info, record)) ==
     149                 :         HA_OFFSET_ERROR)
     150          357821 :       goto err2;
     151                 :   }
     152                 : 
     153                 :   /* Write all keys to indextree */
     154          357821 :   buff= info->lastkey_buff2;
     155         1475727 :   for (i=0, keyinfo= share->keyinfo ; i < share->base.keys ; i++, keyinfo++)
     156                 :   {
     157                 :     MARIA_KEY int_key;
     158         1211772 :     if (maria_is_key_active(share->state.key_map, i))
     159                 :     {
     160                 :       my_bool local_lock_tree= (lock_tree &&
     161                 :                                 !(info->bulk_insert &&
     162         1211772 :                                   is_tree_inited(&info->bulk_insert[i])));
     163         1211772 :       if (local_lock_tree)
     164                 :       {
     165               0 :         rw_wrlock(&keyinfo->root_lock);
     166               0 :         keyinfo->version++;
     167                 :       }
     168         1211772 :       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         1211772 :         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           93866 :           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           93866 :           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         1117906 :       info->update&= ~HA_STATE_RNEXT_SAME;
     267                 : 
     268         1117906 :       if (local_lock_tree)
     269               0 :         rw_unlock(&keyinfo->root_lock);
     270                 :     }
     271                 :   }
     272          263955 :   if (share->calc_write_checksum)
     273            5768 :     info->cur_row.checksum= (*share->calc_write_checksum)(info,record);
     274          263955 :   if (filepos != HA_OFFSET_ERROR)
     275                 :   {
     276          263955 :     if ((*share->write_record)(info,record))
     277          263954 :       goto err;
     278          263954 :     info->state->checksum+= info->cur_row.checksum;
     279                 :   }
     280          263954 :   if (!share->now_transactional)
     281                 :   {
     282          175577 :     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          263954 :   info->state->records++;
     291          263954 :   info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_WRITTEN |
     292                 :                  HA_STATE_ROW_CHANGED);
     293          263954 :   share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED;
     294          263954 :   info->state->changed= 1;
     295                 : 
     296          263954 :   info->cur_row.lastpos= filepos;
     297          263954 :   VOID(_ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
     298          263954 :   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          263954 :   if (share->is_log_table)
     315               0 :     _ma_update_status((void*) info);
     316                 : 
     317                 :   allow_break();                                /* Allow SIGHUP & SIGINT */
     318          263954 :   DBUG_RETURN(0);
     319                 : 
     320           93867 : err:
     321           93867 :   save_errno= my_errno;
     322           93867 :   fatal_error= 0;
     323           93867 :   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           93867 :     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           93867 :     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          375472 :     while ( i-- > 0)
     344                 :     {
     345          187738 :       if (maria_is_key_active(share->state.key_map, i))
     346                 :       {
     347                 :         my_bool local_lock_tree= (lock_tree &&
     348                 :                                   !(info->bulk_insert &&
     349          187738 :                                     is_tree_inited(&info->bulk_insert[i])));
     350          187738 :         keyinfo= share->keyinfo + i;
     351          187738 :         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          187738 :         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          187738 :           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          187738 :         if (local_lock_tree)
     379               0 :           rw_unlock(&keyinfo->root_lock);
     380                 :       }
     381                 :     }
     382                 :   }
     383                 :   else
     384               0 :     fatal_error= 1;
     385                 : 
     386           93867 :   if ((*share->write_record_abort)(info))
     387               0 :     fatal_error= 1;
     388           93867 :   if (fatal_error)
     389                 :   {
     390               0 :     maria_print_error(info->s, HA_ERR_CRASHED);
     391               0 :     maria_mark_crashed(info);
     392                 :   }
     393                 : 
     394           93867 :   info->update= (HA_STATE_CHANGED | HA_STATE_WRITTEN | HA_STATE_ROW_CHANGED);
     395           93867 :   my_errno=save_errno;
     396           93907 : err2:
     397           93907 :   save_errno=my_errno;
     398           93907 :   DBUG_ASSERT(save_errno);
     399           93907 :   if (!save_errno)
     400               0 :     save_errno= HA_ERR_INTERNAL_ERROR;          /* Should never happen */
     401           93907 :   DBUG_PRINT("error", ("got error: %d", save_errno));
     402           93907 :   VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
     403                 :   allow_break();                        /* Allow SIGHUP & SIGINT */
     404           93907 :   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         1346285 : {
     418         1346285 :   DBUG_ENTER("_ma_ck_write");
     419                 : 
     420         1346285 :   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         1346285 :   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         1346285 : {
     435                 :   my_bool error;
     436         1346285 :   MARIA_KEYDEF *keyinfo= key->keyinfo;
     437         1346285 :   my_off_t  *root= &info->s->state.key_root[keyinfo->key_nr];
     438         1346285 :   DBUG_ENTER("_ma_ck_write_btree");
     439                 : 
     440         1346285 :   error= _ma_ck_write_btree_with_log(info, key, root,
     441                 :                                      keyinfo->write_comp_flag | key->flag);
     442         1346285 :   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         1346285 :   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         1346285 : {
     464         1346285 :   MARIA_SHARE *share= info->s;
     465         1346285 :   LSN lsn= LSN_IMPOSSIBLE;
     466                 :   int error;
     467         1346285 :   my_off_t new_root= *root;
     468                 :   uchar key_buff[MARIA_MAX_KEY_BUFF];
     469                 :   MARIA_KEY org_key;
     470         1346285 :   DBUG_ENTER("_ma_ck_write_btree_with_log");
     471                 : 
     472         1346285 :   LINT_INIT_STRUCT(org_key);
     473         1346285 :   if (share->now_transactional)
     474                 :   {
     475                 :     /* Save original value as the key may change */
     476          684621 :     org_key= *key;
     477          684621 :     memcpy(key_buff, key->data, key->data_length + key->ref_length);
     478                 :   }
     479                 : 
     480         1346285 :   error= _ma_ck_real_write_btree(info, key, &new_root, comp_flag);
     481         1986585 :   if (!error && share->now_transactional)
     482                 :   {
     483                 :     /* Log the original value */
     484          640300 :     *key= org_key;
     485          640300 :     key->data= key_buff;
     486          640300 :     error= _ma_write_undo_key_insert(info, key, root, new_root, &lsn);
     487                 :   }
     488                 :   else
     489                 :   {
     490          705985 :     *root= new_root;
     491          705985 :     _ma_fast_unlock_key_del(info);
     492                 :   }
     493         1346285 :   _ma_unpin_all_pages_and_finalize_row(info, lsn);
     494                 : 
     495         1346285 :   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         1438335 : {
     509                 :   int error;
     510         1438335 :   DBUG_ENTER("_ma_ck_real_write_btree");
     511                 : 
     512                 :   /* key_length parameter is used only if comp_flag is SEARCH_FIND */
     513         1438335 :   if (*root == HA_OFFSET_ERROR ||
     514                 :       (error= w_search(info, comp_flag, key, *root, (MARIA_PAGE *) 0,
     515                 :                        (uchar*) 0, 1)) > 0)
     516            1751 :     error= _ma_enlarge_root(info, key, root);
     517         1438335 :   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            1751 : {
     530                 :   uint t_length, nod_flag;
     531                 :   MARIA_KEY_PARAM s_temp;
     532            1751 :   MARIA_SHARE *share= info->s;
     533            1751 :   MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
     534            1751 :   MARIA_KEYDEF *keyinfo= key->keyinfo;
     535                 :   MARIA_PAGE page;
     536            1751 :   my_bool res= 0;
     537            1751 :   DBUG_ENTER("_ma_enlarge_root");
     538                 : 
     539            1751 :   page.info=    info;
     540            1751 :   page.keyinfo= keyinfo;
     541            1751 :   page.buff=    info->buff;
     542            1751 :   page.flag=    0;
     543                 : 
     544            1751 :   nod_flag= (*root != HA_OFFSET_ERROR) ?  share->base.key_reflength : 0;
     545                 :   /* Store pointer to prev page if nod */
     546            1751 :   _ma_kpointer(info, page.buff + share->keypage_header, *root);
     547            1751 :   t_length= (*keyinfo->pack_key)(key, nod_flag, (uchar*) 0,
     548                 :                                  (uchar*) 0, (uchar*) 0, &s_temp);
     549            1751 :   page.size= share->keypage_header + t_length + nod_flag;
     550                 : 
     551            1751 :   bzero(page.buff, share->keypage_header);
     552            1751 :   _ma_store_keynr(share, page.buff, keyinfo->key_nr);
     553            1751 :   if (nod_flag)
     554             568 :     page.flag|= KEYPAGE_FLAG_ISNOD;
     555            1751 :   if (key->flag & (SEARCH_USER_KEY_HAS_TRANSID | SEARCH_PAGE_KEY_HAS_TRANSID))
     556             326 :     page.flag|= KEYPAGE_FLAG_HAS_TRANSID;
     557            1751 :   (*keyinfo->store_key)(keyinfo, page.buff + share->keypage_header +
     558                 :                         nod_flag, &s_temp);
     559                 : 
     560                 :   /* Mark that info->buff was used */
     561            1751 :   info->keyread_buff_used= info->page_changed= 1;
     562            1751 :   if ((page.pos= _ma_new(info, PAGECACHE_PRIORITY_HIGH, &page_link)) ==
     563                 :       HA_OFFSET_ERROR)
     564               0 :     DBUG_RETURN(1);
     565            1751 :   *root= page.pos;
     566                 : 
     567            1751 :   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            1751 :   bzero(page.buff + page.size, share->block_size - page.size);
     575                 : 
     576            1751 :   if (share->now_transactional && _ma_log_new(&page, 1))
     577               0 :     res= 1;
     578                 : 
     579            1751 :   if (_ma_write_keypage(&page, page_link->write_lock,
     580                 :                         PAGECACHE_PRIORITY_HIGH))
     581               0 :     res= 1;
     582                 : 
     583            1751 :   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         2271685 : {
     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         2271685 :   MARIA_SHARE *share= info->s;
     607         2271685 :   MARIA_KEYDEF *keyinfo= key->keyinfo;
     608                 :   MARIA_PAGE page;
     609         2271685 :   DBUG_ENTER("w_search");
     610         2271685 :   DBUG_PRINT("enter",("page: %ld", (long) page_pos));
     611                 : 
     612         2271685 :   if (!(temp_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
     613                 :                                       MARIA_MAX_KEY_BUFF*2)))
     614               0 :     DBUG_RETURN(-1);
     615         2271685 :   if (_ma_fetch_keypage(&page, info, keyinfo, page_pos, PAGECACHE_LOCK_WRITE,
     616                 :                         DFLT_INIT_HITS, temp_buff, 0))
     617         2271685 :     goto err;
     618                 : 
     619         2271685 :   flag= (*keyinfo->bin_search)(key, &page, comp_flag, &keypos,
     620                 :                                keybuff, &was_last_key);
     621         2271685 :   if (flag == 0)
     622                 :   {
     623                 :     MARIA_KEY tmp_key;
     624                 :     /* get position to record with duplicated key */
     625                 : 
     626          104963 :     tmp_key.keyinfo= keyinfo;
     627          104963 :     tmp_key.data= keybuff;
     628                 : 
     629          104963 :     if ((*keyinfo->get_key)(&tmp_key, page.flag, page.node, &keypos))
     630          104963 :       dup_key_pos= _ma_row_pos_from_key(&tmp_key);
     631                 :     else
     632               0 :       dup_key_pos= HA_OFFSET_ERROR;
     633                 : 
     634          104963 :     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          104963 :       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          104963 :       info->dup_key_trid= _ma_trid_from_key(&tmp_key);
     691          104963 :       info->dup_key_pos= dup_key_pos;
     692          104963 :       my_errno= HA_ERR_FOUND_DUPP_KEY;
     693          104963 :       goto err;
     694                 :     }
     695                 :   }
     696         2166722 :   if (flag == MARIA_FOUND_WRONG_KEY)
     697         2166722 :     goto err;
     698         2166722 :   if (!was_last_key)
     699         1694940 :     insert_last=0;
     700         2166722 :   next_page= _ma_kpos(page.node, keypos);
     701         2166722 :   if (next_page == HA_OFFSET_ERROR ||
     702                 :       (error= w_search(info, comp_flag, key, next_page,
     703                 :                        &page, keypos, insert_last)) > 0)
     704                 :   {
     705         1334735 :     error= _ma_insert(info, key, &page, keypos, keybuff,
     706                 :                       father_page, father_keypos, insert_last);
     707         1334735 :     page_mark_changed(info, &page);
     708         1334735 :     if (_ma_write_keypage(&page, PAGECACHE_LOCK_LEFT_WRITELOCKED,
     709                 :                           DFLT_INIT_HITS))
     710         2166722 :       goto err;
     711                 :   }
     712                 :   my_afree(temp_buff);
     713         2166722 :   DBUG_RETURN(error);
     714          104963 : err:
     715                 :   my_afree(temp_buff);
     716          104963 :   DBUG_PRINT("exit",("Error: %d",my_errno));
     717          104963 :   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         1334735 : {
     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         1334735 :   MARIA_SHARE *share= info->s;
     760         1334735 :   MARIA_KEYDEF *keyinfo= key->keyinfo;
     761         1334735 :   DBUG_ENTER("_ma_insert");
     762         1334735 :   DBUG_PRINT("enter",("key_pos: 0x%lx", (ulong) key_pos));
     763         1334735 :   DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, key););
     764                 : 
     765         1334735 :   org_anc_length= a_length= anc_page->size;
     766         1334735 :   nod_flag= anc_page->node;
     767                 : 
     768         1334735 :   anc_buff= anc_page->buff;
     769         1334735 :   endpos= anc_buff+ a_length;
     770         1334735 :   prev_key= (key_pos == anc_buff + share->keypage_header + nod_flag ?
     771                 :              (uchar*) 0 : key_buff);
     772         1334735 :   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         1334735 :   if (prev_key && (keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
     777                 :   {
     778          537699 :     DBUG_DUMP("prev_key", prev_key, _ma_keylength(keyinfo,prev_key));
     779                 :   }
     780         1334735 :   if (keyinfo->flag & HA_PACK_KEY)
     781                 :   {
     782          400534 :     DBUG_PRINT("test",("t_length: %d  ref_len: %d",
     783                 :                        t_length,s_temp.ref_length));
     784          400534 :     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         1334735 :   if (t_length > 0)
     789                 :   {
     790         1334520 :     if (t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
     791                 :     {
     792               0 :       my_errno=HA_ERR_CRASHED;
     793               0 :       DBUG_RETURN(-1);
     794                 :     }
     795         1334520 :     bmove_upp(endpos+t_length, endpos, (uint) (endpos-key_pos));
     796                 :   }
     797                 :   else
     798                 :   {
     799             215 :     if (-t_length >= keyinfo->maxlength*2+MAX_POINTER_LENGTH)
     800                 :     {
     801               0 :       my_errno=HA_ERR_CRASHED;
     802               0 :       DBUG_RETURN(-1);
     803                 :     }
     804             215 :     bmove(key_pos,key_pos-t_length,(uint) (endpos-key_pos)+t_length);
     805                 :   }
     806         1334735 :   (*keyinfo->store_key)(keyinfo,key_pos,&s_temp);
     807         1334735 :   a_length+=t_length;
     808                 : 
     809         1334735 :   if (key->flag & (SEARCH_USER_KEY_HAS_TRANSID | SEARCH_PAGE_KEY_HAS_TRANSID))
     810                 :   {
     811          298708 :     _ma_mark_page_with_transid(share, anc_page);
     812                 :   }
     813         1334735 :   anc_page->size= a_length;
     814         1334735 :   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         1334735 :   if (a_length <= (uint) keyinfo->block_length - KEYPAGE_CHECKSUM_SIZE)
     821                 :   {
     822         1330050 :     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         1330050 :       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         1330050 :     DBUG_RETURN(0);                             /* There is room on page */
     888                 :   }
     889                 :   /* Page is full */
     890            4685 :   if (nod_flag)
     891               5 :     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            4685 :   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            1860 :     s_temp.key_pos= key_pos;
     903            1860 :     page_mark_changed(info, father_page);
     904            1860 :     DBUG_RETURN(_ma_balance_page(info, keyinfo, key, anc_page,
     905                 :                                  father_page, father_key_pos,
     906                 :                                  &s_temp));
     907                 :   }
     908            2825 :   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            2825 : {
     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            2825 :   MARIA_PINNED_PAGE tmp_page_link, *page_link= &tmp_page_link;
     948            2825 :   MARIA_SHARE *share= info->s;
     949            2825 :   MARIA_KEYDEF *keyinfo= key->keyinfo;
     950                 :   MARIA_KEY tmp_key;
     951                 :   MARIA_PAGE new_page;
     952                 :   int res;
     953            2825 :   DBUG_ENTER("_ma_split_page");
     954                 : 
     955            2825 :   LINT_INIT(after_key);
     956            2825 :   DBUG_DUMP("buff", split_page->buff, split_page->size);
     957                 : 
     958            2825 :   info->page_changed=1;                      /* Info->buff is used */
     959            2825 :   info->keyread_buff_used=1;
     960            2825 :   page_flag= split_page->flag;
     961            2825 :   nod_flag=  split_page->node;
     962            2825 :   key_ref_length= share->keypage_header + nod_flag;
     963                 : 
     964            2825 :   new_page.info= info;
     965            2825 :   new_page.buff= info->buff;
     966            2825 :   new_page.keyinfo= keyinfo;
     967                 : 
     968            2825 :   tmp_key.data=   key_buff;
     969            2825 :   tmp_key.keyinfo= keyinfo;
     970            2825 :   if (insert_last_key)
     971              15 :     key_pos= _ma_find_last_pos(&tmp_key, split_page, &after_key);
     972                 :   else
     973            2810 :     key_pos= _ma_find_half_pos(&tmp_key, split_page, &after_key);
     974            2825 :   if (!key_pos)
     975               0 :     DBUG_RETURN(-1);
     976                 : 
     977            2825 :   key_length= tmp_key.data_length + tmp_key.ref_length;
     978            2825 :   split_length= (uint) (key_pos - split_page->buff);
     979            2825 :   a_length= split_page->size;
     980            2825 :   split_page->size= split_length;
     981            2825 :   page_store_size(share, split_page);
     982                 : 
     983            2825 :   key_pos=after_key;
     984            2825 :   if (nod_flag)
     985                 :   {
     986               5 :     DBUG_PRINT("test",("Splitting nod"));
     987               5 :     pos=key_pos-nod_flag;
     988               5 :     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            2825 :   if ((new_page.pos= _ma_new(info, PAGECACHE_PRIORITY_HIGH, &page_link)) ==
     993                 :       HA_OFFSET_ERROR)
     994               0 :     DBUG_RETURN(-1);
     995                 : 
     996            2825 :   _ma_copy_key(key, &tmp_key);
     997            2825 :   _ma_kpointer(info, key->data + key_length, new_page.pos);
     998                 : 
     999                 :   /* Store new page */
    1000            2825 :   if (!(*keyinfo->get_key)(&tmp_key, page_flag, nod_flag, &key_pos))
    1001               0 :     DBUG_RETURN(-1);
    1002                 : 
    1003            2825 :   t_length=(*keyinfo->pack_key)(&tmp_key, nod_flag, (uchar *) 0,
    1004                 :                                 (uchar*) 0, (uchar*) 0, &s_temp);
    1005            2825 :   length=(uint) ((split_page->buff + a_length) - key_pos);
    1006            2825 :   memcpy(new_page.buff + key_ref_length + t_length, key_pos,
    1007                 :          (size_t) length);
    1008            2825 :   (*keyinfo->store_key)(keyinfo,new_page.buff+key_ref_length,&s_temp);
    1009            2825 :   page_length= length + t_length + key_ref_length;
    1010                 : 
    1011            2825 :   bzero(new_page.buff, share->keypage_header);
    1012                 :   /* Copy KEYFLAG_FLAG_ISNODE and KEYPAGE_FLAG_HAS_TRANSID from parent page */
    1013            2825 :   new_page.flag= page_flag;
    1014            2825 :   new_page.size= page_length;
    1015            2825 :   page_store_info(share, &new_page);
    1016                 : 
    1017                 :   /* Copy key number */
    1018            2825 :   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            2825 :   res= 2;                                       /* Middle key up */
    1024            2825 :   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            2825 :   bzero(new_page.buff + page_length, share->block_size - page_length);
    1033                 : 
    1034            2825 :   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            2825 :   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            2825 :   DBUG_DUMP_KEY("middle_key", key);
    1046            2825 :   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            3306 : {
    1062                 :   uint keys, length, key_ref_length, page_flag, nod_flag;
    1063                 :   uchar *page, *end, *lastpos;
    1064            3306 :   MARIA_HA *info= ma_page->info;
    1065            3306 :   MARIA_SHARE *share= info->s;
    1066            3306 :   MARIA_KEYDEF *keyinfo= key->keyinfo;
    1067            3306 :   DBUG_ENTER("_ma_find_half_pos");
    1068                 : 
    1069            3306 :   nod_flag= ma_page->node;
    1070            3306 :   key_ref_length= share->keypage_header + nod_flag;
    1071            3306 :   page_flag= ma_page->flag;
    1072            3306 :   length=    ma_page->size - key_ref_length;
    1073            3306 :   page=      ma_page->buff+ key_ref_length;        /* Point to first key */
    1074                 : 
    1075            3306 :   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            1131 :     key_ref_length=   keyinfo->keylength+nod_flag;
    1080            1131 :     key->data_length= keyinfo->keylength - info->s->rec_reflength;
    1081            1131 :     key->ref_length=  info->s->rec_reflength;
    1082            1131 :     key->flag= 0;
    1083            1131 :     keys=length/(key_ref_length*2);
    1084            1131 :     end=page+keys*key_ref_length;
    1085            1131 :     *after_key=end+key_ref_length;
    1086            1131 :     memcpy(key->data, end, key_ref_length);
    1087            1131 :     DBUG_RETURN(end);
    1088                 :   }
    1089                 : 
    1090            2175 :   end=page+length/2-key_ref_length;             /* This is aprox. half */
    1091            2175 :   key->data[0]= 0;                               /* Safety */
    1092                 :   do
    1093                 :   {
    1094          240189 :     lastpos=page;
    1095          240189 :     if (!(length= (*keyinfo->get_key)(key, page_flag, nod_flag, &page)))
    1096               0 :       DBUG_RETURN(0);
    1097          240189 :   } while (page < end);
    1098            2175 :   *after_key= page;
    1099            2175 :   DBUG_PRINT("exit",("returns: 0x%lx  page: 0x%lx  half: 0x%lx",
    1100                 :                      (long) lastpos, (long) page, (long) end));
    1101            2175 :   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              15 : {
    1124                 :   uint keys, length, key_ref_length, page_flag;
    1125                 :   uchar *page, *end, *lastpos, *prevpos;
    1126                 :   uchar key_buff[MARIA_MAX_KEY_BUFF];
    1127              15 :   MARIA_HA *info= ma_page->info;
    1128              15 :   MARIA_SHARE *share= info->s;
    1129              15 :   MARIA_KEYDEF *keyinfo= int_key->keyinfo;
    1130                 :   MARIA_KEY tmp_key;
    1131              15 :   DBUG_ENTER("_ma_find_last_pos");
    1132                 : 
    1133              15 :   key_ref_length= share->keypage_header;
    1134              15 :   page_flag= ma_page->flag;
    1135              15 :   length= ma_page->size - key_ref_length;
    1136              15 :   page=   ma_page->buff + key_ref_length;
    1137                 : 
    1138              15 :   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               1 :     keys= length / keyinfo->keylength - 2;
    1143               1 :     length= keyinfo->keylength;
    1144               1 :     int_key->data_length= length - info->s->rec_reflength;
    1145               1 :     int_key->ref_length=  info->s->rec_reflength;
    1146               1 :     int_key->flag= 0;
    1147               1 :     end=page+keys*length;
    1148               1 :     *after_key=end+length;
    1149               1 :     memcpy(int_key->data, end, length);
    1150               1 :     DBUG_RETURN(end);
    1151                 :   }
    1152                 : 
    1153              14 :   end=page+length-key_ref_length;
    1154              14 :   lastpos=page;
    1155              14 :   tmp_key.data= key_buff;
    1156              14 :   tmp_key.keyinfo= int_key->keyinfo;
    1157              14 :   key_buff[0]= 0;                               /* Safety */
    1158                 : 
    1159                 :   /* We know that there are at least 2 keys on the page */
    1160                 : 
    1161              14 :   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            4059 :     prevpos=lastpos; lastpos=page;
    1170            4059 :     int_key->data_length= tmp_key.data_length;
    1171            4059 :     int_key->ref_length=  tmp_key.ref_length;
    1172            4059 :     int_key->flag=        tmp_key.flag;
    1173            4059 :     memcpy(int_key->data, key_buff, length);         /* previous key */
    1174            4059 :     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            4059 :   } while (page < end);
    1180                 : 
    1181              14 :   *after_key=lastpos;
    1182              14 :   DBUG_PRINT("exit",("returns: 0x%lx  page: 0x%lx  end: 0x%lx",
    1183                 :                      (long) prevpos,(long) page,(long) end));
    1184              14 :   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            1860 : {
    1208            1860 :   MARIA_PINNED_PAGE tmp_page_link, *new_page_link= &tmp_page_link;
    1209            1860 :   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            1860 :   DBUG_ENTER("_ma_balance_page");
    1218                 : 
    1219            1860 :   k_length= keyinfo->keylength;
    1220            1860 :   father_length= father_page->size;
    1221            1860 :   father_keylength= k_length + share->base.key_reflength;
    1222            1860 :   nod_flag= curr_page->node;
    1223            1860 :   curr_keylength= k_length+nod_flag;
    1224            1860 :   info->page_changed=1;
    1225                 : 
    1226            2832 :   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             972 :     right=1;
    1232             972 :     next_page.pos= _ma_kpos(share->base.key_reflength,
    1233                 :                             father_key_pos+father_keylength);
    1234             972 :     left_page=  curr_page;
    1235             972 :     right_page= &next_page;
    1236             972 :     DBUG_PRINT("info", ("use right page: %lu", (ulong) next_page.pos));
    1237                 :   }
    1238                 :   else
    1239                 :   {
    1240             888 :     right=0;
    1241             888 :     father_key_pos-=father_keylength;
    1242             888 :     next_page.pos= _ma_kpos(share->base.key_reflength,father_key_pos);
    1243             888 :     left_page=  &next_page;
    1244             888 :     right_page= curr_page;
    1245             888 :     DBUG_PRINT("info", ("use left page: %lu", (ulong) next_page.pos));
    1246                 :   }                                     /* father_key_pos ptr to parting key */
    1247                 : 
    1248            1860 :   if (_ma_fetch_keypage(&next_page, info, keyinfo, next_page.pos,
    1249                 :                         PAGECACHE_LOCK_WRITE,
    1250                 :                         DFLT_INIT_HITS, info->buff, 0))
    1251            1860 :     goto err;
    1252            1860 :   page_mark_changed(info, &next_page);
    1253            1860 :   DBUG_DUMP("next", next_page.buff, next_page.size);
    1254                 : 
    1255                 :   /* Test if there is room to share keys */
    1256            1860 :   left_length= left_page->size;
    1257            1860 :   right_length= right_page->size;
    1258            1860 :   keys= ((left_length+right_length-share->keypage_header*2-nod_flag*2)/
    1259                 :          curr_keylength);
    1260                 : 
    1261            1860 :   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            1571 :     new_left_length= share->keypage_header+nod_flag+(keys/2)*curr_keylength;
    1266            1571 :     new_right_length=share->keypage_header+nod_flag+(((keys+1)/2)*
    1267                 :                                                        curr_keylength);
    1268            1571 :     left_page->size=  new_left_length;
    1269            1571 :     page_store_size(share, left_page);
    1270            1571 :     right_page->size= new_right_length;
    1271            1571 :     page_store_size(share, right_page);
    1272                 : 
    1273            1571 :     DBUG_PRINT("info", ("left_length: %u -> %u  right_length: %u -> %u",
    1274                 :                         left_length, new_left_length,
    1275                 :                         right_length, new_right_length));
    1276            1571 :     if (left_length < new_left_length)
    1277                 :     {
    1278                 :       uint length;
    1279             716 :       DBUG_PRINT("info", ("move keys to end of buff"));
    1280                 : 
    1281                 :       /* Move keys right_page -> left_page */
    1282             716 :       pos= left_page->buff+left_length;
    1283             716 :       memcpy(pos,father_key_pos, (size_t) k_length);
    1284             716 :       memcpy(pos+k_length, right_page->buff + share->keypage_header,
    1285                 :              (size_t) (length=new_left_length - left_length - k_length));
    1286             716 :       pos= right_page->buff + share->keypage_header + length;
    1287             716 :       memcpy(father_key_pos, pos, (size_t) k_length);
    1288             716 :       bmove(right_page->buff + share->keypage_header,
    1289                 :             pos + k_length, new_right_length);
    1290                 : 
    1291             716 :       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             855 :       DBUG_PRINT("info", ("move keys to start of right_page"));
    1345                 : 
    1346             855 :       bmove_upp(right_page->buff + new_right_length,
    1347                 :                 right_page->buff + right_length,
    1348                 :                 right_length - share->keypage_header);
    1349             855 :       length= new_right_length -right_length - k_length;
    1350             855 :       memcpy(right_page->buff + share->keypage_header + length, father_key_pos,
    1351                 :              (size_t) k_length);
    1352             855 :       pos= left_page->buff + new_left_length;
    1353             855 :       memcpy(father_key_pos, pos, (size_t) k_length);
    1354             855 :       memcpy(right_page->buff + share->keypage_header, pos+k_length,
    1355                 :              (size_t) length);
    1356                 : 
    1357             855 :       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            1571 :             goto err;
    1406                 :         }
    1407                 :       }
    1408                 :     }
    1409                 : 
    1410                 :     /* Log changes to father (one level up) page */
    1411                 : 
    1412            1571 :     if (share->now_transactional &&
    1413                 :         _ma_log_change(father_page, father_key_pos, k_length))
    1414            1571 :       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            1571 :     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            1571 :     DBUG_RETURN(0);
    1426                 :   }
    1427                 : 
    1428                 :   /* left_page and right_page are full, lets split and make new nod */
    1429                 : 
    1430             289 :   extra_buff= info->buff+share->base.max_key_block_length;
    1431             289 :   new_left_length= new_right_length= (share->keypage_header + nod_flag +
    1432                 :                                       (keys+1) / 3 * curr_keylength);
    1433             289 :   extra_page.info=    info;
    1434             289 :   extra_page.keyinfo= keyinfo;
    1435             289 :   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             289 :   if (keys == 5)                                /* Too few keys to balance */
    1443               0 :     new_left_length-=curr_keylength;
    1444             289 :   extra_length= (nod_flag + left_length + right_length -
    1445                 :                  new_left_length - new_right_length - curr_keylength);
    1446             289 :   extra_buff_length= extra_length + share->keypage_header;
    1447             289 :   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             289 :   left_page->size= new_left_length;
    1453             289 :   page_store_size(share, left_page);
    1454             289 :   right_page->size= new_right_length;
    1455             289 :   page_store_size(share, right_page);
    1456                 : 
    1457             289 :   bzero(extra_buff, share->keypage_header);
    1458             289 :   extra_page.flag= nod_flag ? KEYPAGE_FLAG_ISNOD : 0;
    1459             289 :   extra_page.size= extra_buff_length;
    1460             289 :   page_store_info(share, &extra_page);
    1461                 : 
    1462                 :   /* Copy key number */
    1463             289 :   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             289 :   pos= right_page->buff + right_length-extra_length;
    1468             289 :   memcpy(extra_buff + share->keypage_header, pos, extra_length);
    1469                 :   /* Zero old data from buffer */
    1470             289 :   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             289 :   memcpy(tmp_part_key, pos-k_length,k_length);
    1475                 :   /* Make place for new keys */
    1476             289 :   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             289 :   pos= left_page->buff + new_left_length;
    1480             289 :   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             289 :   parting_key= right_page->buff + share->keypage_header + tmp_length;
    1484             289 :   memcpy(parting_key, father_key_pos, (size_t) k_length);
    1485                 : 
    1486                 :   /* Move new parting keys up to caller */
    1487             289 :   memcpy((right ? key->data : father_key_pos),pos,(size_t) k_length);
    1488             289 :   memcpy((right ? father_key_pos : key->data),tmp_part_key, k_length);
    1489                 : 
    1490             289 :   if ((extra_page.pos= _ma_new(info, DFLT_INIT_HITS, &new_page_link))
    1491                 :       == HA_OFFSET_ERROR)
    1492             289 :     goto err;
    1493             289 :   _ma_kpointer(info,key->data+k_length, extra_page.pos);
    1494                 :   /* This is safe as long we are using not keys with transid */
    1495             289 :   key->data_length= k_length - info->s->rec_reflength;
    1496             289 :   key->ref_length= info->s->rec_reflength;
    1497                 : 
    1498             289 :   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             117 :     swap_variables(my_off_t, extra_page.pos, next_page.pos);
    1508                 :   } 
    1509                 : 
    1510             289 :   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             289 :       goto err;
    1582                 :   }
    1583                 : 
    1584             289 :   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             289 :   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          640300 : {
    1782          640300 :   MARIA_SHARE *share= info->s;
    1783          640300 :   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          640300 :   lsn_store(log_data, info->trn->undo_lsn);
    1793          640300 :   key_nr_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE,
    1794                 :                keyinfo->key_nr);
    1795          640300 :   key_length= key->data_length + key->ref_length;
    1796          640300 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
    1797          640300 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
    1798          640300 :   log_array[TRANSLOG_INTERNAL_PARTS + 1].str=    key->data;
    1799          640300 :   log_array[TRANSLOG_INTERNAL_PARTS + 1].length= key_length;
    1800                 : 
    1801          640300 :   msg.root= root;
    1802          640300 :   msg.value= new_root;
    1803          640300 :   msg.auto_increment= 0;
    1804          640300 :   key_value= key->data;
    1805          640300 :   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          640300 :   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            2994 : {
    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            2994 :   MARIA_HA *info= ma_page->info;
    1855            2994 :   MARIA_SHARE *share= info->s;
    1856                 :   my_off_t page;
    1857            2994 :   DBUG_ENTER("_ma_log_new");
    1858            2994 :   DBUG_PRINT("enter", ("page: %lu", (ulong) ma_page->pos));
    1859                 : 
    1860            2994 :   DBUG_ASSERT(share->now_transactional);
    1861                 : 
    1862                 :   /* Store address of new root page */
    1863            2994 :   page= ma_page->pos / share->block_size;
    1864            2994 :   page_store(log_data + FILEID_STORE_SIZE, page);
    1865                 : 
    1866                 :   /* Store link to next unused page */
    1867            2994 :   if (info->key_del_used == 2)
    1868            2588 :     page= 0;                                    /* key_del not changed */
    1869                 :   else
    1870             406 :     page= ((share->key_del_current == HA_OFFSET_ERROR) ? IMPOSSIBLE_PAGE_NO :
    1871                 :            share->key_del_current / share->block_size);
    1872                 : 
    1873            2994 :   page_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, page);
    1874            2994 :   key_nr_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE*2,
    1875                 :                ma_page->keyinfo->key_nr);
    1876            2994 :   log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE*2 + KEY_NR_STORE_SIZE]=
    1877                 :     (uchar) root_page;
    1878                 : 
    1879            2994 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
    1880            2994 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
    1881                 : 
    1882            2994 :   page_length= ma_page->size - LSN_STORE_SIZE;
    1883            2994 :   log_array[TRANSLOG_INTERNAL_PARTS + 1].str=   ma_page->buff + LSN_STORE_SIZE;
    1884            2994 :   log_array[TRANSLOG_INTERNAL_PARTS + 1].length= page_length;
    1885                 : 
    1886            2994 :   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            2994 :   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            1881 : {
    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            1881 :   uint offset= (uint) (key_pos - ma_page->buff);
    1988                 :   uint translog_parts, extra_length;
    1989            1881 :   MARIA_HA *info= ma_page->info; 
    1990                 :   my_off_t page;
    1991            1881 :   DBUG_ENTER("_ma_log_split");
    1992            1881 :   DBUG_PRINT("enter", ("page: %lu  org_length: %u  new_length: %u",
    1993                 :                        (ulong) ma_page->pos, org_length, new_length));
    1994                 : 
    1995            1881 :   log_pos= log_data + FILEID_STORE_SIZE;
    1996            1881 :   page= ma_page->pos / info->s->block_size;
    1997            1881 :   page_store(log_pos, page);
    1998            1881 :   log_pos+= PAGE_STORE_SIZE;
    1999                 : 
    2000            2882 :   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            1001 :     uint length_offset= org_length - new_length;
    2007            1001 :     log_pos[0]= KEY_OP_DEL_SUFFIX;
    2008            1001 :     int2store(log_pos+1, length_offset);
    2009            1001 :     log_pos+= 3;
    2010            1001 :     translog_parts= 1;
    2011            1001 :     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             880 :     max_key_length= new_length - offset;
    2022             880 :     extra_length= min(key_length, max_key_length);
    2023                 : 
    2024             880 :     if ((int) new_length < (int) (org_length + move_length + data_length))
    2025                 :     {
    2026                 :       /* Shorten page */
    2027             880 :       uint diff= org_length + move_length + data_length - new_length;
    2028             880 :       log_pos[0]= KEY_OP_DEL_SUFFIX;
    2029             880 :       int2store(log_pos + 1, diff);
    2030             880 :       log_pos+= 3;
    2031                 :     }
    2032                 :     else
    2033                 :     {
    2034               0 :       DBUG_ASSERT(new_length == org_length + move_length + data_length);
    2035                 :     }
    2036                 : 
    2037             880 :     log_pos[0]= KEY_OP_OFFSET;
    2038             880 :     int2store(log_pos+1, offset);
    2039             880 :     log_pos+= 3;
    2040                 : 
    2041             880 :     if (move_length)
    2042                 :     {
    2043             880 :       log_pos[0]= KEY_OP_SHIFT;
    2044             880 :       int2store(log_pos+1, move_length);
    2045             880 :       log_pos+= 3;
    2046                 :     }
    2047                 : 
    2048             880 :     log_pos[0]= KEY_OP_CHANGE;
    2049             880 :     int2store(log_pos+1, extra_length);
    2050             880 :     log_pos+= 3;
    2051                 : 
    2052                 :     /* Point to original inserted key data */
    2053             880 :     if (prefix_or_suffix == KEY_OP_ADD_PREFIX)
    2054               0 :       key_pos+= data_length;
    2055                 : 
    2056             880 :     translog_parts= 2;
    2057             880 :     log_array[TRANSLOG_INTERNAL_PARTS + 1].str=    key_pos;
    2058             880 :     log_array[TRANSLOG_INTERNAL_PARTS + 1].length= extra_length;
    2059                 :   }
    2060                 : 
    2061            1881 :   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            1881 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
    2080            1881 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos -
    2081                 :                                                          log_data);
    2082            1881 :   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

Generated by: LTP GCOV extension version 1.4