LTP GCOV extension - code coverage report
Current view: directory - storage/maria - ma_page.c
Test: maria-unit-test.html
Date: 2009-03-04 Instrumented lines: 201
Code covered: 77.6 % Executed lines: 156

       1                 : /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
       2                 : 
       3                 :    This program is free software; you can redistribute it and/or modify
       4                 :    it under the terms of the GNU General Public License as published by
       5                 :    the Free Software Foundation; version 2 of the License.
       6                 : 
       7                 :    This program is distributed in the hope that it will be useful,
       8                 :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9                 :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10                 :    GNU General Public License for more details.
      11                 : 
      12                 :    You should have received a copy of the GNU General Public License
      13                 :    along with this program; if not, write to the Free Software
      14                 :    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
      15                 : 
      16                 : /*
      17                 :   Read and write key blocks
      18                 : 
      19                 :   The basic structure of a key block is as follows:
      20                 : 
      21                 :   LSN           7 (LSN_STORE_SIZE);     Log number for last change;
      22                 :                 Only for transactional pages
      23                 :   PACK_TRANSID  6 (TRANSID_SIZE);       Relative transid to pack page transid's
      24                 :                 Only for transactional pages
      25                 :   KEYNR         1 (KEYPAGE_KEYID_SIZE)  Which index this page belongs to
      26                 :   FLAG          1 (KEYPAGE_FLAG_SIZE)   Flags for page
      27                 :   PAGE_SIZE     2 (KEYPAGE_USED_SIZE)   How much of the page is used.
      28                 :                                         high-byte-first
      29                 : 
      30                 :   The flag is a combination of the following values:
      31                 : 
      32                 :    KEYPAGE_FLAG_ISNOD            Page is a node
      33                 :    KEYPAGE_FLAG_HAS_TRANSID      There may be a transid on the page.
      34                 : 
      35                 :   After this we store key data, either packed or not packed, directly
      36                 :   after each other.  If the page is a node flag, there is a pointer to
      37                 :   the next key page at page start and after each key.
      38                 : 
      39                 :   At end of page the last KEYPAGE_CHECKSUM_SIZE bytes are reserved for a
      40                 :   page checksum.
      41                 : */
      42                 : 
      43                 : #include "maria_def.h"
      44                 : #include "trnman.h"
      45                 : #include "ma_key_recover.h"
      46                 : 
      47                 : /**
      48                 :    Fill MARIA_PAGE structure for usage with _ma_write_keypage
      49                 : */
      50                 : 
      51                 : void _ma_page_setup(MARIA_PAGE *page, MARIA_HA *info,
      52                 :                     const MARIA_KEYDEF *keyinfo, my_off_t pos,
      53                 :                     uchar *buff)
      54          957183 : {
      55          957183 :   MARIA_SHARE *share= info->s;
      56                 : 
      57          957183 :   page->info=    info;
      58          957183 :   page->keyinfo= keyinfo;
      59          957183 :   page->buff=    buff;
      60          957183 :   page->pos=     pos;
      61          957183 :   page->size=    _ma_get_page_used(share, buff);
      62          957183 :   page->flag=    _ma_get_keypage_flag(share, buff);
      63          957183 :   page->node=    ((page->flag & KEYPAGE_FLAG_ISNOD) ?
      64                 :                   share->base.key_reflength : 0);
      65                 : }
      66                 : 
      67                 : 
      68                 : /**
      69                 :   Fetch a key-page in memory
      70                 : 
      71                 :   @fn _ma_fetch_keypage()
      72                 :   @param page           Fill this struct with information about read page
      73                 :   @param info           Maria handler
      74                 :   @param keyinfo        Key definition for used key
      75                 :   @param pos            Position for page (in bytes)
      76                 :   @param lock           Lock type for page
      77                 :   @param level          Importance of page; Priority for page cache
      78                 :   @param buff           Buffer to use for page
      79                 :   @param return_buffer  Set to 1 if we want to force useage of buff
      80                 : 
      81                 :   @return
      82                 :   @retval 0  ok
      83                 :   @retval 1  error
      84                 : */
      85                 : 
      86                 : my_bool _ma_fetch_keypage(MARIA_PAGE *page, MARIA_HA *info,
      87                 :                           const MARIA_KEYDEF *keyinfo,
      88                 :                           my_off_t pos, enum pagecache_page_lock lock,
      89                 :                           int level, uchar *buff,
      90                 :                           my_bool return_buffer __attribute__ ((unused)))
      91         4689190 : {
      92                 :   uchar *tmp;
      93                 :   MARIA_PINNED_PAGE page_link;
      94         4689190 :   MARIA_SHARE *share= info->s;
      95         4689190 :   uint block_size= share->block_size;
      96         4689190 :   DBUG_ENTER("_ma_fetch_keypage");
      97         4689190 :   DBUG_PRINT("enter",("pos: %ld", (long) pos));
      98                 : 
      99         4689190 :   tmp= pagecache_read(share->pagecache, &share->kfile,
     100                 :                       (pgcache_page_no_t) (pos / block_size), level, buff,
     101                 :                       share->page_type, lock, &page_link.link);
     102                 : 
     103         4689190 :   if (lock != PAGECACHE_LOCK_LEFT_UNLOCKED)
     104                 :   {
     105         4324999 :     DBUG_ASSERT(lock == PAGECACHE_LOCK_WRITE);
     106         4324999 :     page_link.unlock=  PAGECACHE_LOCK_WRITE_UNLOCK;
     107         4324999 :     page_link.changed= 0;
     108         4324999 :     push_dynamic(&info->pinned_pages, (void*) &page_link);
     109         4324999 :     page->link_offset= info->pinned_pages.elements-1;
     110                 :   }
     111                 : 
     112         4689190 :   if (tmp == info->buff)
     113            8928 :     info->keyread_buff_used=1;
     114         4680262 :   else if (!tmp)
     115                 :   {
     116               0 :     DBUG_PRINT("error",("Got errno: %d from pagecache_read",my_errno));
     117               0 :     info->last_keypage=HA_OFFSET_ERROR;
     118               0 :     maria_print_error(share, HA_ERR_CRASHED);
     119               0 :     my_errno=HA_ERR_CRASHED;
     120               0 :     DBUG_RETURN(1);
     121                 :   }
     122         4689190 :   info->last_keypage= pos;
     123                 : 
     124                 :   /*
     125                 :     Setup page structure to make pages easy to use
     126                 :     This is same as page_fill_info, but here inlined as this si used
     127                 :     so often.
     128                 :   */
     129         4689190 :   page->info=    info;
     130         4689190 :   page->keyinfo= keyinfo;
     131         4689190 :   page->buff=    tmp;
     132         4689190 :   page->pos=     pos;
     133         4689190 :   page->size=    _ma_get_page_used(share, tmp);
     134         4689190 :   page->flag=    _ma_get_keypage_flag(share, tmp);
     135         4689190 :   page->node=   ((page->flag & KEYPAGE_FLAG_ISNOD) ?
     136                 :                  share->base.key_reflength : 0);
     137                 : 
     138                 : #ifdef EXTRA_DEBUG
     139                 :   {
     140         4689190 :     uint page_size= page->size;
     141         4689190 :     if (page_size < 4 || page_size > block_size ||
     142                 :         _ma_get_keynr(share, tmp) != keyinfo->key_nr)
     143                 :     {
     144               0 :       DBUG_PRINT("error",("page %lu had wrong page length: %u  keynr: %u",
     145                 :                           (ulong) (pos / block_size), page_size,
     146                 :                           _ma_get_keynr(share, tmp)));
     147               0 :       DBUG_DUMP("page", tmp, page_size);
     148               0 :       info->last_keypage = HA_OFFSET_ERROR;
     149               0 :       maria_print_error(share, HA_ERR_CRASHED);
     150               0 :       my_errno= HA_ERR_CRASHED;
     151               0 :       tmp= 0;
     152                 :     }
     153                 :   }
     154                 : #endif
     155         4689190 :   DBUG_RETURN(0);
     156                 : } /* _ma_fetch_keypage */
     157                 : 
     158                 : 
     159                 : /* Write a key-page on disk */
     160                 : 
     161                 : my_bool _ma_write_keypage(MARIA_PAGE *page, enum pagecache_page_lock lock,
     162                 :                           int level)
     163         2583597 : {
     164         2583597 :   MARIA_SHARE *share= page->info->s;
     165         2583597 :   uint block_size= share->block_size;
     166         2583597 :   uchar *buff= page->buff;
     167                 :   my_bool res;
     168                 :   MARIA_PINNED_PAGE page_link;
     169         2583597 :   DBUG_ENTER("_ma_write_keypage");
     170                 : 
     171                 : #ifdef EXTRA_DEBUG                              /* Safety check */
     172                 :   {
     173                 :     uint page_length, nod_flag;
     174         2583597 :     page_length= _ma_get_page_used(share, buff);
     175         2583597 :     nod_flag=    _ma_test_if_nod(share, buff);
     176                 : 
     177         2583597 :     DBUG_ASSERT(page->size == page_length);
     178         2583597 :     DBUG_ASSERT(page->flag == _ma_get_keypage_flag(share, buff));
     179                 : 
     180         2583597 :     if (page->pos < share->base.keystart ||
     181                 :         page->pos+block_size > share->state.state.key_file_length ||
     182                 :         (page->pos & (maria_block_size-1)))
     183                 :     {
     184               0 :       DBUG_PRINT("error",("Trying to write inside key status region: "
     185                 :                           "key_start: %lu  length: %lu  page: %lu",
     186                 :                           (long) share->base.keystart,
     187                 :                           (long) share->state.state.key_file_length,
     188                 :                           (long) page->pos));
     189               0 :       my_errno=EINVAL;
     190               0 :       DBUG_ASSERT(0);
     191                 :       DBUG_RETURN(1);
     192                 :     }
     193         2583597 :     DBUG_PRINT("page",("write page at: %lu",(long) page->pos));
     194         2583597 :     DBUG_DUMP("buff", buff, page_length);
     195         2583597 :     DBUG_ASSERT(page_length >= share->keypage_header + nod_flag +
     196                 :                 page->keyinfo->minlength || maria_in_recovery);
     197                 :   }
     198                 : #endif
     199                 : 
     200                 :   /* Verify that keynr is correct */
     201         2583597 :   DBUG_ASSERT(_ma_get_keynr(share, buff) == page->keyinfo->key_nr);
     202                 : 
     203                 : #if defined(EXTRA_DEBUG) && defined(HAVE_purify) && defined(NOT_ANYMORE)
     204                 :   {
     205                 :     /* This is here to catch uninitialized bytes */
     206                 :     uint length= page->size;
     207                 :     ulong crc= my_checksum(0, buff, length);
     208                 :     int4store(buff + block_size - KEYPAGE_CHECKSUM_SIZE, crc);
     209                 :   }
     210                 : #endif
     211                 : 
     212                 : #ifdef IDENTICAL_PAGES_AFTER_RECOVERY
     213                 :   {
     214                 :     uint length= page->size;
     215                 :     DBUG_ASSERT(length <= block_size - KEYPAGE_CHECKSUM_SIZE);
     216                 :     bzero(buff + length, block_size - length);
     217                 :   }
     218                 : #endif
     219                 : 
     220         2583597 :   res= pagecache_write(share->pagecache,
     221                 :                        &share->kfile,
     222                 :                        (pgcache_page_no_t) (page->pos / block_size),
     223                 :                        level, buff, share->page_type,
     224                 :                        lock,
     225                 :                        lock == PAGECACHE_LOCK_LEFT_WRITELOCKED ?
     226                 :                        PAGECACHE_PIN_LEFT_PINNED :
     227                 :                        (lock == PAGECACHE_LOCK_WRITE_UNLOCK ?
     228                 :                         PAGECACHE_UNPIN : PAGECACHE_PIN),
     229                 :                        PAGECACHE_WRITE_DELAY, &page_link.link,
     230                 :                        LSN_IMPOSSIBLE);
     231                 : 
     232         2583597 :   if (lock == PAGECACHE_LOCK_WRITE)
     233                 :   {
     234                 :     /* It was not locked before, we have to unlock it when we unpin pages */
     235            4865 :     page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
     236            4865 :     page_link.changed= 1;
     237            4865 :     push_dynamic(&page->info->pinned_pages, (void*) &page_link);
     238                 :   }
     239         2583597 :   DBUG_RETURN(res);
     240                 : }
     241                 : 
     242                 : 
     243                 : /**
     244                 :   @brief Put page in free list
     245                 : 
     246                 :   @fn    _ma_dispose()
     247                 :   @param info           Maria handle
     248                 :   @param pos            Address to page
     249                 :   @param page_not_read  1 if page has not yet been read
     250                 : 
     251                 :   @note
     252                 :     The page at 'pos' must have been read with a write lock.
     253                 :     This function does logging (unlike _ma_new()).
     254                 : 
     255                 :   @return
     256                 :   @retval  0    ok
     257                 :   @retval  1    error
     258                 : 
     259                 : */
     260                 : 
     261                 : int _ma_dispose(register MARIA_HA *info, my_off_t pos, my_bool page_not_read)
     262            4071 : {
     263                 :   my_off_t old_link;
     264                 :   uchar buff[MAX_KEYPAGE_HEADER_SIZE+ 8 + 2];
     265                 :   ulonglong page_no;
     266            4071 :   MARIA_SHARE *share= info->s;
     267                 :   MARIA_PINNED_PAGE page_link;
     268            4071 :   uint block_size= share->block_size;
     269            4071 :   int result= 0;
     270                 :   enum pagecache_page_lock lock_method;
     271                 :   enum pagecache_page_pin pin_method;
     272            4071 :   DBUG_ENTER("_ma_dispose");
     273            4071 :   DBUG_PRINT("enter",("pos: %ld", (long) pos));
     274            4071 :   DBUG_ASSERT(pos % block_size == 0);
     275                 : 
     276            4071 :   (void) _ma_lock_key_del(info, 0);
     277                 : 
     278            4071 :   old_link= share->key_del_current;
     279            4071 :   share->key_del_current= pos;
     280            4071 :   page_no= pos / block_size;
     281            4071 :   bzero(buff, share->keypage_header);
     282            4071 :   _ma_store_keynr(share, buff, (uchar) MARIA_DELETE_KEY_NR);
     283            4071 :   _ma_store_page_used(share, buff, share->keypage_header + 8);
     284            4071 :   mi_sizestore(buff + share->keypage_header, old_link);
     285            4071 :   share->state.changed|= STATE_NOT_SORTED_PAGES;
     286                 : 
     287            4071 :   if (share->now_transactional)
     288                 :   {
     289                 :     LSN lsn;
     290                 :     uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2];
     291                 :     LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
     292                 :     my_off_t page;
     293                 : 
     294                 :     /* Store address of deleted page */
     295            2588 :     page_store(log_data + FILEID_STORE_SIZE, page_no);
     296                 : 
     297                 :     /* Store link to next unused page (the link that is written to page) */
     298            2588 :     page= (old_link == HA_OFFSET_ERROR ? IMPOSSIBLE_PAGE_NO :
     299                 :            old_link / block_size);
     300            2588 :     page_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, page);
     301                 : 
     302            2588 :     log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
     303            2588 :     log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
     304                 : 
     305            2588 :     if (translog_write_record(&lsn, LOGREC_REDO_INDEX_FREE_PAGE,
     306                 :                               info->trn, info,
     307                 :                               (translog_size_t) sizeof(log_data),
     308                 :                               TRANSLOG_INTERNAL_PARTS + 1, log_array,
     309                 :                               log_data, NULL))
     310               0 :       result= 1;
     311                 :   }
     312                 : 
     313            4071 :   if (page_not_read)
     314                 :   {
     315               0 :     lock_method= PAGECACHE_LOCK_WRITE;
     316               0 :     pin_method= PAGECACHE_PIN;
     317                 :   }
     318                 :   else
     319                 :   {
     320            4071 :     lock_method= PAGECACHE_LOCK_LEFT_WRITELOCKED;
     321            4071 :     pin_method= PAGECACHE_PIN_LEFT_PINNED;
     322                 :   }
     323                 : 
     324            4071 :   if (pagecache_write_part(share->pagecache,
     325                 :                            &share->kfile, (pgcache_page_no_t) page_no,
     326                 :                            PAGECACHE_PRIORITY_LOW, buff,
     327                 :                            share->page_type,
     328                 :                            lock_method, pin_method,
     329                 :                            PAGECACHE_WRITE_DELAY, &page_link.link,
     330                 :                            LSN_IMPOSSIBLE,
     331                 :                            0, share->keypage_header + 8))
     332               0 :     result= 1;
     333                 : 
     334                 : #ifdef IDENTICAL_PAGES_AFTER_RECOVERY
     335                 :   {
     336                 :     uchar *page_buff= pagecache_block_link_to_buffer(page_link.link);
     337                 :     bzero(page_buff + share->keypage_header + 8,
     338                 :           block_size - share->keypage_header - 8 - KEYPAGE_CHECKSUM_SIZE);
     339                 :   }
     340                 : #endif
     341                 : 
     342            4071 :   if (page_not_read)
     343                 :   {
     344                 :     /* It was not locked before, we have to unlock it when we unpin pages */
     345               0 :     page_link.unlock= PAGECACHE_LOCK_WRITE_UNLOCK;
     346               0 :     page_link.changed= 1;
     347               0 :     push_dynamic(&info->pinned_pages, (void*) &page_link);
     348                 :   }
     349                 : 
     350            4071 :   DBUG_RETURN(result);
     351                 : } /* _ma_dispose */
     352                 : 
     353                 : 
     354                 : /**
     355                 :   @brief Get address for free page to use
     356                 : 
     357                 :   @fn     _ma_new()
     358                 :   @param  info          Maria handle
     359                 :   @param  level         Type of key block (caching priority for pagecache)
     360                 :   @param  page_link     Pointer to page in page cache if read. One can
     361                 :                         check if this is used by checking if
     362                 :                         page_link->changed != 0
     363                 : 
     364                 :   @note Logging of this is left to the caller (so that the "new"ing and the
     365                 :   first changes done to this new page can be logged as one single entry - one
     366                 :   single _ma_log_new()) call).
     367                 : 
     368                 :   @return
     369                 :     HA_OFFSET_ERROR     File is full or page read error
     370                 :     #                   Page address to use
     371                 : */
     372                 : 
     373                 : my_off_t _ma_new(register MARIA_HA *info, int level,
     374                 :                  MARIA_PINNED_PAGE **page_link)
     375                 : 
     376            5370 : {
     377                 :   my_off_t pos;
     378            5370 :   MARIA_SHARE *share= info->s;
     379            5370 :   uint block_size= share->block_size;
     380            5370 :   DBUG_ENTER("_ma_new");
     381                 : 
     382            5370 :   if (_ma_lock_key_del(info, 1))
     383                 :   {
     384            4964 :     pthread_mutex_lock(&share->intern_lock);
     385            4964 :     pos= share->state.state.key_file_length;
     386            4964 :     if (pos >= share->base.max_key_file_length - block_size)
     387                 :     {
     388               0 :       my_errno=HA_ERR_INDEX_FILE_FULL;
     389               0 :       pthread_mutex_unlock(&share->intern_lock);
     390               0 :       DBUG_RETURN(HA_OFFSET_ERROR);
     391                 :     }
     392            4964 :     share->state.state.key_file_length+= block_size;
     393                 :     /* Following is for not transactional tables */
     394            4964 :     info->state->key_file_length= share->state.state.key_file_length;
     395            4964 :     pthread_mutex_unlock(&share->intern_lock);
     396            4964 :     (*page_link)->changed= 0;
     397            4964 :     (*page_link)->write_lock= PAGECACHE_LOCK_WRITE;
     398                 :   }
     399                 :   else
     400                 :   {
     401                 :     uchar *buff;
     402             406 :     pos= share->key_del_current;                /* Protected */
     403             406 :     DBUG_ASSERT(share->pagecache->block_size == block_size);
     404             406 :     if (!(buff= pagecache_read(share->pagecache,
     405                 :                                &share->kfile,
     406                 :                                (pgcache_page_no_t) (pos / block_size), level,
     407                 :                                0, share->page_type,
     408                 :                                PAGECACHE_LOCK_WRITE, &(*page_link)->link)))
     409               0 :       pos= HA_OFFSET_ERROR;
     410                 :     else
     411                 :     {
     412                 :       /*
     413                 :         Next deleted page's number is in the header of the present page
     414                 :         (single linked list):
     415                 :       */
     416                 : #ifndef DBUG_OFF
     417                 :       my_off_t key_del_current;
     418                 : #endif
     419             406 :       share->key_del_current= mi_sizekorr(buff+share->keypage_header);
     420                 : #ifndef DBUG_OFF
     421             406 :       key_del_current= share->key_del_current;
     422             406 :       DBUG_ASSERT(key_del_current != share->state.key_del &&
     423                 :                   (key_del_current != 0) &&
     424                 :                   ((key_del_current == HA_OFFSET_ERROR) ||
     425                 :                    (key_del_current <=
     426                 :                     (share->state.state.key_file_length - block_size))));
     427                 : #endif
     428                 :     }
     429                 : 
     430             406 :     (*page_link)->unlock=     PAGECACHE_LOCK_WRITE_UNLOCK;
     431             406 :     (*page_link)->write_lock= PAGECACHE_LOCK_WRITE;
     432                 :     /*
     433                 :       We have to mark it changed as _ma_flush_pending_blocks() uses
     434                 :       'changed' to know if we used the page cache or not
     435                 :     */
     436             406 :     (*page_link)->changed= 1;
     437             406 :     push_dynamic(&info->pinned_pages, (void*) *page_link);
     438             406 :     *page_link= dynamic_element(&info->pinned_pages,
     439                 :                                 info->pinned_pages.elements-1,
     440                 :                                 MARIA_PINNED_PAGE *);
     441                 :   }
     442            5370 :   share->state.changed|= STATE_NOT_SORTED_PAGES;
     443            5370 :   DBUG_PRINT("exit",("Pos: %ld",(long) pos));
     444            5370 :   DBUG_RETURN(pos);
     445                 : } /* _ma_new */
     446                 : 
     447                 : 
     448                 : /**
     449                 :    Log compactation of a index page
     450                 : */
     451                 : 
     452                 : static my_bool _ma_log_compact_keypage(MARIA_HA *info, my_off_t page,
     453                 :                                        TrID min_read_from)
     454               0 : {
     455                 :   LSN lsn;
     456                 :   uchar log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE + 1 + TRANSID_SIZE];
     457                 :   LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
     458               0 :   MARIA_SHARE *share= info->s;
     459               0 :   DBUG_ENTER("_ma_log_compact_keypage");
     460               0 :   DBUG_PRINT("enter", ("page: %lu", (ulong) page));
     461                 : 
     462                 :   /* Store address of new root page */
     463               0 :   page/= share->block_size;
     464               0 :   page_store(log_data + FILEID_STORE_SIZE, page);
     465                 : 
     466               0 :   log_data[FILEID_STORE_SIZE + PAGE_STORE_SIZE]= KEY_OP_COMPACT_PAGE;
     467               0 :   transid_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE +1,
     468                 :                 min_read_from);
     469                 : 
     470               0 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
     471               0 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
     472                 : 
     473               0 :   if (translog_write_record(&lsn, LOGREC_REDO_INDEX,
     474                 :                             info->trn, info,
     475                 :                             (translog_size_t) sizeof(log_data),
     476                 :                             TRANSLOG_INTERNAL_PARTS + 1, log_array,
     477                 :                             log_data, NULL))
     478               0 :     DBUG_RETURN(1);
     479               0 :   DBUG_RETURN(0);
     480                 : }
     481                 : 
     482                 : 
     483                 : /**
     484                 :    Remove all transaction id's less than given one from a key page
     485                 : 
     486                 :    @fn    _ma_compact_keypage()
     487                 :    @param keyinfo        Key handler
     488                 :    @param page_pos       Page position on disk
     489                 :    @param page           Buffer for page
     490                 :    @param min_read_from  Remove all trids from page less than this
     491                 : 
     492                 :    @retval 0             Ok
     493                 :    Ūretval 1             Error;  my_errno contains the error
     494                 : */
     495                 : 
     496                 : my_bool _ma_compact_keypage(MARIA_PAGE *ma_page, TrID min_read_from)
     497             244 : {
     498             244 :   MARIA_HA *info= ma_page->info;
     499             244 :   MARIA_SHARE *share= info->s;
     500                 :   MARIA_KEY key;
     501                 :   uchar *page, *endpos, *start_of_empty_space;
     502                 :   uint page_flag, nod_flag, saved_space;
     503                 :   my_bool page_has_transid;
     504             244 :   DBUG_ENTER("_ma_compact_keypage");
     505                 : 
     506             244 :   page_flag= ma_page->flag;
     507             244 :   if (!(page_flag & KEYPAGE_FLAG_HAS_TRANSID))
     508             136 :     DBUG_RETURN(0);                    /* No transaction id on page */
     509                 : 
     510             108 :   nod_flag= ma_page->node;
     511             108 :   page=    ma_page->buff;
     512             108 :   endpos= page + ma_page->size;
     513             108 :   key.data= info->lastkey_buff;
     514             108 :   key.keyinfo= (MARIA_KEYDEF*) ma_page->keyinfo;
     515                 : 
     516             108 :   page_has_transid= 0;
     517             108 :   page+= share->keypage_header + nod_flag;
     518             108 :   key.data[0]= 0;                             /* safety */
     519             108 :   start_of_empty_space= 0;
     520             108 :   saved_space= 0;
     521                 :   do
     522                 :   {
     523           10620 :     if (!(page= (*ma_page->keyinfo->skip_key)(&key, 0, 0, page)))
     524                 :     {
     525               0 :       DBUG_PRINT("error",("Couldn't find last key:  page: 0x%lx",
     526                 :                           (long) page));
     527               0 :       maria_print_error(share, HA_ERR_CRASHED);
     528               0 :       my_errno=HA_ERR_CRASHED;
     529               0 :       DBUG_RETURN(1);
     530                 :     }
     531           10620 :     if (key_has_transid(page-1))
     532                 :     {
     533                 :       uint transid_length;
     534           10620 :       transid_length= transid_packed_length(page);
     535                 : 
     536           21240 :       if (min_read_from == ~(TrID) 0 ||
     537                 :           min_read_from < transid_get_packed(share, page))
     538                 :       {
     539           10620 :         page[-1]&= 254;                           /* Remove transid marker */
     540           10620 :         transid_length= transid_packed_length(page);
     541           10620 :         if (start_of_empty_space)
     542                 :         {
     543                 :           /* Move block before the transid up in page */
     544           10512 :           uint copy_length= (uint) (page - start_of_empty_space) - saved_space;
     545           10512 :           memmove(start_of_empty_space, start_of_empty_space + saved_space,
     546                 :                   copy_length);
     547           10512 :           start_of_empty_space+= copy_length;
     548                 :         }
     549                 :         else
     550             108 :           start_of_empty_space= page;
     551           10620 :         saved_space+= transid_length;
     552                 :       }
     553                 :       else
     554               0 :         page_has_transid= 1;                /* At least one id left */
     555           10620 :       page+= transid_length;
     556                 :     }
     557           10620 :     page+= nod_flag;
     558           10620 :   } while (page < endpos);
     559                 : 
     560             108 :   DBUG_ASSERT(page == endpos);
     561                 : 
     562             108 :   if (start_of_empty_space)
     563                 :   {
     564                 :     /*
     565                 :       Move last block down
     566                 :       This is always true if any transid was removed
     567                 :     */
     568             108 :     uint copy_length= (uint) (endpos - start_of_empty_space) - saved_space;
     569                 : 
     570             108 :     if (copy_length)
     571               8 :       memmove(start_of_empty_space, start_of_empty_space + saved_space,
     572                 :               copy_length);
     573             108 :     ma_page->size= (uint) (start_of_empty_space + copy_length - ma_page->buff);
     574             108 :     page_store_size(share, ma_page);
     575                 :   }
     576                 : 
     577             108 :   if (!page_has_transid)
     578                 :   {
     579             108 :     ma_page->flag&= ~KEYPAGE_FLAG_HAS_TRANSID;
     580             108 :     _ma_store_keypage_flag(share, ma_page->buff, ma_page->flag);
     581                 :     /* Clear packed transid (in case of zerofill) */
     582             108 :     bzero(ma_page->buff + LSN_STORE_SIZE, TRANSID_SIZE);
     583                 :   }
     584                 : 
     585             108 :   if (share->now_transactional)
     586                 :   {
     587               0 :     if (_ma_log_compact_keypage(info, ma_page->pos, min_read_from))
     588               0 :       DBUG_RETURN(1);
     589                 :   }
     590             108 :   DBUG_RETURN(0);
     591                 : }

Generated by: LTP GCOV extension version 1.4