LTP GCOV extension - code coverage report
Current view: directory - storage/maria - ma_control_file.c
Test: maria-mtr.html
Date: 2009-03-04 Instrumented lines: 155
Code covered: 46.5 % Executed lines: 72

       1                 : /* Copyright (C) 2007 MySQL AB & Guilhem Bichot & Michael Widenius
       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                 :   WL#3234 Maria control file
      18                 :   First version written by Guilhem Bichot on 2006-04-27.
      19                 : */
      20                 : 
      21                 : #ifndef EXTRACT_DEFINITIONS
      22                 : #include "maria_def.h"
      23                 : #include "ma_checkpoint.h"
      24                 : #endif
      25                 : 
      26                 : /*
      27                 :   A control file contains the following objects:
      28                 : 
      29                 : Start of create time variables (at start of file):
      30                 :   - Magic string (including version number of Maria control file)
      31                 :   - Uuid
      32                 :   - Size of create time part
      33                 :   - Size of dynamic part
      34                 :   - Maria block size
      35                 : .....  Here we can add new variables without changing format
      36                 :   - Checksum of create time part (last of block)
      37                 : 
      38                 : Start of changeable part:
      39                 :   - Checksum of changeable part
      40                 :   - LSN of last checkpoint
      41                 :   - Number of last log file
      42                 :   - Max trid in control file (since Maria 1.5 May 2008)
      43                 :   - Number of consecutive recovery failures (since Maria 1.5 May 2008)
      44                 : .....  Here we can add new variables without changing format
      45                 : 
      46                 : The idea is that one can add new variables to the control file and still
      47                 : use it with old program versions. If one needs to do an incompatible change
      48                 : one should increment the control file version number.
      49                 : */
      50                 : 
      51                 : /* Total size should be < sector size for atomic write operation */
      52                 : #define CF_MAX_SIZE 512
      53                 : #define CF_MIN_SIZE (CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + \
      54                 :                      CF_CHECKSUM_SIZE * 2 + CF_LSN_SIZE + CF_FILENO_SIZE)
      55                 : 
      56                 : /* Create time variables */
      57                 : #define CF_MAGIC_STRING "\xfe\xfe\xc"
      58                 : #define CF_MAGIC_STRING_OFFSET 0
      59                 : #define CF_MAGIC_STRING_SIZE   (sizeof(CF_MAGIC_STRING)-1)
      60                 : #define CF_VERSION_OFFSET      (CF_MAGIC_STRING_OFFSET + CF_MAGIC_STRING_SIZE)
      61                 : #define CF_VERSION_SIZE        1
      62                 : #define CF_UUID_OFFSET         (CF_VERSION_OFFSET + CF_VERSION_SIZE)
      63                 : #define CF_UUID_SIZE           MY_UUID_SIZE
      64                 : #define CF_CREATE_TIME_SIZE_OFFSET  (CF_UUID_OFFSET + CF_UUID_SIZE)
      65                 : #define CF_SIZE_SIZE           2
      66                 : #define CF_CHANGEABLE_SIZE_OFFSET   (CF_CREATE_TIME_SIZE_OFFSET + CF_SIZE_SIZE)
      67                 : #define CF_BLOCKSIZE_OFFSET    (CF_CHANGEABLE_SIZE_OFFSET + CF_SIZE_SIZE)
      68                 : #define CF_BLOCKSIZE_SIZE      2
      69                 : 
      70                 : #define CF_CREATE_TIME_TOTAL_SIZE (CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + \
      71                 :                                    CF_CHECKSUM_SIZE)
      72                 : 
      73                 : /*
      74                 :   Start of the part that changes during execution
      75                 :   This is stored at offset uint2korr(file[CF_CHANGEABLE_SIZE])
      76                 : */
      77                 : #define CF_CHECKSUM_OFFSET 0
      78                 : #define CF_CHECKSUM_SIZE 4
      79                 : #define CF_LSN_OFFSET (CF_CHECKSUM_OFFSET + CF_CHECKSUM_SIZE)
      80                 : #define CF_LSN_SIZE LSN_STORE_SIZE
      81                 : #define CF_FILENO_OFFSET (CF_LSN_OFFSET + CF_LSN_SIZE)
      82                 : #define CF_FILENO_SIZE 4
      83                 : #define CF_MAX_TRID_OFFSET (CF_FILENO_OFFSET + CF_FILENO_SIZE)
      84                 : #define CF_MAX_TRID_SIZE TRANSID_SIZE
      85                 : #define CF_RECOV_FAIL_OFFSET (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE)
      86                 : #define CF_RECOV_FAIL_SIZE 1
      87                 : #define CF_CHANGEABLE_TOTAL_SIZE (CF_RECOV_FAIL_OFFSET + CF_RECOV_FAIL_SIZE)
      88                 : 
      89                 : /*
      90                 :   The following values should not be changed, except when changing version
      91                 :   number of the maria control file. These are the minimum sizes of the
      92                 :   parts the code can handle.
      93                 : */
      94                 : 
      95                 : #define CF_MIN_CREATE_TIME_TOTAL_SIZE \
      96                 : (CF_BLOCKSIZE_OFFSET + CF_BLOCKSIZE_SIZE + CF_CHECKSUM_SIZE)
      97                 : #define CF_MIN_CHANGEABLE_TOTAL_SIZE \
      98                 : (CF_FILENO_OFFSET + CF_FILENO_SIZE)
      99                 : 
     100                 : #ifndef EXTRACT_DEFINITIONS
     101                 : 
     102                 : /* This module owns these two vars. */
     103                 : /**
     104                 :    This LSN serves for the two-checkpoint rule, and also to find the
     105                 :    checkpoint record when doing a recovery.
     106                 : */
     107                 : LSN    last_checkpoint_lsn= LSN_IMPOSSIBLE;
     108                 : uint32 last_logno=          FILENO_IMPOSSIBLE;
     109                 : /**
     110                 :    The maximum transaction id given to a transaction. It is only updated at
     111                 :    clean shutdown (in case of crash, logs have better information).
     112                 : */
     113                 : TrID   max_trid_in_control_file= 0;
     114                 : 
     115                 : /**
     116                 :   Number of consecutive log or recovery failures. Reset to 0 after recovery's
     117                 :   success.
     118                 : */
     119                 : uint8 recovery_failures= 0;
     120                 : 
     121                 : /**
     122                 :    @brief If log's lock should be asserted when writing to control file.
     123                 : 
     124                 :    Can be re-used by any function which needs to be thread-safe except when
     125                 :    it is called at startup.
     126                 : */
     127                 : my_bool maria_multi_threaded= FALSE;
     128                 : /** @brief if currently doing a recovery */
     129                 : my_bool maria_in_recovery= FALSE;
     130                 : 
     131                 : /**
     132                 :   Control file is less then  512 bytes (a disk sector),
     133                 :   to be as atomic as possible
     134                 : */
     135                 : static int control_file_fd= -1;
     136                 : 
     137                 : static uint cf_create_time_size;
     138                 : static uint cf_changeable_size;
     139                 : 
     140                 : /**
     141                 :    @brief Create Maria control file
     142                 : */
     143                 : 
     144                 : static CONTROL_FILE_ERROR create_control_file(const char *name,
     145                 :                                               int open_flags)
     146               5 : {
     147                 :   uint32 sum;
     148                 :   uchar buffer[CF_CREATE_TIME_TOTAL_SIZE];
     149               5 :   DBUG_ENTER("maria_create_control_file");
     150                 : 
     151               5 :   if ((control_file_fd= my_create(name, 0,
     152                 :                                   open_flags,
     153                 :                                   MYF(MY_SYNC_DIR | MY_WME))) < 0)
     154               0 :     DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
     155                 : 
     156                 :   /* Reset variables, as we are creating the file */
     157               5 :   cf_create_time_size= CF_CREATE_TIME_TOTAL_SIZE;
     158               5 :   cf_changeable_size=  CF_CHANGEABLE_TOTAL_SIZE;
     159                 : 
     160                 :   /* Create unique uuid for the control file */
     161               5 :   my_uuid_init((ulong) &buffer, (ulong) &maria_uuid);
     162               5 :   my_uuid(maria_uuid);
     163                 : 
     164                 :   /* Prepare and write the file header */
     165               5 :   memcpy(buffer, CF_MAGIC_STRING, CF_MAGIC_STRING_SIZE);
     166               5 :   buffer[CF_VERSION_OFFSET]= CONTROL_FILE_VERSION;
     167               5 :   memcpy(buffer + CF_UUID_OFFSET, maria_uuid, CF_UUID_SIZE);
     168               5 :   int2store(buffer + CF_CREATE_TIME_SIZE_OFFSET, cf_create_time_size);
     169               5 :   int2store(buffer + CF_CHANGEABLE_SIZE_OFFSET, cf_changeable_size);
     170                 : 
     171                 :   /* Write create time variables */
     172               5 :   int2store(buffer + CF_BLOCKSIZE_OFFSET, maria_block_size);
     173                 : 
     174                 :   /* Store checksum for create time parts */
     175               5 :   sum= (uint32) my_checksum(0, buffer, cf_create_time_size -
     176                 :                             CF_CHECKSUM_SIZE);
     177               5 :   int4store(buffer + cf_create_time_size - CF_CHECKSUM_SIZE, sum);
     178                 : 
     179               5 :   if (my_pwrite(control_file_fd, buffer, cf_create_time_size,
     180                 :                 0, MYF(MY_FNABP |  MY_WME)))
     181               0 :     DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
     182                 : 
     183                 :   /*
     184                 :     To be safer we should make sure that there are no logs or data/index
     185                 :     files around (indeed it could be that the control file alone was deleted
     186                 :     or not restored, and we should not go on with life at this point).
     187                 : 
     188                 :     Things should still be relatively safe as if someone tries to use
     189                 :     an old table with a new control file the different uuid:s between
     190                 :     the files will cause ma_open() to generate an HA_ERR_OLD_FILE
     191                 :     error. When used from mysqld this will cause the table to be open
     192                 :     in repair mode which will remove all dependencies between the
     193                 :     table and the old control file.
     194                 : 
     195                 :     We could have a tool which can rebuild the control file, by reading the
     196                 :     directory of logs, finding the newest log, reading it to find last
     197                 :     checkpoint... Slow but can save your db. For this to be possible, we
     198                 :     must always write to the control file right after writing the checkpoint
     199                 :     log record, and do nothing in between (i.e. the checkpoint must be
     200                 :     usable as soon as it has been written to the log).
     201                 :   */
     202                 : 
     203                 :   /* init the file with these "undefined" values */
     204               5 :   DBUG_RETURN(ma_control_file_write_and_force(LSN_IMPOSSIBLE,
     205                 :                                               FILENO_IMPOSSIBLE, 0, 0));
     206                 : }
     207                 : 
     208                 : 
     209                 : /**
     210                 :   Locks control file exclusively. This is kept for the duration of the engine
     211                 :   process, to prevent another Maria instance to write to our logs or control
     212                 :   file.
     213                 : */
     214                 : 
     215                 : static int lock_control_file(const char *name)
     216               5 : {
     217               5 :   uint retry= 0;
     218                 :   /*
     219                 :     On Windows, my_lock() uses locking() which is mandatory locking and so
     220                 :     prevents maria-recovery.test from copying the control file. And in case of
     221                 :     crash, it may take a while for Windows to unlock file, causing downtime.
     222                 :   */
     223                 :   /**
     224                 :     @todo BUG We should explore my_sopen(_SH_DENYWRD) to open or create the
     225                 :     file under Windows.
     226                 :   */
     227                 : #ifndef __WIN__
     228                 :   /*
     229                 :     We can't here use the automatic wait in my_lock() as the alarm thread
     230                 :     may not yet exists.
     231                 :   */
     232              10 :   while (my_lock(control_file_fd, F_WRLCK, 0L, F_TO_EOF,
     233                 :                  MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK | MY_NO_WAIT)))
     234                 :   {
     235               0 :     if (retry == 0)
     236               0 :       my_printf_error(HA_ERR_INITIALIZATION,
     237                 :                       "Can't lock maria control file '%s' for exclusive use, "
     238                 :                       "error: %d. Will retry for %d seconds", 0,
     239                 :                       name, my_errno, MARIA_MAX_CONTROL_FILE_LOCK_RETRY);
     240               0 :     if (retry++ > MARIA_MAX_CONTROL_FILE_LOCK_RETRY)
     241               0 :       return 1;
     242               0 :     sleep(1);
     243                 :   }
     244                 : #endif
     245               5 :   return 0;
     246                 : }
     247                 : 
     248                 : 
     249                 : /*
     250                 :   @brief Initialize control file subsystem
     251                 : 
     252                 :   Looks for the control file. If none and creation is requested, creates file.
     253                 :   If present, reads it to find out last checkpoint's LSN and last log, updates
     254                 :   the last_checkpoint_lsn and last_logno global variables.
     255                 :   Called at engine's start.
     256                 : 
     257                 :   @note
     258                 :     The format of the control file is defined in the comments and defines
     259                 :     at the start of this file.
     260                 : 
     261                 :   @param create_if_missing create file if not found
     262                 : 
     263                 :   @return Operation status
     264                 :     @retval 0      OK
     265                 :     @retval 1      Error (in which case the file is left closed)
     266                 : */
     267                 : 
     268                 : CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
     269                 :                                         my_bool print_error)
     270             117 : {
     271                 :   uchar buffer[CF_MAX_SIZE];
     272                 :   char name[FN_REFLEN], errmsg_buff[256];
     273                 :   const char *errmsg, *lock_failed_errmsg= "Could not get an exclusive lock;"
     274             117 :     " file is probably in use by another process";
     275                 :   uint new_cf_create_time_size, new_cf_changeable_size, new_block_size;
     276                 :   my_off_t file_size;
     277             117 :   int open_flags= O_BINARY | /*O_DIRECT |*/ O_RDWR;
     278             117 :   int error= CONTROL_FILE_UNKNOWN_ERROR;
     279             117 :   DBUG_ENTER("ma_control_file_open");
     280                 : 
     281                 :   /*
     282                 :     If you change sizes in the #defines, you at least have to change the
     283                 :     "*store" and "*korr" calls in this file, and can even create backward
     284                 :     compatibility problems. Beware!
     285                 :   */
     286                 :   DBUG_ASSERT(CF_LSN_SIZE == (3+4));
     287                 :   DBUG_ASSERT(CF_FILENO_SIZE == 4);
     288                 : 
     289             117 :   if (control_file_fd >= 0) /* already open */
     290               0 :     DBUG_RETURN(0);
     291                 : 
     292             117 :   if (fn_format(name, CONTROL_FILE_BASE_NAME,
     293                 :                 maria_data_root, "", MYF(MY_WME)) == NullS)
     294               0 :     DBUG_RETURN(CONTROL_FILE_UNKNOWN_ERROR);
     295                 : 
     296             117 :   if (my_access(name,F_OK))
     297                 :   {
     298                 :     CONTROL_FILE_ERROR create_error;
     299             117 :     if (!create_if_missing)
     300                 :     {
     301             112 :       error= CONTROL_FILE_MISSING;
     302             112 :       errmsg= "Can't find file";
     303             112 :       goto err;
     304                 :     }
     305               5 :     if ((create_error= create_control_file(name, open_flags)))
     306                 :     {
     307               0 :       error= create_error;
     308               0 :       errmsg= "Can't create file";
     309               0 :       goto err;
     310                 :     }
     311               5 :     if (lock_control_file(name))
     312                 :     {
     313               0 :       errmsg= lock_failed_errmsg;
     314               0 :       goto err;
     315                 :     }
     316                 :     goto ok;
     317                 :   }
     318                 : 
     319                 :   /* Otherwise, file exists */
     320                 : 
     321               0 :   if ((control_file_fd= my_open(name, open_flags, MYF(MY_WME))) < 0)
     322                 :   {
     323               0 :     errmsg= "Can't open file";
     324               0 :     goto err;
     325                 :   }
     326                 : 
     327               0 :   if (lock_control_file(name)) /* lock it before reading content */
     328                 :   {
     329               0 :     errmsg= lock_failed_errmsg;
     330               0 :     goto err;
     331                 :   }
     332                 : 
     333               0 :   file_size= my_seek(control_file_fd, 0, SEEK_END, MYF(MY_WME));
     334               0 :   if (file_size == MY_FILEPOS_ERROR)
     335                 :   {
     336               0 :     errmsg= "Can't read size";
     337               0 :     goto err;
     338                 :   }
     339               0 :   if (file_size < CF_MIN_SIZE)
     340                 :   {
     341                 :     /*
     342                 :       Given that normally we write only a sector and it's atomic, the only
     343                 :       possibility for a file to be of too short size is if we crashed at the
     344                 :       very first startup, between file creation and file write. Quite unlikely
     345                 :       (and can be made even more unlikely by doing this: create a temp file,
     346                 :       write it, and then rename it to be the control file).
     347                 :       What's more likely is if someone forgot to restore the control file,
     348                 :       just did a "touch control" to try to get Maria to start, or if the
     349                 :       disk/filesystem has a problem.
     350                 :       So let's be rigid.
     351                 :     */
     352               0 :     error= CONTROL_FILE_TOO_SMALL;
     353               0 :     errmsg= "Size of control file is smaller than expected";
     354               0 :     goto err;
     355                 :   }
     356                 : 
     357                 :   /* Check if control file is unexpectedly big */
     358               0 :   if (file_size > CF_MAX_SIZE)
     359                 :   {
     360               0 :     error= CONTROL_FILE_TOO_BIG;
     361               0 :     errmsg= "File size bigger than expected";
     362               0 :     goto err;
     363                 :   }
     364                 : 
     365               0 :   if (my_pread(control_file_fd, buffer, (size_t)file_size, 0, MYF(MY_FNABP)))
     366                 :   {
     367               0 :     errmsg= "Can't read file";
     368               0 :     goto err;
     369                 :   }
     370                 : 
     371               0 :   if (memcmp(buffer + CF_MAGIC_STRING_OFFSET,
     372                 :              CF_MAGIC_STRING, CF_MAGIC_STRING_SIZE))
     373                 :   {
     374               0 :     error= CONTROL_FILE_BAD_MAGIC_STRING;
     375               0 :     errmsg= "Missing valid id at start of file. File is not a valid maria control file";
     376               0 :     goto err;
     377                 :   }
     378                 : 
     379               0 :   if (buffer[CF_VERSION_OFFSET] > CONTROL_FILE_VERSION)
     380                 :   {
     381               0 :     error= CONTROL_FILE_BAD_VERSION;
     382               0 :     sprintf(errmsg_buff, "File is from a future maria system: %d. Current version is: %d",
     383                 :             (int) buffer[CF_VERSION_OFFSET], CONTROL_FILE_VERSION);
     384               0 :     errmsg= errmsg_buff;
     385               0 :     goto err;
     386                 :   }
     387                 : 
     388               0 :   new_cf_create_time_size= uint2korr(buffer + CF_CREATE_TIME_SIZE_OFFSET);
     389               0 :   new_cf_changeable_size=  uint2korr(buffer + CF_CHANGEABLE_SIZE_OFFSET);
     390                 : 
     391               0 :   if (new_cf_create_time_size < CF_MIN_CREATE_TIME_TOTAL_SIZE ||
     392                 :       new_cf_changeable_size <  CF_MIN_CHANGEABLE_TOTAL_SIZE ||
     393                 :       new_cf_create_time_size + new_cf_changeable_size != file_size)
     394                 :   {
     395               0 :     error= CONTROL_FILE_INCONSISTENT_INFORMATION;
     396               0 :     errmsg= "Sizes stored in control file are inconsistent";
     397               0 :     goto err;
     398                 :   }
     399                 : 
     400               0 :   new_block_size= uint2korr(buffer + CF_BLOCKSIZE_OFFSET);
     401               0 :   if (new_block_size != maria_block_size)
     402                 :   {
     403               0 :     error= CONTROL_FILE_WRONG_BLOCKSIZE;
     404               0 :     sprintf(errmsg_buff,
     405                 :             "Block size in control file (%u) is different than given maria_block_size: %u",
     406                 :             new_block_size, (uint) maria_block_size);
     407               0 :     errmsg= errmsg_buff;
     408               0 :     goto err;
     409                 :   }
     410                 : 
     411               0 :   if (my_checksum(0, buffer, new_cf_create_time_size - CF_CHECKSUM_SIZE) !=
     412                 :       uint4korr(buffer + new_cf_create_time_size - CF_CHECKSUM_SIZE))
     413                 :   {
     414               0 :     error= CONTROL_FILE_BAD_HEAD_CHECKSUM;
     415               0 :     errmsg= "Fixed part checksum mismatch";
     416               0 :     goto err;
     417                 :   }
     418                 : 
     419               0 :   if (my_checksum(0, buffer + new_cf_create_time_size + CF_CHECKSUM_SIZE,
     420                 :                   new_cf_changeable_size - CF_CHECKSUM_SIZE) !=
     421                 :       uint4korr(buffer + new_cf_create_time_size))
     422                 :   {
     423               0 :     error= CONTROL_FILE_BAD_CHECKSUM;
     424               0 :     errmsg= "Changeable part (end of control file) checksum mismatch";
     425               0 :     goto err;
     426                 :   }
     427                 : 
     428               0 :   memcpy(maria_uuid, buffer + CF_UUID_OFFSET, CF_UUID_SIZE);
     429               0 :   cf_create_time_size= new_cf_create_time_size;
     430               0 :   cf_changeable_size=  new_cf_changeable_size;
     431               0 :   last_checkpoint_lsn= lsn_korr(buffer + new_cf_create_time_size +
     432                 :                                 CF_LSN_OFFSET);
     433               0 :   last_logno= uint4korr(buffer + new_cf_create_time_size + CF_FILENO_OFFSET);
     434               0 :   if (new_cf_changeable_size >= (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE))
     435               0 :     max_trid_in_control_file=
     436                 :       transid_korr(buffer + new_cf_create_time_size + CF_MAX_TRID_OFFSET);
     437               0 :   if (new_cf_changeable_size >= (CF_RECOV_FAIL_OFFSET + CF_RECOV_FAIL_SIZE))
     438               0 :     recovery_failures=
     439                 :       (buffer + new_cf_create_time_size + CF_RECOV_FAIL_OFFSET)[0];
     440                 : 
     441               5 : ok:
     442               5 :   DBUG_RETURN(0);
     443                 : 
     444             112 : err:
     445             112 :   if (print_error)
     446               0 :     my_printf_error(HA_ERR_INITIALIZATION,
     447                 :                     "Got error '%s' when trying to use maria control file "
     448                 :                     "'%s'", 0, errmsg, name);
     449             112 :   ma_control_file_end(); /* will unlock file if needed */
     450             112 :   DBUG_RETURN(error);
     451                 : }
     452                 : 
     453                 : 
     454                 : /*
     455                 :   Write information durably to the control file; stores this information into
     456                 :   the last_checkpoint_lsn, last_logno, max_trid_in_control_file,
     457                 :   recovery_failures global variables.
     458                 :   Called when we have created a new log (after syncing this log's creation),
     459                 :   when we have written a checkpoint (after syncing this log record), at
     460                 :   shutdown (for storing trid in case logs are soon removed by user), and
     461                 :   before and after recovery (to store recovery_failures).
     462                 :   Variables last_checkpoint_lsn and last_logno must be protected by caller
     463                 :   using log's lock, unless this function is called at startup.
     464                 : 
     465                 :   SYNOPSIS
     466                 :     ma_control_file_write_and_force()
     467                 :     last_checkpoint_lsn_arg LSN of last checkpoint
     468                 :     last_logno_arg          last log file number
     469                 :     max_trid_arg            maximum transaction longid
     470                 :     recovery_failures_arg   consecutive recovery failures
     471                 : 
     472                 :   NOTE
     473                 :     We always want to do one single my_pwrite() here to be as atomic as
     474                 :     possible.
     475                 : 
     476                 :   RETURN
     477                 :     0 - OK
     478                 :     1 - Error
     479                 : */
     480                 : 
     481                 : int ma_control_file_write_and_force(LSN last_checkpoint_lsn_arg,
     482                 :                                     uint32 last_logno_arg,
     483                 :                                     TrID max_trid_arg,
     484                 :                                     uint8 recovery_failures_arg)
     485              14 : {
     486                 :   uchar buffer[CF_MAX_SIZE];
     487                 :   uint32 sum;
     488                 :   my_bool no_need_sync;
     489              14 :   DBUG_ENTER("ma_control_file_write_and_force");
     490                 : 
     491                 :   /*
     492                 :     We don't need to sync if this is just an increase of
     493                 :     recovery_failures: it's even good if that counter is not increased on disk
     494                 :     in case of power or hardware failure (less false positives when removing
     495                 :     logs).
     496                 :   */
     497              14 :   no_need_sync= ((last_checkpoint_lsn == last_checkpoint_lsn_arg) &&
     498                 :                  (last_logno == last_logno_arg) &&
     499                 :                  (max_trid_in_control_file == max_trid_arg) &&
     500                 :                  (recovery_failures_arg > 0));
     501                 : 
     502              14 :   if (control_file_fd < 0)
     503               0 :     DBUG_RETURN(1);
     504                 : 
     505                 : #ifndef DBUG_OFF
     506              14 :   if (maria_multi_threaded)
     507               0 :     translog_lock_handler_assert_owner();
     508                 : #endif
     509                 : 
     510              14 :   lsn_store(buffer + CF_LSN_OFFSET, last_checkpoint_lsn_arg);
     511              14 :   int4store(buffer + CF_FILENO_OFFSET, last_logno_arg);
     512              14 :   transid_store(buffer + CF_MAX_TRID_OFFSET, max_trid_arg);
     513              14 :   (buffer + CF_RECOV_FAIL_OFFSET)[0]= recovery_failures_arg;
     514                 : 
     515              14 :   if (cf_changeable_size > CF_CHANGEABLE_TOTAL_SIZE)
     516                 :   {
     517                 :     /*
     518                 :       More room than needed for us. Must be a newer version. Clear part which
     519                 :       we cannot maintain, so that any future version notices we didn't
     520                 :       maintain its extra data.
     521                 :     */
     522               0 :     uint zeroed= cf_changeable_size - CF_CHANGEABLE_TOTAL_SIZE;
     523                 :     char msg[150];
     524               0 :     bzero(buffer + CF_CHANGEABLE_TOTAL_SIZE, zeroed);
     525               0 :     my_snprintf(msg, sizeof(msg),
     526                 :                 "Control file must be from a newer version; zero-ing out %u"
     527                 :                 " unknown bytes in control file at offset %u", zeroed,
     528                 :                 cf_changeable_size + cf_create_time_size);
     529               0 :     ma_message_no_user(ME_JUST_WARNING, msg);
     530                 :   }
     531                 :   else
     532                 :   {
     533                 :     /* not enough room for what we need to store: enlarge */
     534              14 :     cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE;
     535                 :   }
     536                 :   /* Note that the create-time portion is not touched */
     537                 : 
     538                 :   /* Checksum is stored first */
     539                 :   compile_time_assert(CF_CHECKSUM_OFFSET == 0);
     540              14 :   sum= my_checksum(0, buffer + CF_CHECKSUM_SIZE,
     541                 :                    cf_changeable_size - CF_CHECKSUM_SIZE);
     542              14 :   int4store(buffer, sum);
     543                 : 
     544              14 :   if (my_pwrite(control_file_fd, buffer, cf_changeable_size,
     545                 :                 cf_create_time_size, MYF(MY_FNABP |  MY_WME)) ||
     546                 :       (!no_need_sync && my_sync(control_file_fd, MYF(MY_WME))))
     547               0 :     DBUG_RETURN(1);
     548                 : 
     549              14 :   last_checkpoint_lsn= last_checkpoint_lsn_arg;
     550              14 :   last_logno= last_logno_arg;
     551              14 :   max_trid_in_control_file= max_trid_arg;
     552              14 :   recovery_failures= recovery_failures_arg;
     553                 : 
     554              14 :   cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE; /* no more warning */
     555              14 :   DBUG_RETURN(0);
     556                 : }
     557                 : 
     558                 : 
     559                 : /*
     560                 :   Free resources taken by control file subsystem
     561                 : 
     562                 :   SYNOPSIS
     563                 :     ma_control_file_end()
     564                 : */
     565                 : 
     566                 : int ma_control_file_end(void)
     567             228 : {
     568                 :   int close_error;
     569             228 :   DBUG_ENTER("ma_control_file_end");
     570                 : 
     571             228 :   if (control_file_fd < 0) /* already closed */
     572             224 :     DBUG_RETURN(0);
     573                 : 
     574                 : #ifndef __WIN__
     575               4 :   (void) my_lock(control_file_fd, F_UNLCK, 0L, F_TO_EOF,
     576                 :                  MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK));
     577                 : #endif
     578                 : 
     579               4 :   close_error= my_close(control_file_fd, MYF(MY_WME));
     580                 :   /*
     581                 :     As my_close() frees structures even if close() fails, we do the same,
     582                 :     i.e. we mark the file as closed in all cases.
     583                 :   */
     584               4 :   control_file_fd= -1;
     585                 :   /*
     586                 :     As this module owns these variables, closing the module forbids access to
     587                 :     them (just a safety):
     588                 :   */
     589               4 :   last_checkpoint_lsn= LSN_IMPOSSIBLE;
     590               4 :   last_logno= FILENO_IMPOSSIBLE;
     591               4 :   max_trid_in_control_file= recovery_failures= 0;
     592                 : 
     593               4 :   DBUG_RETURN(close_error);
     594                 : }
     595                 : 
     596                 : 
     597                 : /**
     598                 :   Tells if control file is initialized.
     599                 : */
     600                 : 
     601                 : my_bool ma_control_file_inited(void)
     602               0 : {
     603               0 :   return (control_file_fd >= 0);
     604                 : }
     605                 : 
     606                 : #endif /* EXTRACT_DEFINITIONS */

Generated by: LTP GCOV extension version 1.4