LTP GCOV extension - code coverage report
Current view: directory - storage/maria - ma_loghandler.c
Test: maria-mtr.html
Date: 2009-03-04 Instrumented lines: 2744
Code covered: 33.5 % Executed lines: 920

       1                 : /* Copyright (C) 2007 MySQL AB & Sanja Belkin
       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                 : #include "maria_def.h"
      17                 : #include "trnman.h"
      18                 : #include "ma_blockrec.h" /* for some constants and in-write hooks */
      19                 : #include "ma_key_recover.h" /* For some in-write hooks */
      20                 : #include "ma_checkpoint.h"
      21                 : 
      22                 : /*
      23                 :   On Windows, neither my_open() nor my_sync() work for directories.
      24                 :   Also there is no need to flush filesystem changes ,i.e to sync()
      25                 :   directories.
      26                 : */
      27                 : #ifdef __WIN__
      28                 : #define sync_dir(A,B) 0
      29                 : #else
      30                 : #define sync_dir(A,B) my_sync(A,B)
      31                 : #endif
      32                 : 
      33                 : /**
      34                 :    @file
      35                 :    @brief Module which writes and reads to a transaction log
      36                 : */
      37                 : 
      38                 : /* 0xFF can never be valid first byte of a chunk */
      39                 : #define TRANSLOG_FILLER 0xFF
      40                 : 
      41                 : /* number of opened log files in the pagecache (should be at least 2) */
      42                 : #define OPENED_FILES_NUM 3
      43                 : #define CACHED_FILES_NUM 5
      44                 : #define CACHED_FILES_NUM_DIRECT_SEARCH_LIMIT 7
      45                 : #if CACHED_FILES_NUM > CACHED_FILES_NUM_DIRECT_SEARCH_LIMIT
      46                 : #include <hash.h>
      47                 : #include <m_ctype.h>
      48                 : #endif
      49                 : 
      50                 : /* transaction log file descriptor */
      51                 : typedef struct st_translog_file
      52                 : {
      53                 :   uint32 number;
      54                 :   PAGECACHE_FILE handler;
      55                 :   my_bool was_recovered;
      56                 :   my_bool is_sync;
      57                 : } TRANSLOG_FILE;
      58                 : 
      59                 : /* records buffer size (should be TRANSLOG_PAGE_SIZE * n) */
      60                 : #define TRANSLOG_WRITE_BUFFER (1024*1024)
      61                 : /*
      62                 :   pagecache_read/write/inject() use bmove512() on their buffers so those must
      63                 :   be long-aligned, which we guarantee by using the type below:
      64                 : */
      65                 : typedef union
      66                 : {
      67                 :   ulonglong dummy;
      68                 :   uchar buffer[TRANSLOG_PAGE_SIZE];
      69                 : } TRANSLOG_PAGE_SIZE_BUFF;
      70                 : 
      71                 : /* min chunk length */
      72                 : #define TRANSLOG_MIN_CHUNK 3
      73                 : /*
      74                 :   Number of buffers used by loghandler
      75                 : 
      76                 :   Should be at least 4, because one thread can block up to 2 buffers in
      77                 :   normal circumstances (less then half of one and full other, or just
      78                 :   switched one and other), But if we met end of the file in the middle and
      79                 :   have to switch buffer it will be 3.  + 1 buffer for flushing/writing.
      80                 :   We have a bigger number here for higher concurrency and to make division
      81                 :   faster.
      82                 : 
      83                 :   The number should be power of 2 to be fast.
      84                 : */
      85                 : #define TRANSLOG_BUFFERS_NO 8
      86                 : /* number of bytes (+ header) which can be unused on first page in sequence */
      87                 : #define TRANSLOG_MINCHUNK_CONTENT 1
      88                 : /* version of log file */
      89                 : #define TRANSLOG_VERSION_ID 10000               /* 1.00.00 */
      90                 : 
      91                 : #define TRANSLOG_PAGE_FLAGS 6 /* transaction log page flags offset */
      92                 : 
      93                 : /* Maximum length of compressed LSNs (the worst case of whole LSN storing) */
      94                 : #define COMPRESSED_LSN_MAX_STORE_SIZE (2 + LSN_STORE_SIZE)
      95                 : #define MAX_NUMBER_OF_LSNS_PER_RECORD 2
      96                 : 
      97                 : 
      98                 : /* max lsn calculation for buffer */
      99                 : #define BUFFER_MAX_LSN(B)  \
     100                 :   ((B)->last_lsn == LSN_IMPOSSIBLE ? (B)->prev_last_lsn : (B)->last_lsn)
     101                 : 
     102                 : /* log write buffer descriptor */
     103                 : struct st_translog_buffer
     104                 : {
     105                 :   /*
     106                 :     Cache for current log. Comes first to be aligned for bmove512() in
     107                 :     pagecache_inject()
     108                 :   */
     109                 :   uchar buffer[TRANSLOG_WRITE_BUFFER];
     110                 :   /*
     111                 :     Maximum LSN of records which ends in this buffer (or IMPOSSIBLE_LSN
     112                 :     if no LSNs ends here)
     113                 :   */
     114                 :   LSN last_lsn;
     115                 :   /* last_lsn of previous buffer or IMPOSSIBLE_LSN if it is very first one */
     116                 :   LSN prev_last_lsn;
     117                 :   /* This buffer offset in the file */
     118                 :   TRANSLOG_ADDRESS offset;
     119                 :   /*
     120                 :     Next buffer offset in the file (it is not always offset + size,
     121                 :     in case of flush by LSN it can be offset + size - TRANSLOG_PAGE_SIZE)
     122                 :   */
     123                 :   TRANSLOG_ADDRESS next_buffer_offset;
     124                 :   /* Previous buffer offset to detect it flush finish */
     125                 :   TRANSLOG_ADDRESS prev_buffer_offset;
     126                 :   /*
     127                 :      How much is written (or will be written when copy_to_buffer_in_progress
     128                 :      become 0) to this buffer
     129                 :   */
     130                 :   translog_size_t size;
     131                 :   /* File handler for this buffer */
     132                 :   TRANSLOG_FILE *file;
     133                 :   /* Threads which are waiting for buffer filling/freeing */
     134                 :   pthread_cond_t waiting_filling_buffer;
     135                 :   /* Number of records which are in copy progress */
     136                 :   uint copy_to_buffer_in_progress;
     137                 :   /* list of waiting buffer ready threads */
     138                 :   struct st_my_thread_var *waiting_flush;
     139                 :   /*
     140                 :     If true then previous buffer overlap with this one (due to flush of
     141                 :     loghandler, the last page of that buffer is the same as the first page
     142                 :     of this buffer) and have to be written first (because contain old
     143                 :     content of page which present in both buffers)
     144                 :   */
     145                 :   my_bool overlay;
     146                 :   uint buffer_no;
     147                 :   /*
     148                 :     Lock for the buffer.
     149                 : 
     150                 :     Current buffer also lock the whole handler (if one want lock the handler
     151                 :     one should lock the current buffer).
     152                 : 
     153                 :     Buffers are locked only in one direction (with overflow and beginning
     154                 :     from the first buffer). If we keep lock on buffer N we can lock only
     155                 :     buffer N+1 (never N-1).
     156                 : 
     157                 :     One thread do not lock more then 2 buffer in a time, so to make dead
     158                 :     lock it should be N thread (where N equal number of buffers) takes one
     159                 :     buffer and try to lock next. But it is impossible because there is only
     160                 :     2 cases when thread take 2 buffers: 1) one thread finishes current
     161                 :     buffer (where horizon is) and start next (to which horizon moves).  2)
     162                 :     flush start from buffer after current (oldest) and go till the current
     163                 :     crabbing by buffer sequence. And there is  only one flush in a moment
     164                 :     (they are serialised).
     165                 : 
     166                 :    Because of above and number of buffers equal 5 we can't get dead lock (it is
     167                 :    impossible to get all 5 buffers locked simultaneously).
     168                 :   */
     169                 :   pthread_mutex_t mutex;
     170                 :   /*
     171                 :     Some thread is going to close the buffer and it should be
     172                 :     done only by that thread
     173                 :   */
     174                 :   my_bool is_closing_buffer;
     175                 :   /*
     176                 :     Version of the buffer increases every time buffer the buffer flushed.
     177                 :     With file and offset it allow detect buffer changes
     178                 :   */
     179                 :   uint8 ver;
     180                 : 
     181                 :   /*
     182                 :     When previous buffer sent to disk it set its address here to allow
     183                 :     to detect when it is done
     184                 :     (we have to keep it in this buffer to lock buffers only in one direction).
     185                 :   */
     186                 :   TRANSLOG_ADDRESS prev_sent_to_disk;
     187                 :   pthread_cond_t prev_sent_to_disk_cond;
     188                 : };
     189                 : 
     190                 : 
     191                 : struct st_buffer_cursor
     192                 : {
     193                 :   /* pointer into the buffer */
     194                 :   uchar *ptr;
     195                 :   /* current buffer */
     196                 :   struct st_translog_buffer *buffer;
     197                 :   /* How many bytes we wrote on the current page */
     198                 :   uint16 current_page_fill;
     199                 :   /*
     200                 :     How many times we write the page on the disk during flushing process
     201                 :     (for sector protection).
     202                 :   */
     203                 :   uint16 write_counter;
     204                 :   /* previous write offset */
     205                 :   uint16 previous_offset;
     206                 :   /* Number of current buffer */
     207                 :   uint8 buffer_no;
     208                 :   /*
     209                 :     True if it is just filling buffer after advancing the pointer to
     210                 :     the horizon.
     211                 :   */
     212                 :   my_bool chaser;
     213                 :   /*
     214                 :     Is current page of the cursor already finished (sector protection
     215                 :     should be applied if it is needed)
     216                 :   */
     217                 :   my_bool protected;
     218                 : };
     219                 : 
     220                 : 
     221                 : typedef uint8 dirty_buffer_mask_t;
     222                 : 
     223                 : struct st_translog_descriptor
     224                 : {
     225                 :   /* *** Parameters of the log handler *** */
     226                 : 
     227                 :   /* Page cache for the log reads */
     228                 :   PAGECACHE *pagecache;
     229                 :   uint flags;
     230                 :   /* File open flags */
     231                 :   uint open_flags;
     232                 :   /* max size of one log size (for new logs creation) */
     233                 :   uint32 log_file_max_size;
     234                 :   uint32 server_version;
     235                 :   /* server ID (used for replication) */
     236                 :   uint32 server_id;
     237                 :   /* Loghandler's buffer capacity in case of chunk 2 filling */
     238                 :   uint32 buffer_capacity_chunk_2;
     239                 :   /*
     240                 :     Half of the buffer capacity in case of chunk 2 filling,
     241                 :     used to decide will we write a record in one group or many.
     242                 :     It is written to the variable just to avoid devision every
     243                 :     time we need it.
     244                 :   */
     245                 :   uint32 half_buffer_capacity_chunk_2;
     246                 :   /* Page overhead calculated by flags (whether CRC is enabled, etc) */
     247                 :   uint16 page_overhead;
     248                 :   /*
     249                 :     Page capacity ("useful load") calculated by flags
     250                 :     (TRANSLOG_PAGE_SIZE - page_overhead-1)
     251                 :   */
     252                 :   uint16 page_capacity_chunk_2;
     253                 :   /* Path to the directory where we store log store files */
     254                 :   char directory[FN_REFLEN];
     255                 : 
     256                 :   /* *** Current state of the log handler *** */
     257                 :   /* list of opened files */
     258                 :   DYNAMIC_ARRAY open_files;
     259                 :   /* min/max number of file in the array */
     260                 :   uint32 max_file, min_file;
     261                 :   /* the opened files list guard */
     262                 :   rw_lock_t open_files_lock;
     263                 : 
     264                 :   /*
     265                 :     File descriptor of the directory where we store log files for syncing
     266                 :     it.
     267                 :   */
     268                 :   File directory_fd;
     269                 :   /* buffers for log writing */
     270                 :   struct st_translog_buffer buffers[TRANSLOG_BUFFERS_NO];
     271                 :   /* Mask where 1 in position N mean that buffer N is not flushed */
     272                 :   dirty_buffer_mask_t dirty_buffer_mask;
     273                 :   /* The above variable protection */
     274                 :   pthread_mutex_t dirty_buffer_mask_lock;
     275                 :   /*
     276                 :      horizon - visible end of the log (here is absolute end of the log:
     277                 :      position where next chunk can start
     278                 :   */
     279                 :   TRANSLOG_ADDRESS horizon;
     280                 :   /* horizon buffer cursor */
     281                 :   struct st_buffer_cursor bc;
     282                 :   /* maximum LSN of the current (not finished) file */
     283                 :   LSN max_lsn;
     284                 : 
     285                 :   /*
     286                 :     Last flushed LSN (protected by log_flush_lock).
     287                 :     Pointers in the log ordered like this:
     288                 :     last_lsn_checked <= flushed <= sent_to_disk <= in_buffers_only <=
     289                 :     max_lsn <= horizon
     290                 :   */
     291                 :   LSN flushed;
     292                 :   /* Last LSN sent to the disk (but maybe not written yet) */
     293                 :   LSN sent_to_disk;
     294                 :   /* Horizon from which log started after initialization */
     295                 :   TRANSLOG_ADDRESS log_start;
     296                 :   TRANSLOG_ADDRESS previous_flush_horizon;
     297                 :   /* All what is after this address is not sent to disk yet */
     298                 :   TRANSLOG_ADDRESS in_buffers_only;
     299                 :   /* protection of sent_to_disk and in_buffers_only */
     300                 :   pthread_mutex_t sent_to_disk_lock;
     301                 :   /*
     302                 :     Protect flushed (see above) and for flush serialization (will
     303                 :     be removed in v1.5
     304                 :   */
     305                 :   pthread_mutex_t log_flush_lock;
     306                 :   pthread_cond_t log_flush_cond;
     307                 : 
     308                 :   /* Protects changing of headers of finished files (max_lsn) */
     309                 :   pthread_mutex_t file_header_lock;
     310                 : 
     311                 :   /*
     312                 :     Sorted array (with protection) of files where we started writing process
     313                 :     and so we can't give last LSN yet
     314                 :   */
     315                 :   pthread_mutex_t unfinished_files_lock;
     316                 :   DYNAMIC_ARRAY unfinished_files;
     317                 : 
     318                 :   /*
     319                 :     minimum number of still need file calculeted during last
     320                 :     translog_purge call
     321                 :   */
     322                 :   uint32 min_need_file;
     323                 :   /* Purger data: minimum file in the log (or 0 if unknown) */
     324                 :   uint32 min_file_number;
     325                 :   /* Protect purger from many calls and it's data */
     326                 :   pthread_mutex_t purger_lock;
     327                 :   /* last low water mark checked */
     328                 :   LSN last_lsn_checked;
     329                 :   /**
     330                 :     Must be set to 0 under loghandler lock every time a new LSN
     331                 :     is generated.
     332                 :   */
     333                 :   my_bool is_everything_flushed;
     334                 :   /* True when flush pass is in progress */
     335                 :   my_bool flush_in_progress;
     336                 :   /* Next flush pass variables */
     337                 :   TRANSLOG_ADDRESS next_pass_max_lsn;
     338                 :   pthread_t max_lsn_requester;
     339                 : };
     340                 : 
     341                 : static struct st_translog_descriptor log_descriptor;
     342                 : 
     343                 : ulong log_purge_type= TRANSLOG_PURGE_IMMIDIATE;
     344                 : ulong log_file_size= TRANSLOG_FILE_SIZE;
     345                 : ulong sync_log_dir= TRANSLOG_SYNC_DIR_NEWFILE;
     346                 : 
     347                 : /* Marker for end of log */
     348                 : static uchar end_of_log= 0;
     349                 : #define END_OF_LOG &end_of_log
     350                 : 
     351                 : enum enum_translog_status translog_status= TRANSLOG_UNINITED;
     352                 : 
     353                 : /* chunk types */
     354                 : #define TRANSLOG_CHUNK_LSN   0x00      /* 0 chunk refer as LSN (head or tail */
     355                 : #define TRANSLOG_CHUNK_FIXED (1 << 6)  /* 1 (pseudo)fixed record (also LSN) */
     356                 : #define TRANSLOG_CHUNK_NOHDR (2 << 6)  /* 2 no head chunk (till page end) */
     357                 : #define TRANSLOG_CHUNK_LNGTH (3 << 6)  /* 3 chunk with chunk length */
     358                 : #define TRANSLOG_CHUNK_TYPE  (3 << 6)  /* Mask to get chunk type */
     359                 : #define TRANSLOG_REC_TYPE    0x3F      /* Mask to get record type */
     360                 : #define TRANSLOG_CHUNK_0_CONT 0x3F     /* the type to mark chunk 0 continue */
     361                 : 
     362                 : /* compressed (relative) LSN constants */
     363                 : #define TRANSLOG_CLSN_LEN_BITS 0xC0    /* Mask to get compressed LSN length */
     364                 : 
     365                 : 
     366                 : #include <my_atomic.h>
     367                 : /* an array that maps id of a MARIA_SHARE to this MARIA_SHARE */
     368                 : static MARIA_SHARE **id_to_share= NULL;
     369                 : /* lock for id_to_share */
     370                 : static my_atomic_rwlock_t LOCK_id_to_share;
     371                 : 
     372                 : static my_bool translog_dummy_callback(uchar *page,
     373                 :                                        pgcache_page_no_t page_no,
     374                 :                                        uchar* data_ptr);
     375                 : static my_bool translog_page_validator(uchar *page,
     376                 :                                        pgcache_page_no_t page_no,
     377                 :                                        uchar* data_ptr);
     378                 : 
     379                 : static my_bool translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner);
     380                 : static uint32 translog_first_file(TRANSLOG_ADDRESS horizon, int is_protected);
     381                 : LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon);
     382                 : 
     383                 : 
     384                 : /*
     385                 :   Initialize log_record_type_descriptors
     386                 : */
     387                 : 
     388                 : LOG_DESC log_record_type_descriptor[LOGREC_NUMBER_OF_TYPES];
     389                 : 
     390                 : 
     391                 : #ifndef DBUG_OFF
     392                 : 
     393                 : #define translog_buffer_lock_assert_owner(B) \
     394                 :   safe_mutex_assert_owner(&(B)->mutex)
     395                 : #define translog_lock_assert_owner() \
     396                 :   safe_mutex_assert_owner(&log_descriptor.bc.buffer->mutex)
     397                 : void translog_lock_handler_assert_owner()
     398               0 : {
     399               0 :   translog_lock_assert_owner();
     400                 : }
     401                 : 
     402                 : /**
     403                 :   @brief check the description table validity
     404                 : 
     405                 :   @param num             how many records should be filled
     406                 : */
     407                 : 
     408                 : static void check_translog_description_table(int num)
     409               5 : {
     410                 :   int i;
     411               5 :   DBUG_ENTER("check_translog_description_table");
     412               5 :   DBUG_PRINT("enter", ("last record: %d", num));
     413               5 :   DBUG_ASSERT(num > 0);
     414                 :   /* last is reserved for extending the table */
     415               5 :   DBUG_ASSERT(num < LOGREC_NUMBER_OF_TYPES - 1);
     416               5 :   DBUG_ASSERT(log_record_type_descriptor[0].rclass == LOGRECTYPE_NOT_ALLOWED);
     417                 : 
     418             220 :   for (i= 0; i <= num; i++)
     419                 :   {
     420             215 :     DBUG_PRINT("info",
     421                 :                ("record type: %d  class: %d  fixed: %u  header: %u  LSNs: %u  "
     422                 :                 "name: %s",
     423                 :                 i, log_record_type_descriptor[i].rclass,
     424                 :                 (uint)log_record_type_descriptor[i].fixed_length,
     425                 :                 (uint)log_record_type_descriptor[i].read_header_len,
     426                 :                 (uint)log_record_type_descriptor[i].compressed_LSN,
     427                 :                 log_record_type_descriptor[i].name));
     428             215 :     switch (log_record_type_descriptor[i].rclass) {
     429                 :     case LOGRECTYPE_NOT_ALLOWED:
     430               5 :       DBUG_ASSERT(i == 0);
     431                 :       break;
     432                 :     case LOGRECTYPE_VARIABLE_LENGTH:
     433             135 :       DBUG_ASSERT(log_record_type_descriptor[i].fixed_length == 0);
     434             135 :       DBUG_ASSERT((log_record_type_descriptor[i].compressed_LSN == 0) ||
     435                 :                   ((log_record_type_descriptor[i].compressed_LSN == 1) &&
     436                 :                    (log_record_type_descriptor[i].read_header_len >=
     437                 :                     LSN_STORE_SIZE)) ||
     438                 :                   ((log_record_type_descriptor[i].compressed_LSN == 2) &&
     439                 :                    (log_record_type_descriptor[i].read_header_len >=
     440                 :                     LSN_STORE_SIZE * 2)));
     441                 :       break;
     442                 :     case LOGRECTYPE_PSEUDOFIXEDLENGTH:
     443              10 :       DBUG_ASSERT(log_record_type_descriptor[i].fixed_length ==
     444                 :                   log_record_type_descriptor[i].read_header_len);
     445              10 :       DBUG_ASSERT(log_record_type_descriptor[i].compressed_LSN > 0);
     446              10 :       DBUG_ASSERT(log_record_type_descriptor[i].compressed_LSN <= 2);
     447                 :       break;
     448                 :     case LOGRECTYPE_FIXEDLENGTH:
     449              65 :       DBUG_ASSERT(log_record_type_descriptor[i].fixed_length ==
     450                 :                   log_record_type_descriptor[i].read_header_len);
     451              65 :       DBUG_ASSERT(log_record_type_descriptor[i].compressed_LSN == 0);
     452                 :       break;
     453                 :     default:
     454               0 :       DBUG_ASSERT(0);
     455                 :     }
     456                 :   }
     457             110 :   for (i= num + 1; i < LOGREC_NUMBER_OF_TYPES; i++)
     458                 :   {
     459             105 :     DBUG_ASSERT(log_record_type_descriptor[i].rclass ==
     460                 :                 LOGRECTYPE_NOT_ALLOWED);
     461                 :   }
     462               5 :   DBUG_VOID_RETURN;
     463                 : }
     464                 : #else
     465                 : #define translog_buffer_lock_assert_owner(B) {}
     466                 : #define translog_lock_assert_owner() {}
     467                 : #endif
     468                 : 
     469                 : static LOG_DESC INIT_LOGREC_RESERVED_FOR_CHUNKS23=
     470                 : {LOGRECTYPE_NOT_ALLOWED, 0, 0, NULL, NULL, NULL, 0,
     471                 :  "reserved", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL };
     472                 : 
     473                 : static LOG_DESC INIT_LOGREC_REDO_INSERT_ROW_HEAD=
     474                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     475                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE, NULL,
     476                 :  write_hook_for_redo, NULL, 0,
     477                 :  "redo_insert_row_head", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     478                 : 
     479                 : static LOG_DESC INIT_LOGREC_REDO_INSERT_ROW_TAIL=
     480                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     481                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE, NULL,
     482                 :  write_hook_for_redo, NULL, 0,
     483                 :  "redo_insert_row_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     484                 : 
     485                 : static LOG_DESC INIT_LOGREC_REDO_NEW_ROW_HEAD=
     486                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     487                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE, NULL,
     488                 :  write_hook_for_redo, NULL, 0,
     489                 :  "redo_new_row_head", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     490                 : 
     491                 : static LOG_DESC INIT_LOGREC_REDO_NEW_ROW_TAIL=
     492                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     493                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE, NULL,
     494                 :  write_hook_for_redo, NULL, 0,
     495                 :  "redo_new_row_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     496                 : 
     497                 : static LOG_DESC INIT_LOGREC_REDO_INSERT_ROW_BLOBS=
     498                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, FILEID_STORE_SIZE, NULL,
     499                 :  write_hook_for_redo, NULL, 0,
     500                 :  "redo_insert_row_blobs", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     501                 : 
     502                 : static LOG_DESC INIT_LOGREC_REDO_PURGE_ROW_HEAD=
     503                 : {LOGRECTYPE_FIXEDLENGTH,
     504                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
     505                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
     506                 :  NULL, write_hook_for_redo, NULL, 0,
     507                 :  "redo_purge_row_head", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     508                 : 
     509                 : static LOG_DESC INIT_LOGREC_REDO_PURGE_ROW_TAIL=
     510                 : {LOGRECTYPE_FIXEDLENGTH,
     511                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
     512                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
     513                 :  NULL, write_hook_for_redo, NULL, 0,
     514                 :  "redo_purge_row_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     515                 : 
     516                 : static LOG_DESC INIT_LOGREC_REDO_FREE_BLOCKS=
     517                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     518                 :  FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE,
     519                 :  NULL, write_hook_for_redo, NULL, 0,
     520                 :  "redo_free_blocks", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     521                 : 
     522                 : static LOG_DESC INIT_LOGREC_REDO_FREE_HEAD_OR_TAIL=
     523                 : {LOGRECTYPE_FIXEDLENGTH,
     524                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE,
     525                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE,
     526                 :  NULL, write_hook_for_redo, NULL, 0,
     527                 :  "redo_free_head_or_tail", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     528                 : 
     529                 : /* not yet used; for when we have versioning */
     530                 : static LOG_DESC INIT_LOGREC_REDO_DELETE_ROW=
     531                 : {LOGRECTYPE_FIXEDLENGTH, 16, 16, NULL, write_hook_for_redo, NULL, 0,
     532                 :  "redo_delete_row", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     533                 : 
     534                 : /** @todo RECOVERY BUG unused, remove? */
     535                 : static LOG_DESC INIT_LOGREC_REDO_UPDATE_ROW_HEAD=
     536                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 9, NULL, write_hook_for_redo, NULL, 0,
     537                 :  "redo_update_row_head", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     538                 : 
     539                 : static LOG_DESC INIT_LOGREC_REDO_INDEX=
     540                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 9, NULL, write_hook_for_redo, NULL, 0,
     541                 :  "redo_index", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     542                 : 
     543                 : static LOG_DESC INIT_LOGREC_REDO_INDEX_NEW_PAGE=
     544                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     545                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2 + KEY_NR_STORE_SIZE + 1,
     546                 :  NULL, write_hook_for_redo, NULL, 0,
     547                 :  "redo_index_new_page", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     548                 : 
     549                 : static LOG_DESC INIT_LOGREC_REDO_INDEX_FREE_PAGE=
     550                 : {LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2,
     551                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2,
     552                 :  NULL, write_hook_for_redo, NULL, 0,
     553                 :  "redo_index_free_page", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     554                 : 
     555                 : static LOG_DESC INIT_LOGREC_REDO_UNDELETE_ROW=
     556                 : {LOGRECTYPE_FIXEDLENGTH, 16, 16, NULL, write_hook_for_redo, NULL, 0,
     557                 :  "redo_undelete_row", LOGREC_NOT_LAST_IN_GROUP, NULL, NULL};
     558                 : 
     559                 : static LOG_DESC INIT_LOGREC_CLR_END=
     560                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, LSN_STORE_SIZE + FILEID_STORE_SIZE +
     561                 :  CLR_TYPE_STORE_SIZE, NULL, write_hook_for_clr_end, NULL, 1,
     562                 :  "clr_end", LOGREC_LAST_IN_GROUP, NULL, NULL};
     563                 : 
     564                 : static LOG_DESC INIT_LOGREC_PURGE_END=
     565                 : {LOGRECTYPE_PSEUDOFIXEDLENGTH, 5, 5, NULL, NULL, NULL, 1,
     566                 :  "purge_end", LOGREC_LAST_IN_GROUP, NULL, NULL};
     567                 : 
     568                 : static LOG_DESC INIT_LOGREC_UNDO_ROW_INSERT=
     569                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     570                 :  LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
     571                 :  NULL, write_hook_for_undo_row_insert, NULL, 1,
     572                 :  "undo_row_insert", LOGREC_LAST_IN_GROUP, NULL, NULL};
     573                 : 
     574                 : static LOG_DESC INIT_LOGREC_UNDO_ROW_DELETE=
     575                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     576                 :  LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
     577                 :  NULL, write_hook_for_undo_row_delete, NULL, 1,
     578                 :  "undo_row_delete", LOGREC_LAST_IN_GROUP, NULL, NULL};
     579                 : 
     580                 : static LOG_DESC INIT_LOGREC_UNDO_ROW_UPDATE=
     581                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     582                 :  LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE + DIRPOS_STORE_SIZE,
     583                 :  NULL, write_hook_for_undo_row_update, NULL, 1,
     584                 :  "undo_row_update", LOGREC_LAST_IN_GROUP, NULL, NULL};
     585                 : 
     586                 : static LOG_DESC INIT_LOGREC_UNDO_KEY_INSERT=
     587                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     588                 :  LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE,
     589                 :  NULL, write_hook_for_undo_key_insert, NULL, 1,
     590                 :  "undo_key_insert", LOGREC_LAST_IN_GROUP, NULL, NULL};
     591                 : 
     592                 : /* This will never be in the log, only in the clr */
     593                 : static LOG_DESC INIT_LOGREC_UNDO_KEY_INSERT_WITH_ROOT=
     594                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     595                 :  LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE + PAGE_STORE_SIZE,
     596                 :  NULL, write_hook_for_undo_key, NULL, 1,
     597                 :  "undo_key_insert_with_root", LOGREC_LAST_IN_GROUP, NULL, NULL};
     598                 : 
     599                 : static LOG_DESC INIT_LOGREC_UNDO_KEY_DELETE=
     600                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     601                 :  LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE,
     602                 :  NULL, write_hook_for_undo_key_delete, NULL, 1,
     603                 :  "undo_key_delete", LOGREC_LAST_IN_GROUP, NULL, NULL};
     604                 : 
     605                 : static LOG_DESC INIT_LOGREC_UNDO_KEY_DELETE_WITH_ROOT=
     606                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     607                 :  LSN_STORE_SIZE + FILEID_STORE_SIZE + KEY_NR_STORE_SIZE + PAGE_STORE_SIZE,
     608                 :  NULL, write_hook_for_undo_key_delete, NULL, 1,
     609                 :  "undo_key_delete_with_root", LOGREC_LAST_IN_GROUP, NULL, NULL};
     610                 : 
     611                 : static LOG_DESC INIT_LOGREC_PREPARE=
     612                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
     613                 :  "prepare", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     614                 : 
     615                 : static LOG_DESC INIT_LOGREC_PREPARE_WITH_UNDO_PURGE=
     616                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, LSN_STORE_SIZE, NULL, NULL, NULL, 1,
     617                 :  "prepare_with_undo_purge", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     618                 : 
     619                 : static LOG_DESC INIT_LOGREC_COMMIT=
     620                 : {LOGRECTYPE_FIXEDLENGTH, 0, 0, NULL,
     621                 :  write_hook_for_commit, NULL, 0, "commit", LOGREC_IS_GROUP_ITSELF, NULL,
     622                 :  NULL};
     623                 : 
     624                 : static LOG_DESC INIT_LOGREC_COMMIT_WITH_UNDO_PURGE=
     625                 : {LOGRECTYPE_PSEUDOFIXEDLENGTH, 5, 5, NULL, write_hook_for_commit, NULL, 1,
     626                 :  "commit_with_undo_purge", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     627                 : 
     628                 : static LOG_DESC INIT_LOGREC_CHECKPOINT=
     629                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
     630                 :  "checkpoint", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     631                 : 
     632                 : static LOG_DESC INIT_LOGREC_REDO_CREATE_TABLE=
     633                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 1 + 2, NULL, NULL, NULL, 0,
     634                 : "redo_create_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     635                 : 
     636                 : static LOG_DESC INIT_LOGREC_REDO_RENAME_TABLE=
     637                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
     638                 :  "redo_rename_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     639                 : 
     640                 : static LOG_DESC INIT_LOGREC_REDO_DROP_TABLE=
     641                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
     642                 :  "redo_drop_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     643                 : 
     644                 : static LOG_DESC INIT_LOGREC_REDO_DELETE_ALL=
     645                 : {LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE, FILEID_STORE_SIZE,
     646                 :  NULL, write_hook_for_redo_delete_all, NULL, 0,
     647                 :  "redo_delete_all", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     648                 : 
     649                 : static LOG_DESC INIT_LOGREC_REDO_REPAIR_TABLE=
     650                 : {LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE + 8 + 8, FILEID_STORE_SIZE + 8 + 8,
     651                 :  NULL, NULL, NULL, 0,
     652                 :  "redo_repair_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     653                 : 
     654                 : static LOG_DESC INIT_LOGREC_FILE_ID=
     655                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 2, NULL, write_hook_for_file_id, NULL, 0,
     656                 :  "file_id", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     657                 : 
     658                 : static LOG_DESC INIT_LOGREC_LONG_TRANSACTION_ID=
     659                 : {LOGRECTYPE_FIXEDLENGTH, 6, 6, NULL, NULL, NULL, 0,
     660                 :  "long_transaction_id", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     661                 : 
     662                 : static LOG_DESC INIT_LOGREC_INCOMPLETE_LOG=
     663                 : {LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE, FILEID_STORE_SIZE,
     664                 :  NULL, NULL, NULL, 0,
     665                 :  "incomplete_log", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     666                 : 
     667                 : static LOG_DESC INIT_LOGREC_INCOMPLETE_GROUP=
     668                 : {LOGRECTYPE_FIXEDLENGTH, 0, 0,
     669                 :  NULL, NULL, NULL, 0,
     670                 :  "incomplete_group", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     671                 : 
     672                 : static LOG_DESC INIT_LOGREC_UNDO_BULK_INSERT=
     673                 : {LOGRECTYPE_VARIABLE_LENGTH, 0,
     674                 :  LSN_STORE_SIZE + FILEID_STORE_SIZE,
     675                 :  NULL, write_hook_for_undo_bulk_insert, NULL, 1,
     676                 :  "undo_bulk_insert", LOGREC_LAST_IN_GROUP, NULL, NULL};
     677                 : 
     678                 : static LOG_DESC INIT_LOGREC_REDO_BITMAP_NEW_PAGE=
     679                 : {LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2,
     680                 :  FILEID_STORE_SIZE + PAGE_STORE_SIZE * 2,
     681                 :  NULL, NULL, NULL, 0,
     682                 :  "redo_create_bitmap", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     683                 : 
     684                 : static LOG_DESC INIT_LOGREC_IMPORTED_TABLE=
     685                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
     686                 :  "imported_table", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     687                 : 
     688                 : static LOG_DESC INIT_LOGREC_DEBUG_INFO=
     689                 : {LOGRECTYPE_VARIABLE_LENGTH, 0, 0, NULL, NULL, NULL, 0,
     690                 :  "info", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
     691                 : 
     692                 : const myf log_write_flags= MY_WME | MY_NABP | MY_WAIT_IF_FULL;
     693                 : 
     694                 : void translog_table_init()
     695               5 : {
     696                 :   int i;
     697               5 :   log_record_type_descriptor[LOGREC_RESERVED_FOR_CHUNKS23]=
     698                 :     INIT_LOGREC_RESERVED_FOR_CHUNKS23;
     699               5 :   log_record_type_descriptor[LOGREC_REDO_INSERT_ROW_HEAD]=
     700                 :     INIT_LOGREC_REDO_INSERT_ROW_HEAD;
     701               5 :   log_record_type_descriptor[LOGREC_REDO_INSERT_ROW_TAIL]=
     702                 :     INIT_LOGREC_REDO_INSERT_ROW_TAIL;
     703               5 :   log_record_type_descriptor[LOGREC_REDO_NEW_ROW_HEAD]=
     704                 :     INIT_LOGREC_REDO_NEW_ROW_HEAD;
     705               5 :   log_record_type_descriptor[LOGREC_REDO_NEW_ROW_TAIL]=
     706                 :     INIT_LOGREC_REDO_NEW_ROW_TAIL;
     707               5 :   log_record_type_descriptor[LOGREC_REDO_INSERT_ROW_BLOBS]=
     708                 :     INIT_LOGREC_REDO_INSERT_ROW_BLOBS;
     709               5 :   log_record_type_descriptor[LOGREC_REDO_PURGE_ROW_HEAD]=
     710                 :     INIT_LOGREC_REDO_PURGE_ROW_HEAD;
     711               5 :   log_record_type_descriptor[LOGREC_REDO_PURGE_ROW_TAIL]=
     712                 :     INIT_LOGREC_REDO_PURGE_ROW_TAIL;
     713               5 :   log_record_type_descriptor[LOGREC_REDO_FREE_BLOCKS]=
     714                 :     INIT_LOGREC_REDO_FREE_BLOCKS;
     715               5 :   log_record_type_descriptor[LOGREC_REDO_FREE_HEAD_OR_TAIL]=
     716                 :     INIT_LOGREC_REDO_FREE_HEAD_OR_TAIL;
     717               5 :   log_record_type_descriptor[LOGREC_REDO_DELETE_ROW]=
     718                 :     INIT_LOGREC_REDO_DELETE_ROW;
     719               5 :   log_record_type_descriptor[LOGREC_REDO_UPDATE_ROW_HEAD]=
     720                 :     INIT_LOGREC_REDO_UPDATE_ROW_HEAD;
     721               5 :   log_record_type_descriptor[LOGREC_REDO_INDEX]=
     722                 :     INIT_LOGREC_REDO_INDEX;
     723               5 :   log_record_type_descriptor[LOGREC_REDO_INDEX_NEW_PAGE]=
     724                 :     INIT_LOGREC_REDO_INDEX_NEW_PAGE;
     725               5 :   log_record_type_descriptor[LOGREC_REDO_INDEX_FREE_PAGE]=
     726                 :     INIT_LOGREC_REDO_INDEX_FREE_PAGE;
     727               5 :   log_record_type_descriptor[LOGREC_REDO_UNDELETE_ROW]=
     728                 :     INIT_LOGREC_REDO_UNDELETE_ROW;
     729               5 :   log_record_type_descriptor[LOGREC_CLR_END]=
     730                 :     INIT_LOGREC_CLR_END;
     731               5 :   log_record_type_descriptor[LOGREC_PURGE_END]=
     732                 :     INIT_LOGREC_PURGE_END;
     733               5 :   log_record_type_descriptor[LOGREC_UNDO_ROW_INSERT]=
     734                 :     INIT_LOGREC_UNDO_ROW_INSERT;
     735               5 :   log_record_type_descriptor[LOGREC_UNDO_ROW_DELETE]=
     736                 :     INIT_LOGREC_UNDO_ROW_DELETE;
     737               5 :   log_record_type_descriptor[LOGREC_UNDO_ROW_UPDATE]=
     738                 :     INIT_LOGREC_UNDO_ROW_UPDATE;
     739               5 :   log_record_type_descriptor[LOGREC_UNDO_KEY_INSERT]=
     740                 :     INIT_LOGREC_UNDO_KEY_INSERT;
     741               5 :   log_record_type_descriptor[LOGREC_UNDO_KEY_INSERT_WITH_ROOT]=
     742                 :     INIT_LOGREC_UNDO_KEY_INSERT_WITH_ROOT;
     743               5 :   log_record_type_descriptor[LOGREC_UNDO_KEY_DELETE]=
     744                 :     INIT_LOGREC_UNDO_KEY_DELETE;
     745               5 :   log_record_type_descriptor[LOGREC_UNDO_KEY_DELETE_WITH_ROOT]=
     746                 :     INIT_LOGREC_UNDO_KEY_DELETE_WITH_ROOT;
     747               5 :   log_record_type_descriptor[LOGREC_PREPARE]=
     748                 :     INIT_LOGREC_PREPARE;
     749               5 :   log_record_type_descriptor[LOGREC_PREPARE_WITH_UNDO_PURGE]=
     750                 :     INIT_LOGREC_PREPARE_WITH_UNDO_PURGE;
     751               5 :   log_record_type_descriptor[LOGREC_COMMIT]=
     752                 :     INIT_LOGREC_COMMIT;
     753               5 :   log_record_type_descriptor[LOGREC_COMMIT_WITH_UNDO_PURGE]=
     754                 :     INIT_LOGREC_COMMIT_WITH_UNDO_PURGE;
     755               5 :   log_record_type_descriptor[LOGREC_CHECKPOINT]=
     756                 :     INIT_LOGREC_CHECKPOINT;
     757               5 :   log_record_type_descriptor[LOGREC_REDO_CREATE_TABLE]=
     758                 :     INIT_LOGREC_REDO_CREATE_TABLE;
     759               5 :   log_record_type_descriptor[LOGREC_REDO_RENAME_TABLE]=
     760                 :     INIT_LOGREC_REDO_RENAME_TABLE;
     761               5 :   log_record_type_descriptor[LOGREC_REDO_DROP_TABLE]=
     762                 :     INIT_LOGREC_REDO_DROP_TABLE;
     763               5 :   log_record_type_descriptor[LOGREC_REDO_DELETE_ALL]=
     764                 :     INIT_LOGREC_REDO_DELETE_ALL;
     765               5 :   log_record_type_descriptor[LOGREC_REDO_REPAIR_TABLE]=
     766                 :     INIT_LOGREC_REDO_REPAIR_TABLE;
     767               5 :   log_record_type_descriptor[LOGREC_FILE_ID]=
     768                 :     INIT_LOGREC_FILE_ID;
     769               5 :   log_record_type_descriptor[LOGREC_LONG_TRANSACTION_ID]=
     770                 :     INIT_LOGREC_LONG_TRANSACTION_ID;
     771               5 :   log_record_type_descriptor[LOGREC_INCOMPLETE_LOG]=
     772                 :     INIT_LOGREC_INCOMPLETE_LOG;
     773               5 :   log_record_type_descriptor[LOGREC_INCOMPLETE_GROUP]=
     774                 :     INIT_LOGREC_INCOMPLETE_GROUP;
     775               5 :   log_record_type_descriptor[LOGREC_UNDO_BULK_INSERT]=
     776                 :     INIT_LOGREC_UNDO_BULK_INSERT;
     777               5 :   log_record_type_descriptor[LOGREC_REDO_BITMAP_NEW_PAGE]=
     778                 :     INIT_LOGREC_REDO_BITMAP_NEW_PAGE;
     779               5 :   log_record_type_descriptor[LOGREC_IMPORTED_TABLE]=
     780                 :     INIT_LOGREC_IMPORTED_TABLE;
     781               5 :   log_record_type_descriptor[LOGREC_DEBUG_INFO]=
     782                 :     INIT_LOGREC_DEBUG_INFO;
     783                 : 
     784             110 :   for (i= LOGREC_FIRST_FREE; i < LOGREC_NUMBER_OF_TYPES; i++)
     785             105 :     log_record_type_descriptor[i].rclass= LOGRECTYPE_NOT_ALLOWED;
     786                 : #ifndef DBUG_OFF
     787               5 :   check_translog_description_table(LOGREC_FIRST_FREE -1);
     788                 : #endif
     789                 : }
     790                 : 
     791                 : 
     792                 : /* all possible flags page overheads */
     793                 : static uint page_overhead[TRANSLOG_FLAGS_NUM];
     794                 : 
     795                 : typedef struct st_translog_validator_data
     796                 : {
     797                 :   TRANSLOG_ADDRESS *addr;
     798                 :   my_bool was_recovered;
     799                 : } TRANSLOG_VALIDATOR_DATA;
     800                 : 
     801                 : 
     802                 : /*
     803                 :   Check cursor/buffer consistence
     804                 : 
     805                 :   SYNOPSIS
     806                 :     translog_check_cursor
     807                 :     cursor               cursor which will be checked
     808                 : */
     809                 : 
     810                 : static void translog_check_cursor(struct st_buffer_cursor *cursor
     811                 :                                  __attribute__((unused)))
     812              49 : {
     813              49 :   DBUG_ASSERT(cursor->chaser ||
     814                 :               ((ulong) (cursor->ptr - cursor->buffer->buffer) ==
     815                 :                cursor->buffer->size));
     816              49 :   DBUG_ASSERT(cursor->buffer->buffer_no == cursor->buffer_no);
     817              49 :   DBUG_ASSERT((cursor->ptr -cursor->buffer->buffer) %TRANSLOG_PAGE_SIZE ==
     818                 :               cursor->current_page_fill % TRANSLOG_PAGE_SIZE);
     819              49 :   DBUG_ASSERT(cursor->current_page_fill <= TRANSLOG_PAGE_SIZE);
     820                 : }
     821                 : 
     822                 : 
     823                 : /**
     824                 :   @brief switch the loghandler in read only mode in case of write error
     825                 : */
     826                 : 
     827                 : void translog_stop_writing()
     828               0 : {
     829               0 :   DBUG_ENTER("translog_stop_writing");
     830               0 :   DBUG_PRINT("error", ("errno: %d   my_errno: %d", errno, my_errno));
     831               0 :   translog_status= (translog_status == TRANSLOG_SHUTDOWN ?
     832                 :                     TRANSLOG_UNINITED :
     833                 :                     TRANSLOG_READONLY);
     834               0 :   log_descriptor.is_everything_flushed= 1;
     835               0 :   log_descriptor.open_flags= O_BINARY | O_RDONLY;
     836               0 :   DBUG_ASSERT(0);
     837                 :   DBUG_VOID_RETURN;
     838                 : }
     839                 : 
     840                 : 
     841                 : /*
     842                 :   @brief Get file name of the log by log number
     843                 : 
     844                 :   @param file_no         Number of the log we want to open
     845                 :   @param path            Pointer to buffer where file name will be
     846                 :                          stored (must be FN_REFLEN bytes at least)
     847                 : 
     848                 :   @return pointer to path
     849                 : */
     850                 : 
     851                 : char *translog_filename_by_fileno(uint32 file_no, char *path)
     852               9 : {
     853                 :   char buff[11], *end;
     854                 :   uint length;
     855               9 :   DBUG_ENTER("translog_filename_by_fileno");
     856               9 :   DBUG_ASSERT(file_no <= 0xfffffff);
     857                 : 
     858                 :   /* log_descriptor.directory is already formated */
     859               9 :   end= strxmov(path, log_descriptor.directory, "maria_log.0000000", NullS);
     860               9 :   length= (uint) (int10_to_str(file_no, buff, 10) - buff);
     861               9 :   strmov(end - length +1, buff);
     862                 : 
     863               9 :   DBUG_PRINT("info", ("Path: '%s'  path: 0x%lx", path, (ulong) path));
     864               9 :   DBUG_RETURN(path);
     865                 : }
     866                 : 
     867                 : 
     868                 : /**
     869                 :   @brief Create log file with given number without cache
     870                 : 
     871                 :   @param file_no         Number of the log we want to open
     872                 : 
     873                 :   retval -1  error
     874                 :   retval # file descriptor number
     875                 : */
     876                 : 
     877                 : static File create_logfile_by_number_no_cache(uint32 file_no)
     878               5 : {
     879                 :   File file;
     880                 :   char path[FN_REFLEN];
     881               5 :   DBUG_ENTER("create_logfile_by_number_no_cache");
     882                 : 
     883               5 :   if (translog_status != TRANSLOG_OK)
     884               0 :      DBUG_RETURN(-1);
     885                 : 
     886                 :   /* TODO: add O_DIRECT to open flags (when buffer is aligned) */
     887               5 :   if ((file= my_create(translog_filename_by_fileno(file_no, path),
     888                 :                        0, O_BINARY | O_RDWR, MYF(MY_WME))) < 0)
     889                 :   {
     890               0 :     DBUG_PRINT("error", ("Error %d during creating file '%s'", errno, path));
     891               0 :     translog_stop_writing();
     892               0 :     DBUG_RETURN(-1);
     893                 :   }
     894               5 :   if (sync_log_dir >= TRANSLOG_SYNC_DIR_NEWFILE &&
     895                 :       sync_dir(log_descriptor.directory_fd, MYF(MY_WME | MY_IGNORE_BADFD)))
     896                 :   {
     897               0 :     DBUG_PRINT("error", ("Error %d during syncing directory '%s'",
     898                 :                          errno, log_descriptor.directory));
     899               0 :     translog_stop_writing();
     900               0 :     DBUG_RETURN(-1);
     901                 :   }
     902               5 :   DBUG_PRINT("info", ("File: '%s'  handler: %d", path, file));
     903               5 :   DBUG_RETURN(file);
     904                 : }
     905                 : 
     906                 : /**
     907                 :   @brief Open (not create) log file with given number without cache
     908                 : 
     909                 :   @param file_no         Number of the log we want to open
     910                 : 
     911                 :   retval -1  error
     912                 :   retval # file descriptor number
     913                 : */
     914                 : 
     915                 : static File open_logfile_by_number_no_cache(uint32 file_no)
     916               0 : {
     917                 :   File file;
     918                 :   char path[FN_REFLEN];
     919               0 :   DBUG_ENTER("open_logfile_by_number_no_cache");
     920                 : 
     921                 :   /* TODO: add O_DIRECT to open flags (when buffer is aligned) */
     922                 :   /* TODO: use my_create() */
     923               0 :   if ((file= my_open(translog_filename_by_fileno(file_no, path),
     924                 :                      log_descriptor.open_flags,
     925                 :                      MYF(MY_WME))) < 0)
     926                 :   {
     927               0 :     DBUG_PRINT("error", ("Error %d during opening file '%s'", errno, path));
     928               0 :     DBUG_RETURN(-1);
     929                 :   }
     930               0 :   DBUG_PRINT("info", ("File: '%s'  handler: %d", path, file));
     931               0 :   DBUG_RETURN(file);
     932                 : }
     933                 : 
     934                 : 
     935                 : /**
     936                 :   @brief get file descriptor by given number using cache
     937                 : 
     938                 :   @param file_no         Number of the log we want to open
     939                 : 
     940                 :   retval # file descriptor
     941                 :   retval NULL file is not opened
     942                 : */
     943                 : 
     944                 : static TRANSLOG_FILE *get_logfile_by_number(uint32 file_no)
     945               4 : {
     946                 :   TRANSLOG_FILE *file;
     947               4 :   DBUG_ENTER("get_logfile_by_number");
     948               4 :   rw_rdlock(&log_descriptor.open_files_lock);
     949               4 :   if (log_descriptor.max_file - file_no >=
     950                 :       log_descriptor.open_files.elements)
     951                 :   {
     952               0 :     DBUG_PRINT("info", ("File #%u is not opened", file_no));
     953               0 :     rw_unlock(&log_descriptor.open_files_lock);
     954               0 :     DBUG_RETURN(NULL);
     955                 :   }
     956               4 :   DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
     957                 :               log_descriptor.open_files.elements);
     958               4 :   DBUG_ASSERT(log_descriptor.max_file >= file_no);
     959               4 :   DBUG_ASSERT(log_descriptor.min_file <= file_no);
     960                 : 
     961               4 :   file= *dynamic_element(&log_descriptor.open_files,
     962                 :                          log_descriptor.max_file - file_no, TRANSLOG_FILE **);
     963               4 :   rw_unlock(&log_descriptor.open_files_lock);
     964               4 :   DBUG_PRINT("info", ("File 0x%lx File no: %lu, File handler: %d",
     965                 :                       (ulong)file, (ulong)file_no,
     966                 :                       (file ? file->handler.file : -1)));
     967               4 :   DBUG_ASSERT(!file || file->number == file_no);
     968               4 :   DBUG_RETURN(file);
     969                 : }
     970                 : 
     971                 : 
     972                 : /**
     973                 :   @brief get current file descriptor
     974                 : 
     975                 :   retval # file descriptor
     976                 : */
     977                 : 
     978                 : static TRANSLOG_FILE *get_current_logfile()
     979              19 : {
     980                 :   TRANSLOG_FILE *file;
     981              19 :   rw_rdlock(&log_descriptor.open_files_lock);
     982              19 :   DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
     983                 :               log_descriptor.open_files.elements);
     984              19 :   file= *dynamic_element(&log_descriptor.open_files, 0, TRANSLOG_FILE **);
     985              19 :   rw_unlock(&log_descriptor.open_files_lock);
     986              19 :   return (file);
     987                 : }
     988                 : 
     989                 : uchar   NEAR maria_trans_file_magic[]=
     990                 : { (uchar) 254, (uchar) 254, (uchar) 11, '\001', 'M', 'A', 'R', 'I', 'A',
     991                 :  'L', 'O', 'G' };
     992                 : #define LOG_HEADER_DATA_SIZE (sizeof(maria_trans_file_magic) + \
     993                 :                               8 + 4 + 4 + 4 + 2 + 3 + \
     994                 :                               LSN_STORE_SIZE)
     995                 : 
     996                 : 
     997                 : /*
     998                 :   Write log file page header in the just opened new log file
     999                 : 
    1000                 :   SYNOPSIS
    1001                 :     translog_write_file_header();
    1002                 : 
    1003                 :    NOTES
    1004                 :     First page is just a marker page; We don't store any real log data in it.
    1005                 : 
    1006                 :   RETURN
    1007                 :     0 OK
    1008                 :     1 ERROR
    1009                 : */
    1010                 : 
    1011                 : static my_bool translog_write_file_header()
    1012               5 : {
    1013                 :   TRANSLOG_FILE *file;
    1014                 :   ulonglong timestamp;
    1015               5 :   uchar page_buff[TRANSLOG_PAGE_SIZE], *page= page_buff;
    1016                 :   my_bool rc;
    1017               5 :   DBUG_ENTER("translog_write_file_header");
    1018                 : 
    1019                 :   /* file tag */
    1020               5 :   memcpy(page, maria_trans_file_magic, sizeof(maria_trans_file_magic));
    1021               5 :   page+= sizeof(maria_trans_file_magic);
    1022                 :   /* timestamp */
    1023               5 :   timestamp= my_getsystime();
    1024               5 :   int8store(page, timestamp);
    1025               5 :   page+= 8;
    1026                 :   /* maria version */
    1027               5 :   int4store(page, TRANSLOG_VERSION_ID);
    1028               5 :   page+= 4;
    1029                 :   /* mysql version (MYSQL_VERSION_ID) */
    1030               5 :   int4store(page, log_descriptor.server_version);
    1031               5 :   page+= 4;
    1032                 :   /* server ID */
    1033               5 :   int4store(page, log_descriptor.server_id);
    1034               5 :   page+= 4;
    1035                 :   /* loghandler page_size */
    1036               5 :   int2store(page, TRANSLOG_PAGE_SIZE - 1);
    1037               5 :   page+= 2;
    1038                 :   /* file number */
    1039               5 :   int3store(page, LSN_FILE_NO(log_descriptor.horizon));
    1040               5 :   page+= 3;
    1041               5 :   lsn_store(page, LSN_IMPOSSIBLE);
    1042               5 :   page+= LSN_STORE_SIZE;
    1043               5 :   memset(page, TRANSLOG_FILLER, sizeof(page_buff) - (page- page_buff));
    1044                 : 
    1045               5 :   file= get_current_logfile();
    1046               5 :   rc= my_pwrite(file->handler.file, page_buff, sizeof(page_buff), 0,
    1047                 :                 log_write_flags) != 0;
    1048                 :   /*
    1049                 :     Dropping the flag in such way can make false alarm: signalling than the
    1050                 :     file in not sync when it is sync, but the situation is quite rare and
    1051                 :     protections with mutexes give much more overhead to the whole engine
    1052                 :   */
    1053               5 :   file->is_sync= 0;
    1054               5 :   DBUG_RETURN(rc);
    1055                 : }
    1056                 : 
    1057                 : /*
    1058                 :   @brief write the new LSN on the given file header
    1059                 : 
    1060                 :   @param file            The file descriptor
    1061                 :   @param lsn             That LSN which should be written
    1062                 : 
    1063                 :   @retval 0 OK
    1064                 :   @retval 1 Error
    1065                 : */
    1066                 : 
    1067                 : static my_bool translog_max_lsn_to_header(File file, LSN lsn)
    1068               0 : {
    1069                 :   uchar lsn_buff[LSN_STORE_SIZE];
    1070               0 :   DBUG_ENTER("translog_max_lsn_to_header");
    1071               0 :   DBUG_PRINT("enter", ("File descriptor: %ld  "
    1072                 :                        "lsn: (%lu,0x%lx)",
    1073                 :                        (long) file,
    1074                 :                        LSN_IN_PARTS(lsn)));
    1075                 : 
    1076               0 :   lsn_store(lsn_buff, lsn);
    1077                 : 
    1078               0 :   DBUG_RETURN(my_pwrite(file, lsn_buff,
    1079                 :                         LSN_STORE_SIZE,
    1080                 :                         (LOG_HEADER_DATA_SIZE - LSN_STORE_SIZE),
    1081                 :                         log_write_flags) != 0 ||
    1082                 :               my_sync(file, MYF(MY_WME)) != 0);
    1083                 : }
    1084                 : 
    1085                 : 
    1086                 : /*
    1087                 :   Information from transaction log file header
    1088                 : */
    1089                 : 
    1090                 : typedef struct st_loghandler_file_info
    1091                 : {
    1092                 :   /*
    1093                 :     LSN_IMPOSSIBLE for current file (not finished file).
    1094                 :     Maximum LSN of the record which parts stored in the
    1095                 :     file.
    1096                 :   */
    1097                 :   LSN max_lsn;
    1098                 :   ulonglong timestamp;   /* Time stamp */
    1099                 :   ulong maria_version;   /* Version of maria loghandler */
    1100                 :   ulong mysql_version;   /* Version of mysql server */
    1101                 :   ulong server_id;       /* Server ID */
    1102                 :   ulong page_size;       /* Loghandler page size */
    1103                 :   ulong file_number;     /* Number of the file (from the file header) */
    1104                 : } LOGHANDLER_FILE_INFO;
    1105                 : 
    1106                 : /*
    1107                 :   @brief Extract hander file information from loghandler file page
    1108                 : 
    1109                 :   @param desc header information descriptor to be filled with information
    1110                 :   @param page_buff buffer with the page content
    1111                 : */
    1112                 : 
    1113                 : static void translog_interpret_file_header(LOGHANDLER_FILE_INFO *desc,
    1114                 :                                            uchar *page_buff)
    1115               0 : {
    1116                 :   uchar *ptr;
    1117                 : 
    1118               0 :   ptr= page_buff + sizeof(maria_trans_file_magic);
    1119               0 :   desc->timestamp= uint8korr(ptr);
    1120               0 :   ptr+= 8;
    1121               0 :   desc->maria_version= uint4korr(ptr);
    1122               0 :   ptr+= 4;
    1123               0 :   desc->mysql_version= uint4korr(ptr);
    1124               0 :   ptr+= 4;
    1125               0 :   desc->server_id= uint4korr(ptr + 4);
    1126               0 :   ptr+= 4;
    1127               0 :   desc->page_size= uint2korr(ptr) + 1;
    1128               0 :   ptr+= 2;
    1129               0 :   desc->file_number= uint3korr(ptr);
    1130               0 :   ptr+=3;
    1131               0 :   desc->max_lsn= lsn_korr(ptr);
    1132                 : }
    1133                 : 
    1134                 : 
    1135                 : /*
    1136                 :   @brief Read hander file information from loghandler file
    1137                 : 
    1138                 :   @param desc header information descriptor to be filled with information
    1139                 :   @param file file descriptor to read
    1140                 : 
    1141                 :   @retval 0 OK
    1142                 :   @retval 1 Error
    1143                 : */
    1144                 : 
    1145                 : my_bool translog_read_file_header(LOGHANDLER_FILE_INFO *desc, File file)
    1146               0 : {
    1147                 :   uchar page_buff[LOG_HEADER_DATA_SIZE];
    1148               0 :   DBUG_ENTER("translog_read_file_header");
    1149                 : 
    1150               0 :   if (my_pread(file, page_buff,
    1151                 :                sizeof(page_buff), 0, MYF(MY_FNABP | MY_WME)))
    1152                 :   {
    1153               0 :     DBUG_PRINT("info", ("log read fail error: %d", my_errno));
    1154               0 :     DBUG_RETURN(1);
    1155                 :   }
    1156               0 :   translog_interpret_file_header(desc, page_buff);
    1157               0 :   DBUG_PRINT("info", ("timestamp: %llu  maria ver: %lu mysql ver: %lu  "
    1158                 :                       "server id %lu page size %lu file number %lu  "
    1159                 :                       "max lsn: (%lu,0x%lx)",
    1160                 :                       (ulonglong) desc->timestamp,
    1161                 :                       (ulong) desc->maria_version,
    1162                 :                       (ulong) desc->mysql_version,
    1163                 :                       (ulong) desc->server_id,
    1164                 :                       desc->page_size, (ulong) desc->file_number,
    1165                 :                       LSN_IN_PARTS(desc->max_lsn)));
    1166               0 :   DBUG_RETURN(0);
    1167                 : }
    1168                 : 
    1169                 : 
    1170                 : /*
    1171                 :   @brief set the lsn to the files from_file - to_file if it is greater
    1172                 :   then written in the file
    1173                 : 
    1174                 :   @param from_file       first file number (min)
    1175                 :   @param to_file         last file number (max)
    1176                 :   @param lsn             the lsn for writing
    1177                 :   @param is_locked       true if current thread locked the log handler
    1178                 : 
    1179                 :   @retval 0 OK
    1180                 :   @retval 1 Error
    1181                 : */
    1182                 : 
    1183                 : static my_bool translog_set_lsn_for_files(uint32 from_file, uint32 to_file,
    1184                 :                                           LSN lsn, my_bool is_locked)
    1185              18 : {
    1186                 :   uint32 file;
    1187              18 :   DBUG_ENTER("translog_set_lsn_for_files");
    1188              18 :   DBUG_PRINT("enter", ("From: %lu  to: %lu  lsn: (%lu,0x%lx)  locked: %d",
    1189                 :                        (ulong) from_file, (ulong) to_file,
    1190                 :                        LSN_IN_PARTS(lsn),
    1191                 :                        is_locked));
    1192              18 :   DBUG_ASSERT(from_file <= to_file);
    1193              18 :   DBUG_ASSERT(from_file > 0); /* we have not file 0 */
    1194                 : 
    1195                 :   /* Checks the current file (not finished yet file) */
    1196              18 :   if (!is_locked)
    1197               0 :     translog_lock();
    1198              18 :   if (to_file == (uint32) LSN_FILE_NO(log_descriptor.horizon))
    1199                 :   {
    1200              18 :     if (likely(cmp_translog_addr(lsn, log_descriptor.max_lsn) > 0))
    1201              18 :       log_descriptor.max_lsn= lsn;
    1202              18 :     to_file--;
    1203                 :   }
    1204              18 :   if (!is_locked)
    1205               0 :     translog_unlock();
    1206                 : 
    1207                 :   /* Checks finished files if they are */
    1208              18 :   pthread_mutex_lock(&log_descriptor.file_header_lock);
    1209              18 :   for (file= from_file; file <= to_file; file++)
    1210                 :   {
    1211                 :     LOGHANDLER_FILE_INFO info;
    1212               0 :     File fd= open_logfile_by_number_no_cache(file);
    1213               0 :     if ((fd < 0) ||
    1214                 :         ((translog_read_file_header(&info, fd) ||
    1215                 :           (cmp_translog_addr(lsn, info.max_lsn) > 0 &&
    1216                 :            translog_max_lsn_to_header(fd, lsn))) |
    1217                 :           my_close(fd, MYF(MY_WME))))
    1218                 :     {
    1219               0 :       translog_stop_writing();
    1220               0 :       DBUG_RETURN(1);
    1221                 :     }
    1222                 :   }
    1223              18 :   pthread_mutex_unlock(&log_descriptor.file_header_lock);
    1224                 : 
    1225              18 :   DBUG_RETURN(0);
    1226                 : }
    1227                 : 
    1228                 : 
    1229                 : /* descriptor of file in unfinished_files */
    1230                 : struct st_file_counter
    1231                 : {
    1232                 :   uint32 file;            /* file number */
    1233                 :   uint32 counter;         /* counter for started writes */
    1234                 : };
    1235                 : 
    1236                 : 
    1237                 : /*
    1238                 :   @brief mark file "in progress" (for multi-group records)
    1239                 : 
    1240                 :   @param file            log file number
    1241                 : */
    1242                 : 
    1243                 : static void translog_mark_file_unfinished(uint32 file)
    1244               0 : {
    1245                 :   int place, i;
    1246                 :   struct st_file_counter fc, *fc_ptr;
    1247                 : 
    1248               0 :   DBUG_ENTER("translog_mark_file_unfinished");
    1249               0 :   DBUG_PRINT("enter", ("file: %lu", (ulong) file));
    1250                 : 
    1251               0 :   fc.file= file; fc.counter= 1;
    1252               0 :   pthread_mutex_lock(&log_descriptor.unfinished_files_lock);
    1253                 : 
    1254               0 :   if (log_descriptor.unfinished_files.elements == 0)
    1255                 :   {
    1256               0 :     insert_dynamic(&log_descriptor.unfinished_files, (uchar*) &fc);
    1257               0 :     DBUG_PRINT("info", ("The first element inserted"));
    1258               0 :     goto end;
    1259                 :   }
    1260                 : 
    1261               0 :   for (place= log_descriptor.unfinished_files.elements - 1;
    1262               0 :        place >= 0;
    1263               0 :        place--)
    1264                 :   {
    1265               0 :     fc_ptr= dynamic_element(&log_descriptor.unfinished_files,
    1266                 :                             place, struct st_file_counter *);
    1267               0 :     if (fc_ptr->file <= file)
    1268               0 :       break;
    1269                 :   }
    1270                 : 
    1271               0 :   if (place >= 0 && fc_ptr->file == file)
    1272                 :   {
    1273               0 :      fc_ptr->counter++;
    1274               0 :      DBUG_PRINT("info", ("counter increased"));
    1275               0 :      goto end;
    1276                 :   }
    1277                 : 
    1278               0 :   if (place == (int)log_descriptor.unfinished_files.elements)
    1279                 :   {
    1280               0 :     insert_dynamic(&log_descriptor.unfinished_files, (uchar*) &fc);
    1281               0 :     DBUG_PRINT("info", ("The last element inserted"));
    1282               0 :     goto end;
    1283                 :   }
    1284                 :   /* shift and assign new element */
    1285               0 :   insert_dynamic(&log_descriptor.unfinished_files,
    1286                 :                  (uchar*)
    1287                 :                  dynamic_element(&log_descriptor.unfinished_files,
    1288                 :                                  log_descriptor.unfinished_files.elements- 1,
    1289                 :                                  struct st_file_counter *));
    1290               0 :   for(i= log_descriptor.unfinished_files.elements - 1; i > place; i--)
    1291                 :   {
    1292                 :     /* we do not use set_dynamic() to avoid unneeded checks */
    1293               0 :     memcpy(dynamic_element(&log_descriptor.unfinished_files,
    1294                 :                            i, struct st_file_counter *),
    1295                 :            dynamic_element(&log_descriptor.unfinished_files,
    1296                 :                            i + 1, struct st_file_counter *),
    1297                 :            sizeof(struct st_file_counter));
    1298                 :   }
    1299               0 :   memcpy(dynamic_element(&log_descriptor.unfinished_files,
    1300                 :                          place + 1, struct st_file_counter *),
    1301                 :          &fc, sizeof(struct st_file_counter));
    1302               0 : end:
    1303               0 :   pthread_mutex_unlock(&log_descriptor.unfinished_files_lock);
    1304               0 :   DBUG_VOID_RETURN;
    1305                 : }
    1306                 : 
    1307                 : 
    1308                 : /*
    1309                 :   @brief remove file mark "in progress" (for multi-group records)
    1310                 : 
    1311                 :   @param file            log file number
    1312                 : */
    1313                 : 
    1314                 : static void translog_mark_file_finished(uint32 file)
    1315               0 : {
    1316                 :   int i;
    1317                 :   struct st_file_counter *fc_ptr;
    1318               0 :   DBUG_ENTER("translog_mark_file_finished");
    1319               0 :   DBUG_PRINT("enter", ("file: %lu", (ulong) file));
    1320                 : 
    1321               0 :   LINT_INIT(fc_ptr);
    1322                 : 
    1323               0 :   pthread_mutex_lock(&log_descriptor.unfinished_files_lock);
    1324                 : 
    1325               0 :   DBUG_ASSERT(log_descriptor.unfinished_files.elements > 0);
    1326               0 :   for (i= 0;
    1327               0 :        i < (int) log_descriptor.unfinished_files.elements;
    1328               0 :        i++)
    1329                 :   {
    1330               0 :     fc_ptr= dynamic_element(&log_descriptor.unfinished_files,
    1331                 :                             i, struct st_file_counter *);
    1332               0 :     if (fc_ptr->file == file)
    1333                 :     {
    1334               0 :       break;
    1335                 :     }
    1336                 :   }
    1337               0 :   DBUG_ASSERT(i < (int) log_descriptor.unfinished_files.elements);
    1338                 : 
    1339               0 :   if (! --fc_ptr->counter)
    1340               0 :     delete_dynamic_element(&log_descriptor.unfinished_files, i);
    1341               0 :   pthread_mutex_unlock(&log_descriptor.unfinished_files_lock);
    1342               0 :   DBUG_VOID_RETURN;
    1343                 : }
    1344                 : 
    1345                 : 
    1346                 : /*
    1347                 :   @brief get max LSN of the record which parts stored in this file
    1348                 : 
    1349                 :   @param file            file number
    1350                 : 
    1351                 :   @return requested LSN or LSN_IMPOSSIBLE/LSN_ERROR
    1352                 :     @retval LSN_IMPOSSIBLE File is still not finished
    1353                 :     @retval LSN_ERROR Error opening file
    1354                 :     @retval # LSN of the record which parts stored in this file
    1355                 : */
    1356                 : 
    1357                 : LSN translog_get_file_max_lsn_stored(uint32 file)
    1358               0 : {
    1359               0 :   uint32 limit= FILENO_IMPOSSIBLE;
    1360               0 :   DBUG_ENTER("translog_get_file_max_lsn_stored");
    1361               0 :   DBUG_PRINT("enter", ("file: %lu", (ulong)file));
    1362               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    1363                 :               translog_status == TRANSLOG_READONLY);
    1364                 : 
    1365               0 :   pthread_mutex_lock(&log_descriptor.unfinished_files_lock);
    1366                 : 
    1367                 :   /* find file with minimum file number "in progress" */
    1368               0 :   if (log_descriptor.unfinished_files.elements > 0)
    1369                 :   {
    1370                 :     struct st_file_counter *fc_ptr;
    1371               0 :     fc_ptr= dynamic_element(&log_descriptor.unfinished_files,
    1372                 :                             0, struct st_file_counter *);
    1373               0 :     limit= fc_ptr->file; /* minimal file number "in progress" */
    1374                 :   }
    1375               0 :   pthread_mutex_unlock(&log_descriptor.unfinished_files_lock);
    1376                 : 
    1377                 :   /*
    1378                 :     if there is no "in progress file" then unfinished file is in progress
    1379                 :     for sure
    1380                 :   */
    1381               0 :   if (limit == FILENO_IMPOSSIBLE)
    1382                 :   {
    1383               0 :     TRANSLOG_ADDRESS horizon= translog_get_horizon();
    1384               0 :     limit= LSN_FILE_NO(horizon);
    1385                 :   }
    1386                 : 
    1387               0 :   if (file >= limit)
    1388                 :   {
    1389               0 :     DBUG_PRINT("info", ("The file in in progress"));
    1390               0 :     DBUG_RETURN(LSN_IMPOSSIBLE);
    1391                 :   }
    1392                 : 
    1393                 :   {
    1394                 :     LOGHANDLER_FILE_INFO info;
    1395               0 :     File fd= open_logfile_by_number_no_cache(file);
    1396               0 :     if ((fd < 0) ||
    1397                 :         (translog_read_file_header(&info, fd) | my_close(fd, MYF(MY_WME))))
    1398                 :     {
    1399               0 :       DBUG_PRINT("error", ("Can't read file header"));
    1400               0 :       DBUG_RETURN(LSN_ERROR);
    1401                 :     }
    1402               0 :     DBUG_PRINT("info", ("Max lsn: (%lu,0x%lx)",
    1403                 :                          LSN_IN_PARTS(info.max_lsn)));
    1404               0 :     DBUG_RETURN(info.max_lsn);
    1405                 :   }
    1406                 : }
    1407                 : 
    1408                 : /*
    1409                 :   Initialize transaction log file buffer
    1410                 : 
    1411                 :   SYNOPSIS
    1412                 :     translog_buffer_init()
    1413                 :     buffer               The buffer to initialize
    1414                 :     num                  Number of this buffer
    1415                 : 
    1416                 :   RETURN
    1417                 :     0  OK
    1418                 :     1  Error
    1419                 : */
    1420                 : 
    1421                 : static my_bool translog_buffer_init(struct st_translog_buffer *buffer, int num)
    1422              40 : {
    1423              40 :   DBUG_ENTER("translog_buffer_init");
    1424              40 :   buffer->prev_last_lsn= buffer->last_lsn= LSN_IMPOSSIBLE;
    1425              40 :   DBUG_PRINT("info", ("last_lsn  and prev_last_lsn set to 0  buffer: 0x%lx",
    1426                 :                       (ulong) buffer));
    1427                 : 
    1428              40 :   buffer->buffer_no= (uint8) num;
    1429                 :   /* This Buffer File */
    1430              40 :   buffer->file= NULL;
    1431              40 :   buffer->overlay= 0;
    1432                 :   /* cache for current log */
    1433              40 :   memset(buffer->buffer, TRANSLOG_FILLER, TRANSLOG_WRITE_BUFFER);
    1434                 :   /* Buffer size */
    1435              40 :   buffer->size= 0;
    1436                 :   /* cond of thread which is waiting for buffer filling */
    1437              40 :   if (pthread_cond_init(&buffer->waiting_filling_buffer, 0))
    1438               0 :     DBUG_RETURN(1);
    1439                 :   /* Number of records which are in copy progress */
    1440              40 :   buffer->copy_to_buffer_in_progress= 0;
    1441                 :   /* list of waiting buffer ready threads */
    1442              40 :   buffer->waiting_flush= 0;
    1443                 :   /*
    1444                 :     Buffers locked by fallowing mutex. As far as buffers create logical
    1445                 :     circle (after last buffer goes first) it trigger false alarm of deadlock
    1446                 :     detect system, so we remove check of deadlock for this buffers. In deed
    1447                 :     all mutex locks concentrated around current buffer except flushing
    1448                 :     thread (but it is only one thread). One thread can't take more then
    1449                 :     2 buffer locks at once. So deadlock is impossible here.
    1450                 : 
    1451                 :     To prevent false alarm of dead lock detection we switch dead lock
    1452                 :     detection for one buffer in the middle of the buffers chain. Excluding
    1453                 :     only one of eight buffers from deadlock detection hardly can hide other
    1454                 :     possible problems which include this mutexes.
    1455                 :   */
    1456              40 :   if (my_pthread_mutex_init(&buffer->mutex, MY_MUTEX_INIT_FAST,
    1457                 :                             "translog_buffer->mutex",
    1458                 :                             (num == TRANSLOG_BUFFERS_NO - 2 ?
    1459                 :                              MYF_NO_DEADLOCK_DETECTION : 0)) ||
    1460                 :       pthread_cond_init(&buffer->prev_sent_to_disk_cond, 0))
    1461               0 :     DBUG_RETURN(1);
    1462              40 :   buffer->is_closing_buffer= 0;
    1463              40 :   buffer->prev_sent_to_disk= LSN_IMPOSSIBLE;
    1464              40 :   buffer->prev_buffer_offset= LSN_IMPOSSIBLE;
    1465              40 :   buffer->ver= 0;
    1466              40 :   DBUG_RETURN(0);
    1467                 : }
    1468                 : 
    1469                 : 
    1470                 : /*
    1471                 :   @brief close transaction log file by descriptor
    1472                 : 
    1473                 :   @param file            pagegecache file descriptor reference
    1474                 : 
    1475                 :   @return Operation status
    1476                 :     @retval 0  OK
    1477                 :     @retval 1  Error
    1478                 : */
    1479                 : 
    1480                 : static my_bool translog_close_log_file(TRANSLOG_FILE *file)
    1481               4 : {
    1482               4 :   int rc= 0;
    1483               4 :   flush_pagecache_blocks(log_descriptor.pagecache, &file->handler,
    1484                 :                          FLUSH_RELEASE);
    1485                 :   /*
    1486                 :     Sync file when we close it
    1487                 :     TODO: sync only we have changed the log
    1488                 :   */
    1489               4 :   if (!file->is_sync)
    1490               4 :     rc= my_sync(file->handler.file, MYF(MY_WME));
    1491               4 :   rc|= my_close(file->handler.file, MYF(MY_WME));
    1492               4 :   my_free(file, MYF(0));
    1493               4 :   return test(rc);
    1494                 : }
    1495                 : 
    1496                 : 
    1497                 : /**
    1498                 :   @brief Dummy function for write failure (the log to not use
    1499                 :   pagecache writing)
    1500                 : */
    1501                 : 
    1502                 : void translog_dummy_write_failure(uchar *data __attribute__((unused)))
    1503               0 : {
    1504                 :   return;
    1505                 : }
    1506                 : 
    1507                 : 
    1508                 : /**
    1509                 :   @brief Initializes TRANSLOG_FILE structure
    1510                 : 
    1511                 :   @param file            reference on the file to initialize
    1512                 :   @param number          file number
    1513                 :   @param is_sync         is file synced on disk
    1514                 : */
    1515                 : 
    1516                 : static void translog_file_init(TRANSLOG_FILE *file, uint32 number,
    1517                 :                                my_bool is_sync)
    1518               5 : {
    1519               5 :   pagecache_file_init(file->handler, &translog_page_validator,
    1520                 :                       &translog_dummy_callback,
    1521                 :                       &translog_dummy_write_failure,
    1522                 :                       maria_flush_log_for_page_none, file);
    1523               5 :   file->number= number;
    1524               5 :   file->was_recovered= 0;
    1525               5 :   file->is_sync= is_sync;
    1526                 : }
    1527                 : 
    1528                 : 
    1529                 : /**
    1530                 :   @brief Create and fill header of new file.
    1531                 : 
    1532                 :   @note the caller must call it right after it has increased
    1533                 :    log_descriptor.horizon to the new file
    1534                 :    (log_descriptor.horizon+= LSN_ONE_FILE)
    1535                 : 
    1536                 : 
    1537                 :   @retval 0 OK
    1538                 :   @retval 1 Error
    1539                 : */
    1540                 : 
    1541                 : static my_bool translog_create_new_file()
    1542               0 : {
    1543               0 :   TRANSLOG_FILE *file= (TRANSLOG_FILE*)my_malloc(sizeof(TRANSLOG_FILE),
    1544                 :                                                  MYF(0));
    1545                 : 
    1546               0 :   TRANSLOG_FILE *old= get_current_logfile();
    1547               0 :   uint32 file_no= LSN_FILE_NO(log_descriptor.horizon);
    1548               0 :   DBUG_ENTER("translog_create_new_file");
    1549                 : 
    1550               0 :   if (file == NULL)
    1551               0 :     goto error;
    1552                 : 
    1553                 :   /*
    1554                 :     Writes max_lsn to the file header before finishing it (there is no need
    1555                 :     to lock file header buffer because it is still unfinished file, so only
    1556                 :     one thread can finish the file and nobody interested of LSN of current
    1557                 :     (unfinished) file, because no one can purge it).
    1558                 :   */
    1559               0 :   if (translog_max_lsn_to_header(old->handler.file, log_descriptor.max_lsn))
    1560               0 :     goto error;
    1561                 : 
    1562               0 :   rw_wrlock(&log_descriptor.open_files_lock);
    1563               0 :   DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
    1564                 :               log_descriptor.open_files.elements);
    1565               0 :   DBUG_ASSERT(file_no == log_descriptor.max_file + 1);
    1566               0 :   if (allocate_dynamic(&log_descriptor.open_files,
    1567                 :                        log_descriptor.max_file - log_descriptor.min_file + 2))
    1568               0 :     goto error_lock;
    1569               0 :   if ((file->handler.file=
    1570                 :        create_logfile_by_number_no_cache(file_no)) == -1)
    1571               0 :     goto error_lock;
    1572               0 :   translog_file_init(file, file_no, 0);
    1573                 : 
    1574                 :   /* this call just expand the array */
    1575               0 :   insert_dynamic(&log_descriptor.open_files, (uchar*)&file);
    1576               0 :   log_descriptor.max_file++;
    1577                 :   {
    1578               0 :     char *start= (char*) dynamic_element(&log_descriptor.open_files, 0,
    1579                 :                                          TRANSLOG_FILE**);
    1580               0 :     memmove(start + sizeof(TRANSLOG_FILE*), start,
    1581                 :             sizeof(TRANSLOG_FILE*) *
    1582                 :             (log_descriptor.max_file - log_descriptor.min_file + 1 - 1));
    1583                 :   }
    1584                 :   /* can't fail we because we expanded array */
    1585               0 :   set_dynamic(&log_descriptor.open_files, (uchar*)&file, 0);
    1586               0 :   DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
    1587                 :               log_descriptor.open_files.elements);
    1588               0 :   rw_unlock(&log_descriptor.open_files_lock);
    1589                 : 
    1590               0 :   DBUG_PRINT("info", ("file_no: %lu", (ulong)file_no));
    1591                 : 
    1592               0 :   if (translog_write_file_header())
    1593               0 :     DBUG_RETURN(1);
    1594                 : 
    1595               0 :   if (ma_control_file_write_and_force(last_checkpoint_lsn, file_no,
    1596                 :                                       max_trid_in_control_file,
    1597                 :                                       recovery_failures))
    1598                 :   {
    1599               0 :     translog_stop_writing();
    1600               0 :     DBUG_RETURN(1);
    1601                 :   }
    1602                 : 
    1603               0 :   DBUG_RETURN(0);
    1604                 : 
    1605               0 : error_lock:
    1606               0 :   rw_unlock(&log_descriptor.open_files_lock);
    1607               0 : error:
    1608               0 :   translog_stop_writing();
    1609               0 :   DBUG_RETURN(1);
    1610                 : }
    1611                 : 
    1612                 : 
    1613                 : /**
    1614                 :   @brief Locks the loghandler buffer.
    1615                 : 
    1616                 :   @param buffer          This buffer which should be locked
    1617                 : 
    1618                 :   @note See comment before buffer 'mutex' variable.
    1619                 : 
    1620                 :   @retval 0 OK
    1621                 :   @retval 1 Error
    1622                 : */
    1623                 : 
    1624                 : static void translog_buffer_lock(struct st_translog_buffer *buffer)
    1625              81 : {
    1626              81 :   DBUG_ENTER("translog_buffer_lock");
    1627              81 :   DBUG_PRINT("enter",
    1628                 :              ("Lock buffer #%u: (0x%lx)", (uint) buffer->buffer_no,
    1629                 :               (ulong) buffer));
    1630              81 :   pthread_mutex_lock(&buffer->mutex);
    1631              81 :   DBUG_VOID_RETURN;
    1632                 : }
    1633                 : 
    1634                 : 
    1635                 : /*
    1636                 :   Unlock the loghandler buffer
    1637                 : 
    1638                 :   SYNOPSIS
    1639                 :     translog_buffer_unlock()
    1640                 :     buffer               This buffer which should be unlocked
    1641                 : 
    1642                 :   RETURN
    1643                 :     0  OK
    1644                 :     1  Error
    1645                 : */
    1646                 : 
    1647                 : static void translog_buffer_unlock(struct st_translog_buffer *buffer)
    1648              81 : {
    1649              81 :   DBUG_ENTER("translog_buffer_unlock");
    1650              81 :   DBUG_PRINT("enter", ("Unlock buffer... #%u (0x%lx)",
    1651                 :                        (uint) buffer->buffer_no, (ulong) buffer));
    1652                 : 
    1653              81 :   pthread_mutex_unlock(&buffer->mutex);
    1654              81 :   DBUG_VOID_RETURN;
    1655                 : }
    1656                 : 
    1657                 : 
    1658                 : /*
    1659                 :   Write a header on the page
    1660                 : 
    1661                 :   SYNOPSIS
    1662                 :     translog_new_page_header()
    1663                 :     horizon              Where to write the page
    1664                 :     cursor               Where to write the page
    1665                 : 
    1666                 :   NOTE
    1667                 :     - space for page header should be checked before
    1668                 : */
    1669                 : 
    1670                 : static uchar translog_sector_random;
    1671                 : 
    1672                 : static void translog_new_page_header(TRANSLOG_ADDRESS *horizon,
    1673                 :                                      struct st_buffer_cursor *cursor)
    1674               5 : {
    1675                 :   uchar *ptr;
    1676                 : 
    1677               5 :   DBUG_ENTER("translog_new_page_header");
    1678               5 :   DBUG_ASSERT(cursor->ptr);
    1679                 : 
    1680               5 :   cursor->protected= 0;
    1681                 : 
    1682               5 :   ptr= cursor->ptr;
    1683                 :   /* Page number */
    1684               5 :   int3store(ptr, LSN_OFFSET(*horizon) / TRANSLOG_PAGE_SIZE);
    1685               5 :   ptr+= 3;
    1686                 :   /* File number */
    1687               5 :   int3store(ptr, LSN_FILE_NO(*horizon));
    1688               5 :   ptr+= 3;
    1689               5 :   DBUG_ASSERT(TRANSLOG_PAGE_FLAGS == (ptr - cursor->ptr));
    1690               5 :   cursor->ptr[TRANSLOG_PAGE_FLAGS]= (uchar) log_descriptor.flags;
    1691               5 :   ptr++;
    1692               5 :   if (log_descriptor.flags & TRANSLOG_PAGE_CRC)
    1693                 :   {
    1694                 : #ifndef DBUG_OFF
    1695               0 :     DBUG_PRINT("info", ("write  0x11223344 CRC to (%lu,0x%lx)",
    1696                 :                         LSN_IN_PARTS(*horizon)));
    1697                 :     /* This will be overwritten by real CRC; This is just for debugging */
    1698               0 :     int4store(ptr, 0x11223344);
    1699                 : #endif
    1700                 :     /* CRC will be put when page is finished */
    1701               0 :     ptr+= CRC_SIZE;
    1702                 :   }
    1703               5 :   if (log_descriptor.flags & TRANSLOG_SECTOR_PROTECTION)
    1704                 :   {
    1705                 :     /*
    1706                 :       translog_sector_randmo works like "random" values producer because
    1707                 :       it is enough to have such "random" for this purpose and it will
    1708                 :       not interfere with higher level pseudo random value generator
    1709                 :     */
    1710               0 :     ptr[0]= translog_sector_random++;
    1711               0 :     ptr+= TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
    1712                 :   }
    1713                 :   {
    1714               5 :     uint len= (ptr - cursor->ptr);
    1715               5 :     (*horizon)+= len; /* increasing the offset part of the address */
    1716               5 :     cursor->current_page_fill= len;
    1717               5 :     if (!cursor->chaser)
    1718               5 :       cursor->buffer->size+= len;
    1719                 :   }
    1720               5 :   cursor->ptr= ptr;
    1721               5 :   DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx  chaser: %d  Size: %lu (%lu)  "
    1722                 :                       "Horizon: (%lu,0x%lx)",
    1723                 :                       (uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
    1724                 :                       cursor->chaser, (ulong) cursor->buffer->size,
    1725                 :                       (ulong) (cursor->ptr - cursor->buffer->buffer),
    1726                 :                       LSN_IN_PARTS(*horizon)));
    1727               5 :   translog_check_cursor(cursor);
    1728               5 :   DBUG_VOID_RETURN;
    1729                 : }
    1730                 : 
    1731                 : 
    1732                 : /*
    1733                 :   Put sector protection on the page image
    1734                 : 
    1735                 :   SYNOPSIS
    1736                 :     translog_put_sector_protection()
    1737                 :     page                 reference on the page content
    1738                 :     cursor               cursor of the buffer
    1739                 : 
    1740                 :   NOTES
    1741                 :     We put a sector protection on all following sectors on the page,
    1742                 :     except the first sector that is protected by page header.
    1743                 : */
    1744                 : 
    1745                 : static void translog_put_sector_protection(uchar *page,
    1746                 :                                            struct st_buffer_cursor *cursor)
    1747               0 : {
    1748                 :   uchar *table= page + log_descriptor.page_overhead -
    1749               0 :     TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
    1750                 :   uint i, offset;
    1751                 :   uint16 last_protected_sector= ((cursor->previous_offset - 1) /
    1752               0 :                                  DISK_DRIVE_SECTOR_SIZE);
    1753               0 :   uint16 start_sector= cursor->previous_offset / DISK_DRIVE_SECTOR_SIZE;
    1754               0 :   uint8 value= table[0] + cursor->write_counter;
    1755               0 :   DBUG_ENTER("translog_put_sector_protection");
    1756                 : 
    1757               0 :   if (start_sector == 0)
    1758                 :   {
    1759                 :     /* First sector is protected by file & page numbers in the page header. */
    1760               0 :     start_sector= 1;
    1761                 :   }
    1762                 : 
    1763               0 :   DBUG_PRINT("enter", ("Write counter:%u  value:%u  offset:%u, "
    1764                 :                        "last protected:%u  start sector:%u",
    1765                 :                        (uint) cursor->write_counter,
    1766                 :                        (uint) value,
    1767                 :                        (uint) cursor->previous_offset,
    1768                 :                        (uint) last_protected_sector, (uint) start_sector));
    1769               0 :   if (last_protected_sector == start_sector)
    1770                 :   {
    1771               0 :     i= last_protected_sector;
    1772               0 :     offset= last_protected_sector * DISK_DRIVE_SECTOR_SIZE;
    1773                 :     /* restore data, because we modified sector which was protected */
    1774               0 :     if (offset < cursor->previous_offset)
    1775               0 :       page[offset]= table[i];
    1776                 :   }
    1777               0 :   for (i= start_sector, offset= start_sector * DISK_DRIVE_SECTOR_SIZE;
    1778               0 :        i < TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
    1779               0 :        i++, (offset+= DISK_DRIVE_SECTOR_SIZE))
    1780                 :   {
    1781               0 :     DBUG_PRINT("info", ("sector:%u  offset:%u  data 0x%x",
    1782                 :                         i, offset, (uint) page[offset]));
    1783               0 :     table[i]= page[offset];
    1784               0 :     page[offset]= value;
    1785               0 :     DBUG_PRINT("info", ("sector:%u  offset:%u  data 0x%x",
    1786                 :                         i, offset, (uint) page[offset]));
    1787                 :   }
    1788               0 :   DBUG_VOID_RETURN;
    1789                 : }
    1790                 : 
    1791                 : 
    1792                 : /*
    1793                 :   Calculate CRC32 of given area
    1794                 : 
    1795                 :   SYNOPSIS
    1796                 :     translog_crc()
    1797                 :     area                 Pointer of the area beginning
    1798                 :     length               The Area length
    1799                 : 
    1800                 :   RETURN
    1801                 :     CRC32
    1802                 : */
    1803                 : 
    1804                 : static uint32 translog_crc(uchar *area, uint length)
    1805               0 : {
    1806               0 :   DBUG_ENTER("translog_crc");
    1807               0 :   DBUG_RETURN(crc32(0L, (unsigned char*) area, length));
    1808                 : }
    1809                 : 
    1810                 : 
    1811                 : /*
    1812                 :   Finish current page with zeros
    1813                 : 
    1814                 :   SYNOPSIS
    1815                 :     translog_finish_page()
    1816                 :     horizon              \ horizon & buffer pointers
    1817                 :     cursor               /
    1818                 : */
    1819                 : 
    1820                 : static void translog_finish_page(TRANSLOG_ADDRESS *horizon,
    1821                 :                                  struct st_buffer_cursor *cursor)
    1822               4 : {
    1823               4 :   uint16 left= TRANSLOG_PAGE_SIZE - cursor->current_page_fill;
    1824               4 :   uchar *page= cursor->ptr - cursor->current_page_fill;
    1825               4 :   DBUG_ENTER("translog_finish_page");
    1826               4 :   DBUG_PRINT("enter", ("Buffer: #%u 0x%lx  "
    1827                 :                        "Buffer addr: (%lu,0x%lx)  "
    1828                 :                        "Page addr: (%lu,0x%lx)  "
    1829                 :                        "size:%lu (%lu)  Pg:%u  left:%u",
    1830                 :                        (uint) cursor->buffer_no, (ulong) cursor->buffer,
    1831                 :                        LSN_IN_PARTS(cursor->buffer->offset),
    1832                 :                        (ulong) LSN_FILE_NO(*horizon),
    1833                 :                        (ulong) (LSN_OFFSET(*horizon) -
    1834                 :                                 cursor->current_page_fill),
    1835                 :                        (ulong) cursor->buffer->size,
    1836                 :                        (ulong) (cursor->ptr -cursor->buffer->buffer),
    1837                 :                        (uint) cursor->current_page_fill, (uint) left));
    1838               4 :   DBUG_ASSERT(LSN_FILE_NO(*horizon) == LSN_FILE_NO(cursor->buffer->offset));
    1839               4 :   translog_check_cursor(cursor);
    1840               4 :   if (cursor->protected)
    1841                 :   {
    1842               0 :     DBUG_PRINT("info", ("Already protected and finished"));
    1843               0 :     DBUG_VOID_RETURN;
    1844                 :   }
    1845               4 :   cursor->protected= 1;
    1846                 : 
    1847               4 :   DBUG_ASSERT(left < TRANSLOG_PAGE_SIZE);
    1848               4 :   if (left != 0)
    1849                 :   {
    1850               4 :     DBUG_PRINT("info", ("left: %u", (uint) left));
    1851               4 :     memset(cursor->ptr, TRANSLOG_FILLER, left);
    1852               4 :     cursor->ptr+= left;
    1853               4 :     (*horizon)+= left; /* offset increasing */
    1854               4 :     if (!cursor->chaser)
    1855               4 :       cursor->buffer->size+= left;
    1856                 :     /* We are finishing the page so reset the counter */
    1857               4 :     cursor->current_page_fill= 0;
    1858               4 :     DBUG_PRINT("info", ("Finish Page buffer #%u: 0x%lx  "
    1859                 :                         "chaser: %d  Size: %lu (%lu)",
    1860                 :                         (uint) cursor->buffer->buffer_no,
    1861                 :                         (ulong) cursor->buffer, cursor->chaser,
    1862                 :                         (ulong) cursor->buffer->size,
    1863                 :                         (ulong) (cursor->ptr - cursor->buffer->buffer)));
    1864               4 :     translog_check_cursor(cursor);
    1865                 :   }
    1866                 :   /*
    1867                 :     When we are finishing the page other thread might not finish the page
    1868                 :     header yet (in case if we started from the middle of the page) so we
    1869                 :     have to read log_descriptor.flags but not the flags from the page.
    1870                 :   */
    1871               4 :   if (log_descriptor.flags & TRANSLOG_SECTOR_PROTECTION)
    1872                 :   {
    1873               0 :     translog_put_sector_protection(page, cursor);
    1874               0 :     DBUG_PRINT("info", ("drop write_counter"));
    1875               0 :     cursor->write_counter= 0;
    1876               0 :     cursor->previous_offset= 0;
    1877                 :   }
    1878               4 :   if (log_descriptor.flags & TRANSLOG_PAGE_CRC)
    1879                 :   {
    1880                 :     uint32 crc= translog_crc(page + log_descriptor.page_overhead,
    1881                 :                              TRANSLOG_PAGE_SIZE -
    1882               0 :                              log_descriptor.page_overhead);
    1883               0 :     DBUG_PRINT("info", ("CRC: %lx", (ulong) crc));
    1884                 :     /* We have page number, file number and flag before crc */
    1885               0 :     int4store(page + 3 + 3 + 1, crc);
    1886                 :   }
    1887               4 :   DBUG_VOID_RETURN;
    1888                 : }
    1889                 : 
    1890                 : 
    1891                 : /*
    1892                 :   @brief Wait until all threads have finished closing this buffer.
    1893                 : 
    1894                 :   @param buffer          This buffer should be check
    1895                 : */
    1896                 : 
    1897                 : static void translog_wait_for_closing(struct st_translog_buffer *buffer)
    1898               0 : {
    1899               0 :   DBUG_ENTER("translog_wait_for_closing");
    1900               0 :   DBUG_PRINT("enter", ("Buffer #%u 0x%lx  copies in progress: %u  "
    1901                 :                        "is closing %u  File: %d  size: %lu",
    1902                 :                        (uint) buffer->buffer_no, (ulong) buffer,
    1903                 :                        (uint) buffer->copy_to_buffer_in_progress,
    1904                 :                        (uint) buffer->is_closing_buffer,
    1905                 :                        (buffer->file ? buffer->file->handler.file : -1),
    1906                 :                        (ulong) buffer->size));
    1907               0 :   translog_buffer_lock_assert_owner(buffer);
    1908                 : 
    1909               0 :   while (buffer->is_closing_buffer)
    1910                 :   {
    1911               0 :     DBUG_PRINT("info", ("wait for writers... buffer: #%u  0x%lx",
    1912                 :                         (uint) buffer->buffer_no, (ulong) buffer));
    1913               0 :     DBUG_ASSERT(buffer->file != NULL);
    1914               0 :     pthread_cond_wait(&buffer->waiting_filling_buffer, &buffer->mutex);
    1915               0 :     DBUG_PRINT("info", ("wait for writers done buffer: #%u  0x%lx",
    1916                 :                         (uint) buffer->buffer_no, (ulong) buffer));
    1917                 :   }
    1918                 : 
    1919               0 :   DBUG_VOID_RETURN;
    1920                 : }
    1921                 : 
    1922                 : 
    1923                 : /*
    1924                 :   @brief Wait until all threads have finished filling this buffer.
    1925                 : 
    1926                 :   @param buffer          This buffer should be check
    1927                 : */
    1928                 : 
    1929                 : static void translog_wait_for_writers(struct st_translog_buffer *buffer)
    1930              21 : {
    1931              21 :   DBUG_ENTER("translog_wait_for_writers");
    1932              21 :   DBUG_PRINT("enter", ("Buffer #%u 0x%lx  copies in progress: %u  "
    1933                 :                        "is closing %u  File: %d  size: %lu",
    1934                 :                        (uint) buffer->buffer_no, (ulong) buffer,
    1935                 :                        (uint) buffer->copy_to_buffer_in_progress,
    1936                 :                        (uint) buffer->is_closing_buffer,
    1937                 :                        (buffer->file ? buffer->file->handler.file : -1),
    1938                 :                        (ulong) buffer->size));
    1939              21 :   translog_buffer_lock_assert_owner(buffer);
    1940                 : 
    1941              21 :   while (buffer->copy_to_buffer_in_progress)
    1942                 :   {
    1943               0 :     DBUG_PRINT("info", ("wait for writers... buffer: #%u  0x%lx",
    1944                 :                         (uint) buffer->buffer_no, (ulong) buffer));
    1945               0 :     DBUG_ASSERT(buffer->file != NULL);
    1946               0 :     pthread_cond_wait(&buffer->waiting_filling_buffer, &buffer->mutex);
    1947               0 :     DBUG_PRINT("info", ("wait for writers done buffer: #%u  0x%lx",
    1948                 :                         (uint) buffer->buffer_no, (ulong) buffer));
    1949                 :   }
    1950                 : 
    1951              21 :   DBUG_VOID_RETURN;
    1952                 : }
    1953                 : 
    1954                 : 
    1955                 : /*
    1956                 : 
    1957                 :   Wait for buffer to become free
    1958                 : 
    1959                 :   SYNOPSIS
    1960                 :     translog_wait_for_buffer_free()
    1961                 :     buffer               The buffer we are waiting for
    1962                 : 
    1963                 :   NOTE
    1964                 :     - this buffer should be locked
    1965                 : */
    1966                 : 
    1967                 : static void translog_wait_for_buffer_free(struct st_translog_buffer *buffer)
    1968               4 : {
    1969               4 :   TRANSLOG_ADDRESS offset= buffer->offset;
    1970               4 :   TRANSLOG_FILE *file= buffer->file;
    1971               4 :   uint8 ver= buffer->ver;
    1972               4 :   DBUG_ENTER("translog_wait_for_buffer_free");
    1973               4 :   DBUG_PRINT("enter", ("Buffer #%u 0x%lx  copies in progress: %u  "
    1974                 :                        "is closing %u  File: %d  size: %lu",
    1975                 :                        (uint) buffer->buffer_no, (ulong) buffer,
    1976                 :                        (uint) buffer->copy_to_buffer_in_progress,
    1977                 :                        (uint) buffer->is_closing_buffer,
    1978                 :                        (buffer->file ? buffer->file->handler.file : -1),
    1979                 :                        (ulong) buffer->size));
    1980                 : 
    1981               4 :   translog_wait_for_writers(buffer);
    1982                 : 
    1983               4 :   if (offset != buffer->offset || file != buffer->file || ver != buffer->ver)
    1984               0 :     DBUG_VOID_RETURN; /* the buffer if already freed */
    1985                 : 
    1986               4 :   while (buffer->file != NULL)
    1987                 :   {
    1988               0 :     DBUG_PRINT("info", ("wait for writers... buffer: #%u  0x%lx",
    1989                 :                         (uint) buffer->buffer_no, (ulong) buffer));
    1990               0 :     pthread_cond_wait(&buffer->waiting_filling_buffer, &buffer->mutex);
    1991               0 :     DBUG_PRINT("info", ("wait for writers done. buffer: #%u  0x%lx",
    1992                 :                         (uint) buffer->buffer_no, (ulong) buffer));
    1993                 :   }
    1994               4 :   DBUG_ASSERT(buffer->copy_to_buffer_in_progress == 0);
    1995               4 :   DBUG_VOID_RETURN;
    1996                 : }
    1997                 : 
    1998                 : 
    1999                 : /*
    2000                 :   Initialize the cursor for a buffer
    2001                 : 
    2002                 :   SYNOPSIS
    2003                 :     translog_cursor_init()
    2004                 :     buffer               The buffer
    2005                 :     cursor               It's cursor
    2006                 :     buffer_no            Number of buffer
    2007                 : */
    2008                 : 
    2009                 : static void translog_cursor_init(struct st_buffer_cursor *cursor,
    2010                 :                                  struct st_translog_buffer *buffer,
    2011                 :                                  uint8 buffer_no)
    2012              14 : {
    2013              14 :   DBUG_ENTER("translog_cursor_init");
    2014              14 :   cursor->ptr= buffer->buffer;
    2015              14 :   cursor->buffer= buffer;
    2016              14 :   cursor->buffer_no= buffer_no;
    2017              14 :   cursor->current_page_fill= 0;
    2018              14 :   cursor->chaser= (cursor != &log_descriptor.bc);
    2019              14 :   cursor->write_counter= 0;
    2020              14 :   cursor->previous_offset= 0;
    2021              14 :   cursor->protected= 0;
    2022              14 :   DBUG_VOID_RETURN;
    2023                 : }
    2024                 : 
    2025                 : 
    2026                 : /*
    2027                 :   @brief Initialize buffer for the current file, and a cursor for this buffer.
    2028                 : 
    2029                 :   @param buffer          The buffer
    2030                 :   @param cursor          It's cursor
    2031                 :   @param buffer_no       Number of buffer
    2032                 : */
    2033                 : 
    2034                 : static void translog_start_buffer(struct st_translog_buffer *buffer,
    2035                 :                                   struct st_buffer_cursor *cursor,
    2036                 :                                   uint buffer_no)
    2037              14 : {
    2038              14 :   DBUG_ENTER("translog_start_buffer");
    2039              14 :   DBUG_PRINT("enter",
    2040                 :              ("Assign buffer: #%u (0x%lx) offset: 0x%lx(%lu)",
    2041                 :               (uint) buffer->buffer_no, (ulong) buffer,
    2042                 :               (ulong) LSN_OFFSET(log_descriptor.horizon),
    2043                 :               (ulong) LSN_OFFSET(log_descriptor.horizon)));
    2044              14 :   DBUG_ASSERT(buffer_no == buffer->buffer_no);
    2045              14 :   buffer->prev_last_lsn= buffer->last_lsn= LSN_IMPOSSIBLE;
    2046              14 :   DBUG_PRINT("info", ("last_lsn and prev_last_lsn set to 0  buffer: 0x%lx",
    2047                 :                       (ulong) buffer));
    2048              14 :   buffer->offset= log_descriptor.horizon;
    2049              14 :   buffer->next_buffer_offset= LSN_IMPOSSIBLE;
    2050              14 :   buffer->file= get_current_logfile();
    2051              14 :   buffer->overlay= 0;
    2052              14 :   buffer->size= 0;
    2053              14 :   translog_cursor_init(cursor, buffer, buffer_no);
    2054              14 :   DBUG_PRINT("info", ("file: #%ld (%d)  init cursor #%u: 0x%lx  "
    2055                 :                       "chaser: %d  Size: %lu (%lu)",
    2056                 :                       (long) (buffer->file ? buffer->file->number : 0),
    2057                 :                       (buffer->file ? buffer->file->handler.file : -1),
    2058                 :                       (uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
    2059                 :                       cursor->chaser, (ulong) cursor->buffer->size,
    2060                 :                       (ulong) (cursor->ptr - cursor->buffer->buffer)));
    2061              14 :   translog_check_cursor(cursor);
    2062              14 :   pthread_mutex_lock(&log_descriptor.dirty_buffer_mask_lock);
    2063              14 :   log_descriptor.dirty_buffer_mask|= (1 << buffer->buffer_no);
    2064              14 :   pthread_mutex_unlock(&log_descriptor.dirty_buffer_mask_lock);
    2065                 : 
    2066              14 :   DBUG_VOID_RETURN;
    2067                 : }
    2068                 : 
    2069                 : 
    2070                 : /*
    2071                 :   @brief Switch to the next buffer in a chain.
    2072                 : 
    2073                 :   @param horizon         \ Pointers on current position in file and buffer
    2074                 :   @param cursor          /
    2075                 :   @param new_file        Also start new file
    2076                 : 
    2077                 :   @note
    2078                 :    - loghandler should be locked
    2079                 :    - after return new and old buffer still are locked
    2080                 : 
    2081                 :   @retval 0 OK
    2082                 :   @retval 1 Error
    2083                 : */
    2084                 : 
    2085                 : static my_bool translog_buffer_next(TRANSLOG_ADDRESS *horizon,
    2086                 :                                     struct st_buffer_cursor *cursor,
    2087                 :                                     my_bool new_file)
    2088               0 : {
    2089               0 :   uint old_buffer_no= cursor->buffer_no;
    2090               0 :   uint new_buffer_no= (old_buffer_no + 1) % TRANSLOG_BUFFERS_NO;
    2091               0 :   struct st_translog_buffer *new_buffer= log_descriptor.buffers + new_buffer_no;
    2092               0 :   my_bool chasing= cursor->chaser;
    2093               0 :   DBUG_ENTER("translog_buffer_next");
    2094                 : 
    2095               0 :   DBUG_PRINT("info", ("horizon: (%lu,0x%lx)  chasing: %d",
    2096                 :                       LSN_IN_PARTS(log_descriptor.horizon), chasing));
    2097                 : 
    2098               0 :   DBUG_ASSERT(cmp_translog_addr(log_descriptor.horizon, *horizon) >= 0);
    2099                 : 
    2100               0 :   translog_finish_page(horizon, cursor);
    2101                 : 
    2102               0 :   if (!chasing)
    2103                 :   {
    2104               0 :     translog_buffer_lock(new_buffer);
    2105                 : #ifndef DBUG_OFF
    2106                 :     {
    2107               0 :       TRANSLOG_ADDRESS offset= new_buffer->offset;
    2108               0 :       TRANSLOG_FILE *file= new_buffer->file;
    2109               0 :       uint8 ver= new_buffer->ver;
    2110               0 :       translog_lock_assert_owner();
    2111                 : #endif
    2112               0 :       translog_wait_for_buffer_free(new_buffer);
    2113                 : #ifndef DBUG_OFF
    2114                 :       /* We keep the handler locked so nobody can start this new buffer */
    2115               0 :       DBUG_ASSERT(offset == new_buffer->offset && new_buffer->file == NULL &&
    2116                 :                   (file == NULL ? ver : (uint8)(ver + 1)) == new_buffer->ver);
    2117                 :     }
    2118                 : #endif
    2119                 :   }
    2120                 :   else
    2121               0 :     DBUG_ASSERT(new_buffer->file != NULL);
    2122                 : 
    2123               0 :   if (new_file)
    2124                 :   {
    2125                 :     /* move the horizon to the next file and its header page */
    2126               0 :     (*horizon)+= LSN_ONE_FILE;
    2127               0 :     (*horizon)= LSN_REPLACE_OFFSET(*horizon, TRANSLOG_PAGE_SIZE);
    2128               0 :     if (!chasing && translog_create_new_file())
    2129                 :     {
    2130               0 :       DBUG_RETURN(1);
    2131                 :     }
    2132                 :   }
    2133                 : 
    2134                 :   /* prepare next page */
    2135               0 :   if (chasing)
    2136               0 :     translog_cursor_init(cursor, new_buffer, new_buffer_no);
    2137                 :   else
    2138                 :   {
    2139               0 :     translog_lock_assert_owner();
    2140               0 :     translog_start_buffer(new_buffer, cursor, new_buffer_no);
    2141               0 :     new_buffer->prev_buffer_offset=
    2142                 :       log_descriptor.buffers[old_buffer_no].offset;
    2143               0 :     new_buffer->prev_last_lsn=
    2144                 :       BUFFER_MAX_LSN(log_descriptor.buffers + old_buffer_no);
    2145                 :   }
    2146               0 :   log_descriptor.buffers[old_buffer_no].next_buffer_offset= new_buffer->offset;
    2147               0 :   DBUG_PRINT("info", ("prev_last_lsn set to (%lu,0x%lx)  buffer: 0x%lx",
    2148                 :                       LSN_IN_PARTS(new_buffer->prev_last_lsn),
    2149                 :                       (ulong) new_buffer));
    2150               0 :   translog_new_page_header(horizon, cursor);
    2151               0 :   DBUG_RETURN(0);
    2152                 : }
    2153                 : 
    2154                 : 
    2155                 : /*
    2156                 :   Sets max LSN sent to file, and address from which data is only in the buffer
    2157                 : 
    2158                 :   SYNOPSIS
    2159                 :     translog_set_sent_to_disk()
    2160                 :     buffer               buffer which we have sent to disk
    2161                 : 
    2162                 :   TODO: use atomic operations if possible (64bit architectures?)
    2163                 : */
    2164                 : 
    2165                 : static void translog_set_sent_to_disk(struct st_translog_buffer *buffer)
    2166               4 : {
    2167               4 :   LSN lsn= buffer->last_lsn;
    2168               4 :   TRANSLOG_ADDRESS in_buffers= buffer->next_buffer_offset;
    2169                 : 
    2170               4 :   DBUG_ENTER("translog_set_sent_to_disk");
    2171               4 :   pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
    2172               4 :   DBUG_PRINT("enter", ("lsn: (%lu,0x%lx) in_buffers: (%lu,0x%lx)  "
    2173                 :                        "in_buffers_only: (%lu,0x%lx)  start: (%lu,0x%lx)  "
    2174                 :                        "sent_to_disk: (%lu,0x%lx)",
    2175                 :                        LSN_IN_PARTS(lsn),
    2176                 :                        LSN_IN_PARTS(in_buffers),
    2177                 :                        LSN_IN_PARTS(log_descriptor.log_start),
    2178                 :                        LSN_IN_PARTS(log_descriptor.in_buffers_only),
    2179                 :                        LSN_IN_PARTS(log_descriptor.sent_to_disk)));
    2180                 :   /*
    2181                 :     We write sequentially (first part of following assert) but we rewrite
    2182                 :     the same page in case we started mysql and shut it down immediately
    2183                 :     (second part of the following assert)
    2184                 :   */
    2185               4 :   DBUG_ASSERT(cmp_translog_addr(lsn, log_descriptor.sent_to_disk) >= 0 ||
    2186                 :               cmp_translog_addr(lsn, log_descriptor.log_start) < 0);
    2187               4 :   log_descriptor.sent_to_disk= lsn;
    2188                 :   /* LSN_IMPOSSIBLE == 0 => it will work for very first time */
    2189               4 :   if (cmp_translog_addr(in_buffers, log_descriptor.in_buffers_only) > 0)
    2190                 :   {
    2191               0 :     log_descriptor.in_buffers_only= in_buffers;
    2192               0 :     DBUG_PRINT("info", ("set new in_buffers_only"));
    2193                 :   }
    2194               4 :   pthread_mutex_unlock(&log_descriptor.sent_to_disk_lock);
    2195               4 :   DBUG_VOID_RETURN;
    2196                 : }
    2197                 : 
    2198                 : 
    2199                 : /*
    2200                 :   Sets address from which data is only in the buffer
    2201                 : 
    2202                 :   SYNOPSIS
    2203                 :     translog_set_only_in_buffers()
    2204                 :     lsn                  LSN to assign
    2205                 :     in_buffers           to assign to in_buffers_only
    2206                 : */
    2207                 : 
    2208                 : static void translog_set_only_in_buffers(TRANSLOG_ADDRESS in_buffers)
    2209               4 : {
    2210               4 :   DBUG_ENTER("translog_set_only_in_buffers");
    2211               4 :   pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
    2212               4 :   DBUG_PRINT("enter", ("in_buffers: (%lu,0x%lx)  "
    2213                 :                        "in_buffers_only: (%lu,0x%lx)",
    2214                 :                        LSN_IN_PARTS(in_buffers),
    2215                 :                        LSN_IN_PARTS(log_descriptor.in_buffers_only)));
    2216                 :   /* LSN_IMPOSSIBLE == 0 => it will work for very first time */
    2217               4 :   if (cmp_translog_addr(in_buffers, log_descriptor.in_buffers_only) > 0)
    2218                 :   {
    2219               0 :     if (translog_status != TRANSLOG_OK)
    2220               0 :       DBUG_VOID_RETURN;
    2221               0 :     log_descriptor.in_buffers_only= in_buffers;
    2222               0 :     DBUG_PRINT("info", ("set new in_buffers_only"));
    2223                 :   }
    2224               4 :   pthread_mutex_unlock(&log_descriptor.sent_to_disk_lock);
    2225               4 :   DBUG_VOID_RETURN;
    2226                 : }
    2227                 : 
    2228                 : 
    2229                 : /*
    2230                 :   Gets address from which data is only in the buffer
    2231                 : 
    2232                 :   SYNOPSIS
    2233                 :     translog_only_in_buffers()
    2234                 : 
    2235                 :   RETURN
    2236                 :     address from which data is only in the buffer
    2237                 : */
    2238                 : 
    2239                 : static TRANSLOG_ADDRESS translog_only_in_buffers()
    2240              10 : {
    2241                 :   register TRANSLOG_ADDRESS addr;
    2242              10 :   DBUG_ENTER("translog_only_in_buffers");
    2243              10 :   pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
    2244              10 :   addr= log_descriptor.in_buffers_only;
    2245              10 :   pthread_mutex_unlock(&log_descriptor.sent_to_disk_lock);
    2246              10 :   DBUG_RETURN(addr);
    2247                 : }
    2248                 : 
    2249                 : 
    2250                 : /*
    2251                 :   Get max LSN sent to file
    2252                 : 
    2253                 :   SYNOPSIS
    2254                 :     translog_get_sent_to_disk()
    2255                 : 
    2256                 :   RETURN
    2257                 :     max LSN send to file
    2258                 : */
    2259                 : 
    2260                 : static LSN translog_get_sent_to_disk()
    2261               8 : {
    2262                 :   register LSN lsn;
    2263               8 :   DBUG_ENTER("translog_get_sent_to_disk");
    2264               8 :   pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
    2265               8 :   lsn= log_descriptor.sent_to_disk;
    2266               8 :   DBUG_PRINT("info", ("sent to disk up to (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
    2267               8 :   pthread_mutex_unlock(&log_descriptor.sent_to_disk_lock);
    2268               8 :   DBUG_RETURN(lsn);
    2269                 : }
    2270                 : 
    2271                 : 
    2272                 : /*
    2273                 :   Get first chunk address on the given page
    2274                 : 
    2275                 :   SYNOPSIS
    2276                 :     translog_get_first_chunk_offset()
    2277                 :     page                 The page where to find first chunk
    2278                 : 
    2279                 :   RETURN
    2280                 :     first chunk offset
    2281                 : */
    2282                 : 
    2283                 : static my_bool translog_get_first_chunk_offset(uchar *page)
    2284               5 : {
    2285               5 :   DBUG_ENTER("translog_get_first_chunk_offset");
    2286               5 :   DBUG_ASSERT(page[TRANSLOG_PAGE_FLAGS] < TRANSLOG_FLAGS_NUM);
    2287               5 :   DBUG_RETURN(page_overhead[page[TRANSLOG_PAGE_FLAGS]]);
    2288                 : }
    2289                 : 
    2290                 : 
    2291                 : /*
    2292                 :   Write coded length of record
    2293                 : 
    2294                 :   SYNOPSIS
    2295                 :     translog_write_variable_record_1group_code_len
    2296                 :     dst                  Destination buffer pointer
    2297                 :     length               Length which should be coded
    2298                 :     header_len           Calculated total header length
    2299                 : */
    2300                 : 
    2301                 : static void
    2302                 : translog_write_variable_record_1group_code_len(uchar *dst,
    2303                 :                                                translog_size_t length,
    2304                 :                                                uint16 header_len)
    2305              13 : {
    2306              13 :   switch (header_len) {
    2307                 :   case 6:                                      /* (5 + 1) */
    2308               4 :     DBUG_ASSERT(length <= 250);
    2309               4 :     *dst= (uint8) length;
    2310               4 :     return;
    2311                 :   case 8:                                      /* (5 + 3) */
    2312               9 :     DBUG_ASSERT(length <= 0xFFFF);
    2313               9 :     *dst= 251;
    2314               9 :     int2store(dst + 1, length);
    2315               9 :     return;
    2316                 :   case 9:                                      /* (5 + 4) */
    2317               0 :     DBUG_ASSERT(length <= (ulong) 0xFFFFFF);
    2318               0 :     *dst= 252;
    2319               0 :     int3store(dst + 1, length);
    2320               0 :     return;
    2321                 :   case 10:                                     /* (5 + 5) */
    2322               0 :     *dst= 253;
    2323               0 :     int4store(dst + 1, length);
    2324               0 :     return;
    2325                 :   default:
    2326               0 :     DBUG_ASSERT(0);
    2327                 :   }
    2328                 :   return;
    2329                 : }
    2330                 : 
    2331                 : 
    2332                 : /*
    2333                 :   Decode record data length and advance given pointer to the next field
    2334                 : 
    2335                 :   SYNOPSIS
    2336                 :     translog_variable_record_1group_decode_len()
    2337                 :     src                  The pointer to the pointer to the length beginning
    2338                 : 
    2339                 :   RETURN
    2340                 :     decoded length
    2341                 : */
    2342                 : 
    2343                 : static translog_size_t translog_variable_record_1group_decode_len(uchar **src)
    2344               0 : {
    2345               0 :   uint8 first= (uint8) (**src);
    2346               0 :   switch (first) {
    2347                 :   case 251:
    2348               0 :     (*src)+= 3;
    2349               0 :     return (uint2korr((*src) - 2));
    2350                 :   case 252:
    2351               0 :     (*src)+= 4;
    2352               0 :     return (uint3korr((*src) - 3));
    2353                 :   case 253:
    2354               0 :     (*src)+= 5;
    2355               0 :     return (uint4korr((*src) - 4));
    2356                 :   case 254:
    2357                 :   case 255:
    2358               0 :     DBUG_ASSERT(0);                             /* reserved for future use */
    2359                 :     return (0);
    2360                 :   default:
    2361               0 :     (*src)++;
    2362               0 :     return (first);
    2363                 :   }
    2364                 : }
    2365                 : 
    2366                 : 
    2367                 : /*
    2368                 :   Get total length of this chunk (not only body)
    2369                 : 
    2370                 :   SYNOPSIS
    2371                 :     translog_get_total_chunk_length()
    2372                 :     page                 The page where chunk placed
    2373                 :     offset               Offset of the chunk on this place
    2374                 : 
    2375                 :   RETURN
    2376                 :     total length of the chunk
    2377                 : */
    2378                 : 
    2379                 : static uint16 translog_get_total_chunk_length(uchar *page, uint16 offset)
    2380               0 : {
    2381               0 :   DBUG_ENTER("translog_get_total_chunk_length");
    2382               0 :   switch (page[offset] & TRANSLOG_CHUNK_TYPE) {
    2383                 :   case TRANSLOG_CHUNK_LSN:
    2384                 :   {
    2385                 :     /* 0 chunk referred as LSN (head or tail) */
    2386                 :     translog_size_t rec_len;
    2387               0 :     uchar *start= page + offset;
    2388               0 :     uchar *ptr= start + 1 + 2; /* chunk type and short trid */
    2389                 :     uint16 chunk_len, header_len, page_rest;
    2390               0 :     DBUG_PRINT("info", ("TRANSLOG_CHUNK_LSN"));
    2391               0 :     rec_len= translog_variable_record_1group_decode_len(&ptr);
    2392               0 :     chunk_len= uint2korr(ptr);
    2393               0 :     header_len= (uint16) (ptr -start) + 2;
    2394               0 :     DBUG_PRINT("info", ("rec len: %lu  chunk len: %u  header len: %u",
    2395                 :                         (ulong) rec_len, (uint) chunk_len, (uint) header_len));
    2396               0 :     if (chunk_len)
    2397                 :     {
    2398               0 :       DBUG_PRINT("info", ("chunk len: %u + %u = %u",
    2399                 :                           (uint) header_len, (uint) chunk_len,
    2400                 :                           (uint) (chunk_len + header_len)));
    2401               0 :       DBUG_RETURN(chunk_len + header_len);
    2402                 :     }
    2403               0 :     page_rest= TRANSLOG_PAGE_SIZE - offset;
    2404               0 :     DBUG_PRINT("info", ("page_rest %u", (uint) page_rest));
    2405               0 :     if (rec_len + header_len < page_rest)
    2406               0 :       DBUG_RETURN(rec_len + header_len);
    2407               0 :     DBUG_RETURN(page_rest);
    2408                 :   }
    2409                 :   case TRANSLOG_CHUNK_FIXED:
    2410                 :   {
    2411                 :     uchar *ptr;
    2412               0 :     uint type= page[offset] & TRANSLOG_REC_TYPE;
    2413                 :     uint length;
    2414                 :     int i;
    2415                 :     /* 1 (pseudo)fixed record (also LSN) */
    2416               0 :     DBUG_PRINT("info", ("TRANSLOG_CHUNK_FIXED"));
    2417               0 :     DBUG_ASSERT(log_record_type_descriptor[type].rclass ==
    2418                 :                 LOGRECTYPE_FIXEDLENGTH ||
    2419                 :                 log_record_type_descriptor[type].rclass ==
    2420                 :                 LOGRECTYPE_PSEUDOFIXEDLENGTH);
    2421               0 :     if (log_record_type_descriptor[type].rclass == LOGRECTYPE_FIXEDLENGTH)
    2422                 :     {
    2423               0 :       DBUG_PRINT("info",
    2424                 :                  ("Fixed length: %u",
    2425                 :                   (uint) (log_record_type_descriptor[type].fixed_length + 3)));
    2426               0 :       DBUG_RETURN(log_record_type_descriptor[type].fixed_length + 3);
    2427                 :     }
    2428                 : 
    2429               0 :     ptr= page + offset + 3;            /* first compressed LSN */
    2430               0 :     length= log_record_type_descriptor[type].fixed_length + 3;
    2431               0 :     for (i= 0; i < log_record_type_descriptor[type].compressed_LSN; i++)
    2432                 :     {
    2433                 :       /* first 2 bits is length - 2 */
    2434               0 :       uint len= (((uint8) (*ptr)) >> 6) + 2;
    2435               0 :       if (ptr[0] == 0 && ((uint8) ptr[1]) == 1)
    2436               0 :         len+= LSN_STORE_SIZE; /* case of full LSN storing */
    2437               0 :       ptr+= len;
    2438                 :       /* subtract saved bytes */
    2439               0 :       length-= (LSN_STORE_SIZE - len);
    2440                 :     }
    2441               0 :     DBUG_PRINT("info", ("Pseudo-fixed length: %u", length));
    2442               0 :     DBUG_RETURN(length);
    2443                 :   }
    2444                 :   case TRANSLOG_CHUNK_NOHDR:
    2445                 :     /* 2 no header chunk (till page end) */
    2446               0 :     DBUG_PRINT("info", ("TRANSLOG_CHUNK_NOHDR  length: %u",
    2447                 :                         (uint) (TRANSLOG_PAGE_SIZE - offset)));
    2448               0 :     DBUG_RETURN(TRANSLOG_PAGE_SIZE - offset);
    2449                 :   case TRANSLOG_CHUNK_LNGTH:                   /* 3 chunk with chunk length */
    2450               0 :     DBUG_PRINT("info", ("TRANSLOG_CHUNK_LNGTH"));
    2451               0 :     DBUG_ASSERT(TRANSLOG_PAGE_SIZE - offset >= 3);
    2452               0 :     DBUG_PRINT("info", ("length: %u", uint2korr(page + offset + 1) + 3));
    2453               0 :     DBUG_RETURN(uint2korr(page + offset + 1) + 3);
    2454                 :   default:
    2455               0 :     DBUG_ASSERT(0);
    2456                 :     DBUG_RETURN(0);
    2457                 :   }
    2458                 : }
    2459                 : 
    2460                 : /*
    2461                 :   @brief Waits previous buffer flush finish
    2462                 : 
    2463                 :   @param buffer          buffer for check
    2464                 : 
    2465                 :   @retval 0 previous buffer flushed and this thread have to flush this one
    2466                 :   @retval 1 previous buffer flushed and this buffer flushed by other thread too
    2467                 : */
    2468                 : 
    2469                 : my_bool translog_prev_buffer_flush_wait(struct st_translog_buffer *buffer)
    2470               8 : {
    2471               8 :   TRANSLOG_ADDRESS offset= buffer->offset;
    2472               8 :   TRANSLOG_FILE *file= buffer->file;
    2473               8 :   uint8 ver= buffer->ver;
    2474               8 :   DBUG_ENTER("translog_prev_buffer_flush_wait");
    2475               8 :   DBUG_PRINT("enter", ("buffer: 0x%lx  #%u  offset: (%lu,0x%lx)  "
    2476                 :                        "prev sent: (%lu,0x%lx) prev offset: (%lu,0x%lx)",
    2477                 :                        (ulong) buffer, (uint) buffer->buffer_no,
    2478                 :                        LSN_IN_PARTS(buffer->offset),
    2479                 :                        LSN_IN_PARTS(buffer->prev_sent_to_disk),
    2480                 :                        LSN_IN_PARTS(buffer->prev_buffer_offset)));
    2481               8 :   translog_buffer_lock_assert_owner(buffer);
    2482                 :   /*
    2483                 :     if prev_sent_to_disk == LSN_IMPOSSIBLE then
    2484                 :     prev_buffer_offset should be LSN_IMPOSSIBLE
    2485                 :     because it means that this buffer was never used
    2486                 :   */
    2487               8 :   DBUG_ASSERT((buffer->prev_sent_to_disk == LSN_IMPOSSIBLE &&
    2488                 :                buffer->prev_buffer_offset == LSN_IMPOSSIBLE) ||
    2489                 :               buffer->prev_sent_to_disk != LSN_IMPOSSIBLE);
    2490               8 :   if (buffer->prev_buffer_offset != buffer->prev_sent_to_disk)
    2491                 :   {
    2492                 :     do {
    2493               0 :       pthread_cond_wait(&buffer->prev_sent_to_disk_cond, &buffer->mutex);
    2494               0 :       if (buffer->file != file || buffer->offset != offset ||
    2495                 :           buffer->ver != ver)
    2496                 :       {
    2497               0 :         translog_buffer_unlock(buffer);
    2498               0 :         DBUG_RETURN(1); /* some the thread flushed the buffer already */
    2499                 :       }
    2500               0 :     } while(buffer->prev_buffer_offset != buffer->prev_sent_to_disk);
    2501                 :   }
    2502               8 :   DBUG_RETURN(0);
    2503                 : }
    2504                 : 
    2505                 : 
    2506                 : /*
    2507                 :   Flush given buffer
    2508                 : 
    2509                 :   SYNOPSIS
    2510                 :     translog_buffer_flush()
    2511                 :     buffer               This buffer should be flushed
    2512                 : 
    2513                 :   RETURN
    2514                 :     0  OK
    2515                 :     1  Error
    2516                 : */
    2517                 : 
    2518                 : static my_bool translog_buffer_flush(struct st_translog_buffer *buffer)
    2519               8 : {
    2520                 :   uint32 i, pg;
    2521               8 :   TRANSLOG_ADDRESS offset= buffer->offset;
    2522               8 :   TRANSLOG_FILE *file= buffer->file;
    2523               8 :   uint8 ver= buffer->ver;
    2524               8 :   DBUG_ENTER("translog_buffer_flush");
    2525               8 :   DBUG_PRINT("enter",
    2526                 :              ("Buffer: #%u 0x%lx file: %d  offset: (%lu,0x%lx)  size: %lu",
    2527                 :               (uint) buffer->buffer_no, (ulong) buffer,
    2528                 :               buffer->file->handler.file,
    2529                 :               LSN_IN_PARTS(buffer->offset),
    2530                 :               (ulong) buffer->size));
    2531               8 :   translog_buffer_lock_assert_owner(buffer);
    2532                 : 
    2533               8 :   if (buffer->file == NULL)
    2534               0 :     DBUG_RETURN(0);
    2535                 : 
    2536               8 :   translog_wait_for_writers(buffer);
    2537                 : 
    2538               8 :   if (buffer->file != file || buffer->offset != offset || buffer->ver != ver)
    2539               0 :     DBUG_RETURN(0); /* some the thread flushed the buffer already */
    2540                 : 
    2541               8 :   if (buffer->is_closing_buffer)
    2542                 :   {
    2543                 :     /* some other flush in progress */
    2544               0 :     translog_wait_for_closing(buffer);
    2545                 :   }
    2546                 : 
    2547               8 :   if (buffer->file != file || buffer->offset != offset || buffer->ver != ver)
    2548               0 :     DBUG_RETURN(0); /* some the thread flushed the buffer already */
    2549                 : 
    2550               8 :   if (buffer->overlay && translog_prev_buffer_flush_wait(buffer))
    2551               0 :     DBUG_RETURN(0); /* some the thread flushed the buffer already */
    2552                 : 
    2553                 :   /*
    2554                 :     Send page by page in the pagecache what we are going to write on the
    2555                 :     disk
    2556                 :   */
    2557               8 :   file= buffer->file;
    2558               8 :   for (i= 0, pg= LSN_OFFSET(buffer->offset) / TRANSLOG_PAGE_SIZE;
    2559              24 :        i < buffer->size;
    2560               8 :        i+= TRANSLOG_PAGE_SIZE, pg++)
    2561                 :   {
    2562               8 :     TRANSLOG_ADDRESS addr= (buffer->offset + i);
    2563                 :     TRANSLOG_VALIDATOR_DATA data;
    2564               8 :     DBUG_PRINT("info", ("send log form %lu till %lu  address: (%lu,0x%lx)  "
    2565                 :                         "page #: %lu  buffer size: %lu  buffer: 0x%lx",
    2566                 :                         (ulong) i, (ulong) (i + TRANSLOG_PAGE_SIZE),
    2567                 :                         LSN_IN_PARTS(addr), (ulong) pg, (ulong) buffer->size,
    2568                 :                         (ulong) buffer));
    2569               8 :     data.addr= &addr;
    2570               8 :     DBUG_ASSERT(log_descriptor.pagecache->block_size == TRANSLOG_PAGE_SIZE);
    2571               8 :     DBUG_ASSERT(i + TRANSLOG_PAGE_SIZE <= buffer->size);
    2572               8 :     if (translog_status != TRANSLOG_OK && translog_status != TRANSLOG_SHUTDOWN)
    2573               0 :       DBUG_RETURN(1);
    2574               8 :     if (pagecache_inject(log_descriptor.pagecache,
    2575                 :                         &file->handler, pg, 3,
    2576                 :                         buffer->buffer + i,
    2577                 :                         PAGECACHE_PLAIN_PAGE,
    2578                 :                         PAGECACHE_LOCK_LEFT_UNLOCKED,
    2579                 :                         PAGECACHE_PIN_LEFT_UNPINNED, 0,
    2580                 :                         LSN_IMPOSSIBLE))
    2581                 :     {
    2582               0 :       DBUG_PRINT("error",
    2583                 :                  ("Can't write page (%lu,0x%lx) to pagecache, error: %d",
    2584                 :                   (ulong) buffer->file->number,
    2585                 :                   (ulong) (LSN_OFFSET(buffer->offset)+ i),
    2586                 :                   my_errno));
    2587               0 :       translog_stop_writing();
    2588               0 :       DBUG_RETURN(1);
    2589                 :     }
    2590                 :   }
    2591               8 :   file->is_sync= 0;
    2592               8 :   if (my_pwrite(file->handler.file, buffer->buffer,
    2593                 :                 buffer->size, LSN_OFFSET(buffer->offset),
    2594                 :                 log_write_flags))
    2595                 :   {
    2596               0 :     DBUG_PRINT("error", ("Can't write buffer (%lu,0x%lx) size %lu "
    2597                 :                          "to the disk (%d)",
    2598                 :                          (ulong) file->handler.file,
    2599                 :                          (ulong) LSN_OFFSET(buffer->offset),
    2600                 :                          (ulong) buffer->size, errno));
    2601               0 :     translog_stop_writing();
    2602               0 :     DBUG_RETURN(1);
    2603                 :   }
    2604                 :   /*
    2605                 :     Dropping the flag in such way can make false alarm: signalling than the
    2606                 :     file in not sync when it is sync, but the situation is quite rare and
    2607                 :     protections with mutexes give much more overhead to the whole engine
    2608                 :   */
    2609               8 :   file->is_sync= 0;
    2610                 : 
    2611               8 :   if (LSN_OFFSET(buffer->last_lsn) != 0)    /* if buffer->last_lsn is set */
    2612                 :   {
    2613               4 :     if (translog_prev_buffer_flush_wait(buffer))
    2614               0 :       DBUG_RETURN(0); /* some the thread flushed the buffer already */
    2615               4 :     translog_set_sent_to_disk(buffer);
    2616                 :   }
    2617                 :   else
    2618               4 :     translog_set_only_in_buffers(buffer->next_buffer_offset);
    2619                 : 
    2620                 :   /* say to next buffer that we are finished */
    2621                 :   {
    2622                 :     struct st_translog_buffer *next_buffer=
    2623               8 :       log_descriptor.buffers + ((buffer->buffer_no + 1) % TRANSLOG_BUFFERS_NO);
    2624               8 :     if (likely(translog_status == TRANSLOG_OK)){
    2625               4 :       translog_buffer_lock(next_buffer);
    2626               4 :       next_buffer->prev_sent_to_disk= buffer->offset;
    2627               4 :       translog_buffer_unlock(next_buffer);
    2628               4 :       pthread_cond_broadcast(&next_buffer->prev_sent_to_disk_cond);
    2629                 :     }
    2630                 :     else
    2631                 :     {
    2632                 :       /*
    2633                 :         It is shutdown =>
    2634                 :           1) there is only one thread
    2635                 :           2) mutexes of other buffers can be destroyed => we can't use them
    2636                 :       */
    2637               4 :       next_buffer->prev_sent_to_disk= buffer->offset;
    2638                 :     }
    2639                 :   }
    2640                 :   /* Free buffer */
    2641               8 :   buffer->file= NULL;
    2642               8 :   buffer->overlay= 0;
    2643               8 :   buffer->ver++;
    2644               8 :   pthread_mutex_lock(&log_descriptor.dirty_buffer_mask_lock);
    2645               8 :   log_descriptor.dirty_buffer_mask&= ~(1 << buffer->buffer_no);
    2646               8 :   pthread_mutex_unlock(&log_descriptor.dirty_buffer_mask_lock);
    2647               8 :   pthread_cond_broadcast(&buffer->waiting_filling_buffer);
    2648               8 :   DBUG_RETURN(0);
    2649                 : }
    2650                 : 
    2651                 : 
    2652                 : /*
    2653                 :   Recover page with sector protection (wipe out failed chunks)
    2654                 : 
    2655                 :   SYNOPSYS
    2656                 :     translog_recover_page_up_to_sector()
    2657                 :     page                 reference on the page
    2658                 :     offset               offset of failed sector
    2659                 : 
    2660                 :   RETURN
    2661                 :     0  OK
    2662                 :     1  Error
    2663                 : */
    2664                 : 
    2665                 : static my_bool translog_recover_page_up_to_sector(uchar *page, uint16 offset)
    2666               0 : {
    2667               0 :   uint16 chunk_offset= translog_get_first_chunk_offset(page), valid_chunk_end;
    2668               0 :   DBUG_ENTER("translog_recover_page_up_to_sector");
    2669               0 :   DBUG_PRINT("enter", ("offset: %u  first chunk: %u",
    2670                 :                        (uint) offset, (uint) chunk_offset));
    2671                 : 
    2672               0 :   while (page[chunk_offset] != TRANSLOG_FILLER && chunk_offset < offset)
    2673                 :   {
    2674                 :     uint16 chunk_length;
    2675               0 :     if ((chunk_length=
    2676                 :          translog_get_total_chunk_length(page, chunk_offset)) == 0)
    2677                 :     {
    2678               0 :       DBUG_PRINT("error", ("cant get chunk length (offset %u)",
    2679                 :                            (uint) chunk_offset));
    2680               0 :       DBUG_RETURN(1);
    2681                 :     }
    2682               0 :     DBUG_PRINT("info", ("chunk: offset: %u  length %u",
    2683                 :                         (uint) chunk_offset, (uint) chunk_length));
    2684               0 :     if (((ulong) chunk_offset) + ((ulong) chunk_length) > TRANSLOG_PAGE_SIZE)
    2685                 :     {
    2686               0 :       DBUG_PRINT("error", ("damaged chunk (offset %u) in trusted area",
    2687                 :                            (uint) chunk_offset));
    2688               0 :       DBUG_RETURN(1);
    2689                 :     }
    2690               0 :     chunk_offset+= chunk_length;
    2691                 :   }
    2692                 : 
    2693               0 :   valid_chunk_end= chunk_offset;
    2694                 :   /* end of trusted area - sector parsing */
    2695               0 :   while (page[chunk_offset] != TRANSLOG_FILLER)
    2696                 :   {
    2697                 :     uint16 chunk_length;
    2698               0 :     if ((chunk_length=
    2699                 :          translog_get_total_chunk_length(page, chunk_offset)) == 0)
    2700               0 :       break;
    2701                 : 
    2702               0 :     DBUG_PRINT("info", ("chunk: offset: %u  length %u",
    2703                 :                         (uint) chunk_offset, (uint) chunk_length));
    2704               0 :     if (((ulong) chunk_offset) + ((ulong) chunk_length) >
    2705                 :         (uint) (offset + DISK_DRIVE_SECTOR_SIZE))
    2706               0 :       break;
    2707                 : 
    2708               0 :     chunk_offset+= chunk_length;
    2709               0 :     valid_chunk_end= chunk_offset;
    2710                 :   }
    2711               0 :   DBUG_PRINT("info", ("valid chunk end offset: %u", (uint) valid_chunk_end));
    2712                 : 
    2713               0 :   memset(page + valid_chunk_end, TRANSLOG_FILLER,
    2714                 :          TRANSLOG_PAGE_SIZE - valid_chunk_end);
    2715                 : 
    2716               0 :   DBUG_RETURN(0);
    2717                 : }
    2718                 : 
    2719                 : 
    2720                 : /**
    2721                 :   @brief Dummy write callback.
    2722                 : */
    2723                 : 
    2724                 : static my_bool
    2725                 : translog_dummy_callback(uchar *page __attribute__((unused)),
    2726                 :                         pgcache_page_no_t page_no __attribute__((unused)),
    2727                 :                         uchar* data_ptr __attribute__((unused)))
    2728               0 : {
    2729               0 :   return 0;
    2730                 : }
    2731                 : 
    2732                 : 
    2733                 : /**
    2734                 :   @brief Checks and removes sector protection.
    2735                 : 
    2736                 :   @param page            reference on the page content.
    2737                 :   @param file            transaction log descriptor.
    2738                 : 
    2739                 :   @retvat 0 OK
    2740                 :   @retval 1 Error
    2741                 : */
    2742                 : 
    2743                 : static my_bool
    2744                 : translog_check_sector_protection(uchar *page, TRANSLOG_FILE *file)
    2745               0 : {
    2746                 :   uint i, offset;
    2747                 :   uchar *table= page + page_overhead[page[TRANSLOG_PAGE_FLAGS]] -
    2748               0 :     TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
    2749               0 :   uint8 current= table[0];
    2750               0 :   DBUG_ENTER("translog_check_sector_protection");
    2751                 : 
    2752               0 :   for (i= 1, offset= DISK_DRIVE_SECTOR_SIZE;
    2753               0 :        i < TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
    2754               0 :        i++, offset+= DISK_DRIVE_SECTOR_SIZE)
    2755                 :   {
    2756                 :     /*
    2757                 :       TODO: add chunk counting for "suspecting" sectors (difference is
    2758                 :       more than 1-2), if difference more then present chunks then it is
    2759                 :       the problem.
    2760                 :     */
    2761               0 :     uint8 test= page[offset];
    2762               0 :     DBUG_PRINT("info", ("sector: #%u  offset: %u  current: %lx "
    2763                 :                         "read: 0x%x  stored: 0x%x%x",
    2764                 :                         i, offset, (ulong) current,
    2765                 :                         (uint) uint2korr(page + offset), (uint) table[i],
    2766                 :                         (uint) table[i + 1]));
    2767                 :     /*
    2768                 :       3 is minimal possible record length. So we can have "distance"
    2769                 :       between 2 sectors value more then DISK_DRIVE_SECTOR_SIZE / 3
    2770                 :       only if it is old value, i.e. the sector was not written.
    2771                 :     */
    2772               0 :     if (((test < current) &&
    2773                 :          ((uint)(0xFFL - current + test) > DISK_DRIVE_SECTOR_SIZE / 3)) ||
    2774                 :         ((test >= current) &&
    2775                 :          ((uint)(test - current) > DISK_DRIVE_SECTOR_SIZE / 3)))
    2776                 :     {
    2777               0 :       if (translog_recover_page_up_to_sector(page, offset))
    2778               0 :         DBUG_RETURN(1);
    2779               0 :       file->was_recovered= 1;
    2780               0 :       DBUG_RETURN(0);
    2781                 :     }
    2782                 : 
    2783                 :     /* Restore value on the page */
    2784               0 :     page[offset]= table[i];
    2785               0 :     current= test;
    2786               0 :     DBUG_PRINT("info", ("sector: #%u  offset: %u  current: %lx  "
    2787                 :                         "read: 0x%x  stored: 0x%x",
    2788                 :                         i, offset, (ulong) current,
    2789                 :                         (uint) page[offset], (uint) table[i]));
    2790                 :   }
    2791               0 :   DBUG_RETURN(0);
    2792                 : }
    2793                 : 
    2794                 : 
    2795                 : /**
    2796                 :   @brief Log page validator (read callback)
    2797                 : 
    2798                 :   @param page            The page data to check
    2799                 :   @param page_no         The page number (<offset>/<page length>)
    2800                 :   @param data_ptr        Read callback data pointer (pointer to TRANSLOG_FILE)
    2801                 : 
    2802                 :   @todo: add turning loghandler to read-only mode after merging with
    2803                 :   that patch.
    2804                 : 
    2805                 :   @retval 0 OK
    2806                 :   @retval 1 Error
    2807                 : */
    2808                 : 
    2809                 : static my_bool translog_page_validator(uchar *page,
    2810                 :                                        pgcache_page_no_t page_no,
    2811                 :                                        uchar* data_ptr)
    2812               8 : {
    2813                 :   uint this_page_page_overhead;
    2814                 :   uint flags;
    2815                 :   uchar *page_pos;
    2816               8 :   TRANSLOG_FILE *data= (TRANSLOG_FILE *) data_ptr;
    2817                 : #ifndef DBUG_OFF
    2818               8 :   pgcache_page_no_t offset= page_no * TRANSLOG_PAGE_SIZE;
    2819                 : #endif
    2820               8 :   DBUG_ENTER("translog_page_validator");
    2821                 : 
    2822               8 :   data->was_recovered= 0;
    2823                 : 
    2824               8 :   if (uint3korr(page) != page_no ||
    2825                 :       uint3korr(page + 3) != data->number)
    2826                 :   {
    2827               0 :     DBUG_PRINT("error", ("Page (%lu,0x%lx): "
    2828                 :                          "page address written in the page is incorrect: "
    2829                 :                          "File %lu instead of %lu or page %lu instead of %lu",
    2830                 :                          (ulong) data->number, (ulong) offset,
    2831                 :                          (ulong) uint3korr(page + 3), (ulong) data->number,
    2832                 :                          (ulong) uint3korr(page),
    2833                 :                          (ulong) page_no));
    2834               0 :     DBUG_RETURN(1);
    2835                 :   }
    2836               8 :   flags= (uint)(page[TRANSLOG_PAGE_FLAGS]);
    2837               8 :   this_page_page_overhead= page_overhead[flags];
    2838               8 :   if (flags & ~(TRANSLOG_PAGE_CRC | TRANSLOG_SECTOR_PROTECTION |
    2839                 :                 TRANSLOG_RECORD_CRC))
    2840                 :   {
    2841               0 :     DBUG_PRINT("error", ("Page (%lu,0x%lx): "
    2842                 :                          "Garbage in the page flags field detected : %x",
    2843                 :                          (ulong) data->number, (ulong) offset,
    2844                 :                          (uint) flags));
    2845               0 :     DBUG_RETURN(1);
    2846                 :   }
    2847               8 :   page_pos= page + (3 + 3 + 1);
    2848               8 :   if (flags & TRANSLOG_PAGE_CRC)
    2849                 :   {
    2850                 :     uint32 crc= translog_crc(page + this_page_page_overhead,
    2851                 :                              TRANSLOG_PAGE_SIZE -
    2852               0 :                              this_page_page_overhead);
    2853               0 :     if (crc != uint4korr(page_pos))
    2854                 :     {
    2855               0 :       DBUG_PRINT("error", ("Page (%lu,0x%lx): "
    2856                 :                            "CRC mismatch: calculated: %lx on the page %lx",
    2857                 :                            (ulong) data->number, (ulong) offset,
    2858                 :                            (ulong) crc, (ulong) uint4korr(page_pos)));
    2859               0 :       DBUG_RETURN(1);
    2860                 :     }
    2861               0 :     page_pos+= CRC_SIZE;                      /* Skip crc */
    2862                 :   }
    2863               8 :   if (flags & TRANSLOG_SECTOR_PROTECTION &&
    2864                 :       translog_check_sector_protection(page, data))
    2865                 :   {
    2866               0 :     DBUG_RETURN(1);
    2867                 :   }
    2868               8 :   DBUG_RETURN(0);
    2869                 : }
    2870                 : 
    2871                 : 
    2872                 : /**
    2873                 :   @brief Locks the loghandler.
    2874                 : */
    2875                 : 
    2876                 : void translog_lock()
    2877              61 : {
    2878                 :   uint8 current_buffer;
    2879              61 :   DBUG_ENTER("translog_lock");
    2880                 : 
    2881                 :   /*
    2882                 :      Locking the loghandler mean locking current buffer, but it can change
    2883                 :      during locking, so we should check it
    2884                 :   */
    2885                 :   for (;;)
    2886                 :   {
    2887                 :     /*
    2888                 :       log_descriptor.bc.buffer_no is only one byte so its reading is
    2889                 :       an atomic operation
    2890                 :     */
    2891              61 :     current_buffer= log_descriptor.bc.buffer_no;
    2892              61 :     translog_buffer_lock(log_descriptor.buffers + current_buffer);
    2893              61 :     if (log_descriptor.bc.buffer_no == current_buffer)
    2894              61 :       break;
    2895               0 :     translog_buffer_unlock(log_descriptor.buffers + current_buffer);
    2896              61 :   }
    2897              61 :   DBUG_VOID_RETURN;
    2898                 : }
    2899                 : 
    2900                 : 
    2901                 : /*
    2902                 :   Unlock the loghandler
    2903                 : 
    2904                 :   SYNOPSIS
    2905                 :     translog_unlock()
    2906                 : 
    2907                 :   RETURN
    2908                 :     0  OK
    2909                 :     1  Error
    2910                 : */
    2911                 : 
    2912                 : void translog_unlock()
    2913              52 : {
    2914              52 :   translog_buffer_unlock(log_descriptor.bc.buffer);
    2915                 : }
    2916                 : 
    2917                 : 
    2918                 : /**
    2919                 :   @brief Get log page by file number and offset of the beginning of the page
    2920                 : 
    2921                 :   @param data            validator data, which contains the page address
    2922                 :   @param buffer          buffer for page placing
    2923                 :                          (might not be used in some cache implementations)
    2924                 :   @param direct_link     if it is not NULL then caller can accept direct
    2925                 :                          link to the page cache
    2926                 : 
    2927                 :   @retval NULL Error
    2928                 :   @retval #    pointer to the page cache which should be used to read this page
    2929                 : */
    2930                 : 
    2931                 : static uchar *translog_get_page(TRANSLOG_VALIDATOR_DATA *data, uchar *buffer,
    2932                 :                                 PAGECACHE_BLOCK_LINK **direct_link)
    2933               5 : {
    2934               5 :   TRANSLOG_ADDRESS addr= *(data->addr), in_buffers;
    2935               5 :   uint32 file_no= LSN_FILE_NO(addr);
    2936                 :   TRANSLOG_FILE *file;
    2937               5 :   DBUG_ENTER("translog_get_page");
    2938               5 :   DBUG_PRINT("enter", ("File: %lu  Offset: %lu(0x%lx)",
    2939                 :                        (ulong) file_no,
    2940                 :                        (ulong) LSN_OFFSET(addr),
    2941                 :                        (ulong) LSN_OFFSET(addr)));
    2942                 : 
    2943                 :   /* it is really page address */
    2944               5 :   DBUG_ASSERT(LSN_OFFSET(addr) % TRANSLOG_PAGE_SIZE == 0);
    2945               5 :   if (direct_link)
    2946               0 :     *direct_link= NULL;
    2947                 : 
    2948               5 : restart:
    2949                 : 
    2950               5 :   in_buffers= translog_only_in_buffers();
    2951               5 :   DBUG_PRINT("info", ("in_buffers: (%lu,0x%lx)",
    2952                 :                       LSN_IN_PARTS(in_buffers)));
    2953               5 :   if (in_buffers != LSN_IMPOSSIBLE &&
    2954                 :       cmp_translog_addr(addr, in_buffers) >= 0)
    2955                 :   {
    2956               5 :     translog_lock();
    2957               5 :     DBUG_ASSERT(cmp_translog_addr(addr, log_descriptor.horizon) < 0);
    2958                 :     /* recheck with locked loghandler */
    2959               5 :     in_buffers= translog_only_in_buffers();
    2960               5 :     if (cmp_translog_addr(addr, in_buffers) >= 0)
    2961                 :     {
    2962               5 :       uint16 buffer_no= log_descriptor.bc.buffer_no;
    2963                 : #ifndef DBUG_OFF
    2964               5 :       uint16 buffer_start= buffer_no;
    2965                 : #endif
    2966               5 :       struct st_translog_buffer *buffer_unlock= log_descriptor.bc.buffer;
    2967               5 :       struct st_translog_buffer *curr_buffer= log_descriptor.bc.buffer;
    2968                 :       for (;;)
    2969                 :       {
    2970                 :         /*
    2971                 :           if the page is in the buffer and it is the last version of the
    2972                 :           page (in case of division the page by buffer flush)
    2973                 :         */
    2974               5 :         if (curr_buffer->file != NULL &&
    2975                 :             cmp_translog_addr(addr, curr_buffer->offset) >= 0 &&
    2976                 :             cmp_translog_addr(addr,
    2977                 :                               (curr_buffer->next_buffer_offset ?
    2978                 :                                curr_buffer->next_buffer_offset:
    2979                 :                                curr_buffer->offset + curr_buffer->size)) < 0)
    2980                 :         {
    2981               5 :           TRANSLOG_ADDRESS offset= curr_buffer->offset;
    2982               5 :           TRANSLOG_FILE *fl= curr_buffer->file;
    2983               5 :           uchar *from, *table= NULL;
    2984                 :           int is_last_unfinished_page;
    2985               5 :           uint last_protected_sector= 0;
    2986                 :           TRANSLOG_FILE file_copy;
    2987               5 :           uint8 ver= curr_buffer->ver;
    2988               5 :           translog_wait_for_writers(curr_buffer);
    2989               5 :           if (offset != curr_buffer->offset || fl != curr_buffer->file ||
    2990                 :               ver != curr_buffer->ver)
    2991                 :           {
    2992               0 :             DBUG_ASSERT(buffer_unlock == curr_buffer);
    2993               0 :             translog_buffer_unlock(buffer_unlock);
    2994               0 :             goto restart;
    2995                 :           }
    2996               5 :           DBUG_ASSERT(LSN_FILE_NO(addr) ==  LSN_FILE_NO(curr_buffer->offset));
    2997               5 :           from= curr_buffer->buffer + (addr - curr_buffer->offset);
    2998               5 :           memcpy(buffer, from, TRANSLOG_PAGE_SIZE);
    2999                 :           /*
    3000                 :             We can use copy then in translog_page_validator() because it
    3001                 :             do not put it permanently somewhere.
    3002                 :             We have to use copy because after releasing log lock we can't
    3003                 :             guaranty that the file still be present (in real life it will be
    3004                 :             present but theoretically possible that it will be released
    3005                 :             already from last files cache);
    3006                 :           */
    3007               5 :           file_copy= *(curr_buffer->file);
    3008               5 :           file_copy.handler.callback_data= (uchar*) &file_copy;
    3009               5 :           is_last_unfinished_page= ((log_descriptor.bc.buffer ==
    3010                 :                                      curr_buffer) &&
    3011                 :                                     (log_descriptor.bc.ptr >= from) &&
    3012                 :                                     (log_descriptor.bc.ptr <
    3013                 :                                      from + TRANSLOG_PAGE_SIZE));
    3014               5 :           if (is_last_unfinished_page &&
    3015                 :               (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION))
    3016                 :           {
    3017               0 :             last_protected_sector= ((log_descriptor.bc.previous_offset - 1) /
    3018                 :                                     DISK_DRIVE_SECTOR_SIZE);
    3019               0 :             table= buffer + log_descriptor.page_overhead -
    3020                 :               TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
    3021                 :           }
    3022                 : 
    3023               5 :           DBUG_ASSERT(buffer_unlock == curr_buffer);
    3024               5 :           translog_buffer_unlock(buffer_unlock);
    3025               5 :           if (is_last_unfinished_page)
    3026                 :           {
    3027                 :             uint i;
    3028                 :             /*
    3029                 :               This is last unfinished page => we should not check CRC and
    3030                 :               remove only that protection which already installed (no need
    3031                 :               to check it)
    3032                 : 
    3033                 :               We do not check the flag of sector protection, because if
    3034                 :               (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION) is
    3035                 :               not set then last_protected_sector will be 0 so following loop
    3036                 :               will be never executed
    3037                 :             */
    3038               5 :             DBUG_PRINT("info", ("This is last unfinished page, "
    3039                 :                                 "last protected sector %u",
    3040                 :                                 last_protected_sector));
    3041               5 :             for (i= 1; i <= last_protected_sector; i++)
    3042                 :             {
    3043               0 :               uint offset= i * DISK_DRIVE_SECTOR_SIZE;
    3044               0 :               DBUG_PRINT("info", ("Sector %u: 0x%02x <- 0x%02x",
    3045                 :                                   i, buffer[offset],
    3046                 :                                   table[i]));
    3047               0 :               buffer[offset]= table[i];
    3048                 :             }
    3049                 :           }
    3050                 :           else
    3051                 :           {
    3052                 :             /*
    3053                 :               This IF should be true because we use in-memory data which
    3054                 :               supposed to be correct.
    3055                 :             */
    3056               0 :             if (translog_page_validator(buffer,
    3057                 :                                         LSN_OFFSET(addr) / TRANSLOG_PAGE_SIZE,
    3058                 :                                         (uchar*) &file_copy))
    3059                 :             {
    3060               0 :               DBUG_ASSERT(0);
    3061                 :               buffer= NULL;
    3062                 :             }
    3063                 :           }
    3064               5 :           DBUG_RETURN(buffer);
    3065                 :         }
    3066               0 :         buffer_no= (buffer_no + 1) % TRANSLOG_BUFFERS_NO;
    3067               0 :         curr_buffer= log_descriptor.buffers + buffer_no;
    3068               0 :         translog_buffer_lock(curr_buffer);
    3069               0 :         translog_buffer_unlock(buffer_unlock);
    3070               0 :         buffer_unlock= curr_buffer;
    3071                 :         /* we can't make a full circle */
    3072               0 :         DBUG_ASSERT(buffer_start != buffer_no);
    3073                 :       }
    3074                 :     }
    3075               0 :     translog_unlock();
    3076                 :   }
    3077               0 :   file= get_logfile_by_number(file_no);
    3078               0 :   DBUG_ASSERT(file != NULL);
    3079               0 :   buffer= pagecache_read(log_descriptor.pagecache, &file->handler,
    3080                 :                          LSN_OFFSET(addr) / TRANSLOG_PAGE_SIZE,
    3081                 :                          3, (direct_link ? NULL : buffer),
    3082                 :                          PAGECACHE_PLAIN_PAGE,
    3083                 :                          (direct_link ?
    3084                 :                           PAGECACHE_LOCK_READ :
    3085                 :                           PAGECACHE_LOCK_LEFT_UNLOCKED),
    3086                 :                          direct_link);
    3087               0 :   DBUG_PRINT("info", ("Direct link is assigned to : 0x%lx * 0x%lx",
    3088                 :                       (ulong) direct_link,
    3089                 :                       (ulong)(direct_link ? *direct_link : NULL)));
    3090               0 :   data->was_recovered= file->was_recovered;
    3091               0 :   DBUG_RETURN(buffer);
    3092                 : }
    3093                 : 
    3094                 : 
    3095                 : /**
    3096                 :   @brief free direct log page link
    3097                 : 
    3098                 :   @param direct_link the direct log page link to be freed
    3099                 : 
    3100                 : */
    3101                 : 
    3102                 : static void translog_free_link(PAGECACHE_BLOCK_LINK *direct_link)
    3103               0 : {
    3104               0 :   DBUG_ENTER("translog_free_link");
    3105               0 :   DBUG_PRINT("info", ("Direct link: 0x%lx",
    3106                 :                       (ulong) direct_link));
    3107               0 :   if (direct_link)
    3108               0 :     pagecache_unlock_by_link(log_descriptor.pagecache, direct_link,
    3109                 :                              PAGECACHE_LOCK_READ_UNLOCK, PAGECACHE_UNPIN,
    3110                 :                              LSN_IMPOSSIBLE, LSN_IMPOSSIBLE, 0, FALSE);
    3111               0 :   DBUG_VOID_RETURN;
    3112                 : }
    3113                 : 
    3114                 : 
    3115                 : /**
    3116                 :   @brief Finds last full page of the given log file.
    3117                 : 
    3118                 :   @param addr            address structure to fill with data, which contain
    3119                 :                          file number of the log file
    3120                 :   @param last_page_ok    Result of the check whether last page OK.
    3121                 :                          (for now only we check only that file length
    3122                 :                          divisible on page length).
    3123                 :   @param no_errors       suppress messages about non-critical errors
    3124                 : 
    3125                 :   @retval 0 OK
    3126                 :   @retval 1 Error
    3127                 : */
    3128                 : 
    3129                 : static my_bool translog_get_last_page_addr(TRANSLOG_ADDRESS *addr,
    3130                 :                                            my_bool *last_page_ok,
    3131                 :                                            my_bool no_errors)
    3132               0 : {
    3133                 :   char path[FN_REFLEN];
    3134                 :   uint32 rec_offset;
    3135                 :   my_off_t file_size;
    3136               0 :   uint32 file_no= LSN_FILE_NO(*addr);
    3137                 :   TRANSLOG_FILE *file;
    3138                 : #ifndef DBUG_OFF
    3139                 :   char buff[21];
    3140                 : #endif
    3141               0 :   DBUG_ENTER("translog_get_last_page_addr");
    3142                 : 
    3143               0 :   if (likely((file= get_logfile_by_number(file_no)) != NULL))
    3144                 :   {
    3145                 :     /*
    3146                 :       This function used only during initialization of loghandler or in
    3147                 :       scanner (which mean we need read that part of the log), so the
    3148                 :       requested log file have to be opened and can't be freed after
    3149                 :       returning pointer on it (file_size).
    3150                 :     */
    3151               0 :     file_size= my_seek(file->handler.file, 0, SEEK_END, MYF(0));
    3152                 :   }
    3153                 :   else
    3154                 :   {
    3155                 :     /*
    3156                 :       This branch is used only during very early initialization
    3157                 :       when files are not opened.
    3158                 :     */
    3159                 :     File fd;
    3160               0 :     if ((fd= my_open(translog_filename_by_fileno(file_no, path),
    3161                 :                      O_RDONLY, (no_errors ? MYF(0) : MYF(MY_WME)))) < 0)
    3162                 :     {
    3163               0 :       my_errno= errno;
    3164               0 :       DBUG_PRINT("error", ("Error %d during opening file #%d",
    3165                 :                            errno, file_no));
    3166               0 :       DBUG_RETURN(1);
    3167                 :     }
    3168               0 :     file_size= my_seek(fd, 0, SEEK_END, MYF(0));
    3169               0 :     my_close(fd, MYF(0));
    3170                 :   }
    3171               0 :   DBUG_PRINT("info", ("File size: %s", llstr(file_size, buff)));
    3172               0 :   if (file_size == MY_FILEPOS_ERROR)
    3173               0 :     DBUG_RETURN(1);
    3174               0 :   DBUG_ASSERT(file_size < ULL(0xffffffff));
    3175               0 :   if (((uint32)file_size) > TRANSLOG_PAGE_SIZE)
    3176                 :   {
    3177               0 :     rec_offset= (((((uint32)file_size) / TRANSLOG_PAGE_SIZE) - 1) *
    3178                 :                        TRANSLOG_PAGE_SIZE);
    3179               0 :     *last_page_ok= (((uint32)file_size) == rec_offset + TRANSLOG_PAGE_SIZE);
    3180                 :   }
    3181                 :   else
    3182                 :   {
    3183               0 :     *last_page_ok= 0;
    3184               0 :     rec_offset= 0;
    3185                 :   }
    3186               0 :   *addr= MAKE_LSN(file_no, rec_offset);
    3187               0 :   DBUG_PRINT("info", ("Last page: 0x%lx  ok: %d", (ulong) rec_offset,
    3188                 :                       *last_page_ok));
    3189               0 :   DBUG_RETURN(0);
    3190                 : }
    3191                 : 
    3192                 : 
    3193                 : /**
    3194                 :   @brief Get number bytes for record length storing
    3195                 : 
    3196                 :   @param length          Record length which will be encoded
    3197                 : 
    3198                 :   @return 1,3,4,5 - number of bytes to store given length
    3199                 : */
    3200                 : 
    3201                 : static uint translog_variable_record_length_bytes(translog_size_t length)
    3202              13 : {
    3203              13 :   if (length < 250)
    3204               4 :     return 1;
    3205               9 :   if (length < 0xFFFF)
    3206               9 :     return 3;
    3207               0 :   if (length < (ulong) 0xFFFFFF)
    3208               0 :     return 4;
    3209               0 :   return 5;
    3210                 : }
    3211                 : 
    3212                 : 
    3213                 : /**
    3214                 :   @brief Gets header of this chunk.
    3215                 : 
    3216                 :   @param chunk           The pointer to the chunk beginning
    3217                 : 
    3218                 :   @retval # total length of the chunk
    3219                 :   @retval 0 Error
    3220                 : */
    3221                 : 
    3222                 : static uint16 translog_get_chunk_header_length(uchar *chunk)
    3223               0 : {
    3224               0 :   DBUG_ENTER("translog_get_chunk_header_length");
    3225               0 :   switch (*chunk & TRANSLOG_CHUNK_TYPE) {
    3226                 :   case TRANSLOG_CHUNK_LSN:
    3227                 :   {
    3228                 :     /* 0 chunk referred as LSN (head or tail) */
    3229                 :     translog_size_t rec_len;
    3230               0 :     uchar *start= chunk;
    3231               0 :     uchar *ptr= start + 1 + 2;
    3232                 :     uint16 chunk_len, header_len;
    3233               0 :     DBUG_PRINT("info", ("TRANSLOG_CHUNK_LSN"));
    3234               0 :     rec_len= translog_variable_record_1group_decode_len(&ptr);
    3235               0 :     chunk_len= uint2korr(ptr);
    3236               0 :     header_len= (uint16) (ptr - start) +2;
    3237               0 :     DBUG_PRINT("info", ("rec len: %lu  chunk len: %u  header len: %u",
    3238                 :                         (ulong) rec_len, (uint) chunk_len, (uint) header_len));
    3239               0 :     if (chunk_len)
    3240                 :     {
    3241                 :       /* TODO: fine header end */
    3242                 :       /*
    3243                 :         The last chunk of multi-group record can be base for it header
    3244                 :         calculation (we skip to the first group to read the header) so if we
    3245                 :         stuck here something is wrong.
    3246                 :       */
    3247               0 :       DBUG_ASSERT(0);
    3248                 :       DBUG_RETURN(0);                               /* Keep compiler happy */
    3249                 :     }
    3250               0 :     DBUG_RETURN(header_len);
    3251                 :   }
    3252                 :   case TRANSLOG_CHUNK_FIXED:
    3253                 :   {
    3254                 :     /* 1 (pseudo)fixed record (also LSN) */
    3255               0 :     DBUG_PRINT("info", ("TRANSLOG_CHUNK_FIXED = 3"));
    3256               0 :     DBUG_RETURN(3);
    3257                 :   }
    3258                 :   case TRANSLOG_CHUNK_NOHDR:
    3259                 :     /* 2 no header chunk (till page end) */
    3260               0 :     DBUG_PRINT("info", ("TRANSLOG_CHUNK_NOHDR = 1"));
    3261               0 :     DBUG_RETURN(1);
    3262                 :     break;
    3263                 :   case TRANSLOG_CHUNK_LNGTH:
    3264                 :     /* 3 chunk with chunk length */
    3265               0 :     DBUG_PRINT("info", ("TRANSLOG_CHUNK_LNGTH = 3"));
    3266               0 :     DBUG_RETURN(3);
    3267                 :     break;
    3268                 :   default:
    3269               0 :     DBUG_ASSERT(0);
    3270                 :     DBUG_RETURN(0);                               /* Keep compiler happy */
    3271                 :   }
    3272                 : }
    3273                 : 
    3274                 : 
    3275                 : /**
    3276                 :   @brief Truncate the log to the given address. Used during the startup if the
    3277                 :          end of log if corrupted.
    3278                 : 
    3279                 :   @param addr            new horizon
    3280                 : 
    3281                 :   @retval 0 OK
    3282                 :   @retval 1 Error
    3283                 : */
    3284                 : 
    3285                 : static my_bool translog_truncate_log(TRANSLOG_ADDRESS addr)
    3286               0 : {
    3287                 :   uchar *page;
    3288                 :   TRANSLOG_ADDRESS current_page;
    3289                 :   uint32 next_page_offset, page_rest;
    3290                 :   uint32 i;
    3291                 :   File fd;
    3292                 :   TRANSLOG_VALIDATOR_DATA data;
    3293                 :   char path[FN_REFLEN];
    3294                 :   uchar page_buff[TRANSLOG_PAGE_SIZE];
    3295               0 :   DBUG_ENTER("translog_truncate_log");
    3296                 :   /* TODO: write warning to the client */
    3297               0 :   DBUG_PRINT("warning", ("removing all records from (%lu,0x%lx) "
    3298                 :                          "till (%lu,0x%lx)",
    3299                 :                          LSN_IN_PARTS(addr),
    3300                 :                          LSN_IN_PARTS(log_descriptor.horizon)));
    3301               0 :   DBUG_ASSERT(cmp_translog_addr(addr, log_descriptor.horizon) < 0);
    3302                 :   /* remove files between the address and horizon */
    3303               0 :   for (i= LSN_FILE_NO(addr) + 1; i <= LSN_FILE_NO(log_descriptor.horizon); i++)
    3304               0 :     if (my_delete(translog_filename_by_fileno(i, path),  MYF(MY_WME)))
    3305                 :     {
    3306               0 :       translog_unlock();
    3307               0 :       DBUG_RETURN(1);
    3308                 :     }
    3309                 : 
    3310                 :   /* truncate the last file up to the last page */
    3311               0 :   next_page_offset= LSN_OFFSET(addr);
    3312               0 :   next_page_offset= (next_page_offset -
    3313                 :                      ((next_page_offset - 1) % TRANSLOG_PAGE_SIZE + 1) +
    3314                 :                      TRANSLOG_PAGE_SIZE);
    3315               0 :   page_rest= next_page_offset - LSN_OFFSET(addr);
    3316               0 :   memset(page_buff, TRANSLOG_FILLER, page_rest);
    3317               0 :   if ((fd= open_logfile_by_number_no_cache(LSN_FILE_NO(addr))) < 0 ||
    3318                 :       ((my_chsize(fd, next_page_offset, TRANSLOG_FILLER, MYF(MY_WME)) ||
    3319                 :         (page_rest && my_pwrite(fd, page_buff, page_rest, LSN_OFFSET(addr),
    3320                 :                                 log_write_flags)) ||
    3321                 :         my_sync(fd, MYF(MY_WME))) |
    3322                 :        my_close(fd, MYF(MY_WME))) ||
    3323                 :       (sync_log_dir >= TRANSLOG_SYNC_DIR_ALWAYS &&
    3324                 :        sync_dir(log_descriptor.directory_fd, MYF(MY_WME | MY_IGNORE_BADFD))))
    3325               0 :     DBUG_RETURN(1);
    3326                 : 
    3327                 :   /* fix the horizon */
    3328               0 :   log_descriptor.horizon= addr;
    3329                 :   /* fix the buffer data */
    3330               0 :   current_page= MAKE_LSN(LSN_FILE_NO(addr), (next_page_offset -
    3331                 :                                              TRANSLOG_PAGE_SIZE));
    3332               0 :   data.addr= &current_page;
    3333               0 :   if ((page= translog_get_page(&data, log_descriptor.buffers->buffer, NULL)) ==
    3334                 :       NULL)
    3335               0 :     DBUG_RETURN(1);
    3336               0 :   if (page != log_descriptor.buffers->buffer)
    3337               0 :     memcpy(log_descriptor.buffers->buffer, page, TRANSLOG_PAGE_SIZE);
    3338               0 :   log_descriptor.bc.buffer->offset= current_page;
    3339               0 :   log_descriptor.bc.buffer->size= LSN_OFFSET(addr) - LSN_OFFSET(current_page);
    3340               0 :   log_descriptor.bc.ptr=
    3341                 :     log_descriptor.buffers->buffer + log_descriptor.bc.buffer->size;
    3342               0 :   log_descriptor.bc.current_page_fill= log_descriptor.bc.buffer->size;
    3343               0 :   DBUG_RETURN(0);
    3344                 : }
    3345                 : 
    3346                 : 
    3347                 : /**
    3348                 :   Applies function 'callback' to all files (in a directory) which
    3349                 :   name looks like a log's name (maria_log.[0-9]{7}).
    3350                 :   If 'callback' returns TRUE this interrupts the walk and returns
    3351                 :   TRUE. Otherwise FALSE is returned after processing all log files.
    3352                 :   It cannot just use log_descriptor.directory because that may not yet have
    3353                 :   been initialized.
    3354                 : 
    3355                 :   @param  directory        directory to scan
    3356                 :   @param  callback         function to apply; is passed directory and base
    3357                 :                            name of found file
    3358                 : */
    3359                 : 
    3360                 : my_bool translog_walk_filenames(const char *directory,
    3361                 :                                 my_bool (*callback)(const char *,
    3362                 :                                                     const char *))
    3363               0 : {
    3364                 :   MY_DIR *dirp;
    3365                 :   uint i;
    3366               0 :   my_bool rc= FALSE;
    3367                 : 
    3368                 :   /* Finds and removes transaction log files */
    3369               0 :   if (!(dirp = my_dir(directory, MYF(MY_DONT_SORT))))
    3370               0 :     return FALSE;
    3371                 : 
    3372               0 :   for (i= 0; i < dirp->number_off_files; i++)
    3373                 :   {
    3374               0 :     char *file= dirp->dir_entry[i].name;
    3375               0 :     if (strncmp(file, "maria_log.", 10) == 0 &&
    3376                 :         file[10] >= '0' && file[10] <= '9' &&
    3377                 :         file[11] >= '0' && file[11] <= '9' &&
    3378                 :         file[12] >= '0' && file[12] <= '9' &&
    3379                 :         file[13] >= '0' && file[13] <= '9' &&
    3380                 :         file[14] >= '0' && file[14] <= '9' &&
    3381                 :         file[15] >= '0' && file[15] <= '9' &&
    3382                 :         file[16] >= '0' && file[16] <= '9' &&
    3383                 :         file[17] >= '0' && file[17] <= '9' &&
    3384                 :         file[18] == '\0' && (*callback)(directory, file))
    3385                 :     {
    3386               0 :       rc= TRUE;
    3387               0 :       break;
    3388                 :     }
    3389                 :   }
    3390               0 :   my_dirend(dirp);
    3391               0 :   return rc;
    3392                 : }
    3393                 : 
    3394                 : 
    3395                 : /**
    3396                 :   @brief Fills table of dependence length of page header from page flags
    3397                 : */
    3398                 : 
    3399                 : static void translog_fill_overhead_table()
    3400               5 : {
    3401                 :   uint i;
    3402              45 :   for (i= 0; i < TRANSLOG_FLAGS_NUM; i++)
    3403                 :   {
    3404              40 :      page_overhead[i]= 7;
    3405              40 :      if (i & TRANSLOG_PAGE_CRC)
    3406              20 :        page_overhead[i]+= CRC_SIZE;
    3407              40 :      if (i & TRANSLOG_SECTOR_PROTECTION)
    3408              20 :        page_overhead[i]+= TRANSLOG_PAGE_SIZE /
    3409                 :                            DISK_DRIVE_SECTOR_SIZE;
    3410                 :   }
    3411                 : }
    3412                 : 
    3413                 : 
    3414                 : /**
    3415                 :   Callback to find first log in directory.
    3416                 : */
    3417                 : 
    3418                 : static my_bool translog_callback_search_first(const char *directory
    3419                 :                                               __attribute__((unused)),
    3420                 :                                               const char *filename
    3421                 :                                               __attribute__((unused)))
    3422               0 : {
    3423               0 :   return TRUE;
    3424                 : }
    3425                 : 
    3426                 : 
    3427                 : /**
    3428                 :   @brief Checks that chunk is LSN one
    3429                 : 
    3430                 :   @param type            type of the chunk
    3431                 : 
    3432                 :   @retval 1 the chunk is LNS
    3433                 :   @retval 0 the chunk is not LSN
    3434                 : */
    3435                 : 
    3436                 : static my_bool translog_is_LSN_chunk(uchar type)
    3437               0 : {
    3438               0 :   DBUG_ENTER("translog_is_LSN_chunk");
    3439               0 :   DBUG_PRINT("info", ("byte: %x  chunk type: %u  record type: %u",
    3440                 :                       type, type >> 6, type & TRANSLOG_REC_TYPE));
    3441               0 :   DBUG_RETURN(((type & TRANSLOG_CHUNK_TYPE) == TRANSLOG_CHUNK_FIXED) ||
    3442                 :               (((type & TRANSLOG_CHUNK_TYPE) == TRANSLOG_CHUNK_LSN)  &&
    3443                 :                ((type & TRANSLOG_REC_TYPE)) != TRANSLOG_CHUNK_0_CONT));
    3444                 : }
    3445                 : 
    3446                 : 
    3447                 : /**
    3448                 :   @brief Initialize transaction log
    3449                 : 
    3450                 :   @param directory       Directory where log files are put
    3451                 :   @param log_file_max_size max size of one log size (for new logs creation)
    3452                 :   @param server_version  version of MySQL server (MYSQL_VERSION_ID)
    3453                 :   @param server_id       server ID (replication & Co)
    3454                 :   @param pagecache       Page cache for the log reads
    3455                 :   @param flags           flags (TRANSLOG_PAGE_CRC, TRANSLOG_SECTOR_PROTECTION
    3456                 :                            TRANSLOG_RECORD_CRC)
    3457                 :   @param read_only       Put transaction log in read-only mode
    3458                 :   @param init_table_func function to initialize record descriptors table
    3459                 :   @param no_errors       suppress messages about non-critical errors
    3460                 : 
    3461                 :   @todo
    3462                 :     Free used resources in case of error.
    3463                 : 
    3464                 :   @retval 0 OK
    3465                 :   @retval 1 Error
    3466                 : */
    3467                 : 
    3468                 : my_bool translog_init_with_table(const char *directory,
    3469                 :                                  uint32 log_file_max_size,
    3470                 :                                  uint32 server_version,
    3471                 :                                  uint32 server_id, PAGECACHE *pagecache,
    3472                 :                                  uint flags, my_bool readonly,
    3473                 :                                  void (*init_table_func)(),
    3474                 :                                  my_bool no_errors)
    3475               5 : {
    3476                 :   int i;
    3477               5 :   int old_log_was_recovered= 0, logs_found= 0;
    3478               5 :   uint old_flags= flags;
    3479               5 :   uint32 start_file_num= 1;
    3480                 :   TRANSLOG_ADDRESS sure_page, last_page, last_valid_page, checkpoint_lsn;
    3481               5 :   my_bool version_changed= 0;
    3482               5 :   DBUG_ENTER("translog_init_with_table");
    3483                 : 
    3484               5 :   id_to_share= NULL;
    3485               5 :   log_descriptor.directory_fd= -1;
    3486               5 :   log_descriptor.is_everything_flushed= 1;
    3487               5 :   log_descriptor.next_pass_max_lsn= LSN_IMPOSSIBLE;
    3488                 : 
    3489               5 :   (*init_table_func)();
    3490                 :   compile_time_assert(sizeof(log_descriptor.dirty_buffer_mask) * 8 >=
    3491                 :                       TRANSLOG_BUFFERS_NO);
    3492               5 :   log_descriptor.dirty_buffer_mask= 0;
    3493               5 :   if (readonly)
    3494               0 :     log_descriptor.open_flags= O_BINARY | O_RDONLY;
    3495                 :   else
    3496               5 :     log_descriptor.open_flags= O_BINARY | O_RDWR;
    3497               5 :   if (pthread_mutex_init(&log_descriptor.sent_to_disk_lock,
    3498                 :                          MY_MUTEX_INIT_FAST) ||
    3499                 :       pthread_mutex_init(&log_descriptor.file_header_lock,
    3500                 :                          MY_MUTEX_INIT_FAST) ||
    3501                 :       pthread_mutex_init(&log_descriptor.unfinished_files_lock,
    3502                 :                          MY_MUTEX_INIT_FAST) ||
    3503                 :       pthread_mutex_init(&log_descriptor.purger_lock,
    3504                 :                          MY_MUTEX_INIT_FAST) ||
    3505                 :       pthread_mutex_init(&log_descriptor.log_flush_lock,
    3506                 :                          MY_MUTEX_INIT_FAST) ||
    3507                 :       pthread_mutex_init(&log_descriptor.dirty_buffer_mask_lock,
    3508                 :                          MY_MUTEX_INIT_FAST) ||
    3509                 :       pthread_cond_init(&log_descriptor.log_flush_cond, 0) ||
    3510                 :       my_rwlock_init(&log_descriptor.open_files_lock,
    3511                 :                      NULL) ||
    3512                 :       my_init_dynamic_array(&log_descriptor.open_files,
    3513                 :                             sizeof(TRANSLOG_FILE*), 10, 10) ||
    3514                 :       my_init_dynamic_array(&log_descriptor.unfinished_files,
    3515                 :                             sizeof(struct st_file_counter),
    3516                 :                             10, 10))
    3517                 :     goto err;
    3518               5 :   log_descriptor.min_need_file= 0;
    3519               5 :   log_descriptor.min_file_number= 0;
    3520               5 :   log_descriptor.last_lsn_checked= LSN_IMPOSSIBLE;
    3521                 : 
    3522                 :   /* Directory to store files */
    3523               5 :   unpack_dirname(log_descriptor.directory, directory);
    3524                 : #ifndef __WIN__
    3525               5 :   if ((log_descriptor.directory_fd= my_open(log_descriptor.directory,
    3526                 :                                             O_RDONLY, MYF(MY_WME))) < 0)
    3527                 :   {
    3528               0 :     my_errno= errno;
    3529               0 :     DBUG_PRINT("error", ("Error %d during opening directory '%s'",
    3530                 :                          errno, log_descriptor.directory));
    3531               0 :     goto err;
    3532                 :   }
    3533                 : #endif
    3534               5 :   log_descriptor.in_buffers_only= LSN_IMPOSSIBLE;
    3535               5 :   DBUG_ASSERT(log_file_max_size % TRANSLOG_PAGE_SIZE == 0 &&
    3536                 :               log_file_max_size >= TRANSLOG_MIN_FILE_SIZE);
    3537                 :   /* max size of one log size (for new logs creation) */
    3538               5 :   log_file_size= log_descriptor.log_file_max_size=
    3539                 :     log_file_max_size;
    3540                 :   /* server version */
    3541               5 :   log_descriptor.server_version= server_version;
    3542                 :   /* server ID */
    3543               5 :   log_descriptor.server_id= server_id;
    3544                 :   /* Page cache for the log reads */
    3545               5 :   log_descriptor.pagecache= pagecache;
    3546                 :   /* Flags */
    3547               5 :   DBUG_ASSERT((flags &
    3548                 :                ~(TRANSLOG_PAGE_CRC | TRANSLOG_SECTOR_PROTECTION |
    3549                 :                  TRANSLOG_RECORD_CRC)) == 0);
    3550               5 :   log_descriptor.flags= flags;
    3551               5 :   translog_fill_overhead_table();
    3552               5 :   log_descriptor.page_overhead= page_overhead[flags];
    3553               5 :   log_descriptor.page_capacity_chunk_2=
    3554                 :     TRANSLOG_PAGE_SIZE - log_descriptor.page_overhead - 1;
    3555                 :   compile_time_assert(TRANSLOG_WRITE_BUFFER % TRANSLOG_PAGE_SIZE == 0);
    3556               5 :   log_descriptor.buffer_capacity_chunk_2=
    3557                 :     (TRANSLOG_WRITE_BUFFER / TRANSLOG_PAGE_SIZE) *
    3558                 :     log_descriptor.page_capacity_chunk_2;
    3559               5 :   log_descriptor.half_buffer_capacity_chunk_2=
    3560                 :     log_descriptor.buffer_capacity_chunk_2 / 2;
    3561               5 :   DBUG_PRINT("info",
    3562                 :              ("Overhead: %u  pc2: %u  bc2: %u,  bc2/2: %u",
    3563                 :               log_descriptor.page_overhead,
    3564                 :               log_descriptor.page_capacity_chunk_2,
    3565                 :               log_descriptor.buffer_capacity_chunk_2,
    3566                 :               log_descriptor.half_buffer_capacity_chunk_2));
    3567                 : 
    3568                 :   /* Just to init it somehow (hack for bootstrap)*/
    3569                 :   {
    3570               5 :     TRANSLOG_FILE *file= 0;
    3571               5 :     log_descriptor.min_file = log_descriptor.max_file= 1;
    3572               5 :     insert_dynamic(&log_descriptor.open_files, (uchar *)&file);
    3573               5 :     translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
    3574               5 :     pop_dynamic(&log_descriptor.open_files);
    3575                 :   }
    3576                 : 
    3577                 :   /* Buffers for log writing */
    3578              45 :   for (i= 0; i < TRANSLOG_BUFFERS_NO; i++)
    3579                 :   {
    3580              40 :     if (translog_buffer_init(log_descriptor.buffers + i, i))
    3581              40 :       goto err;
    3582              40 :     DBUG_PRINT("info", ("translog_buffer buffer #%u: 0x%lx",
    3583                 :                         i, (ulong) log_descriptor.buffers + i));
    3584                 :   }
    3585                 : 
    3586                 :   /*
    3587                 :     last_logno and last_checkpoint_lsn were set in
    3588                 :     ma_control_file_create_or_open()
    3589                 :   */
    3590               5 :   logs_found= (last_logno != FILENO_IMPOSSIBLE);
    3591                 : 
    3592               5 :   translog_status= (readonly ? TRANSLOG_READONLY : TRANSLOG_OK);
    3593               5 :   checkpoint_lsn= last_checkpoint_lsn;
    3594                 : 
    3595               5 :   if (logs_found)
    3596                 :   {
    3597                 :     my_bool pageok;
    3598               0 :     DBUG_PRINT("info", ("log found..."));
    3599                 :     /*
    3600                 :       TODO: scan directory for maria_log.XXXXXXXX files and find
    3601                 :        highest XXXXXXXX & set logs_found
    3602                 :       TODO: check that last checkpoint within present log addresses space
    3603                 : 
    3604                 :       find the log end
    3605                 :     */
    3606               0 :     if (LSN_FILE_NO(last_checkpoint_lsn) == FILENO_IMPOSSIBLE)
    3607                 :     {
    3608               0 :       DBUG_ASSERT(LSN_OFFSET(last_checkpoint_lsn) == 0);
    3609                 :       /* only last log needs to be checked */
    3610               0 :       sure_page= MAKE_LSN(last_logno, TRANSLOG_PAGE_SIZE);
    3611                 :     }
    3612                 :     else
    3613                 :     {
    3614               0 :       sure_page= last_checkpoint_lsn;
    3615               0 :       DBUG_ASSERT(LSN_OFFSET(sure_page) % TRANSLOG_PAGE_SIZE != 0);
    3616               0 :       sure_page-= LSN_OFFSET(sure_page) % TRANSLOG_PAGE_SIZE;
    3617                 :     }
    3618                 :     /* Set horizon to the beginning of the last file first */
    3619               0 :     log_descriptor.horizon= last_page= MAKE_LSN(last_logno, 0);
    3620               0 :     if (translog_get_last_page_addr(&last_page, &pageok, no_errors))
    3621                 :     {
    3622               0 :       if (!translog_walk_filenames(log_descriptor.directory,
    3623                 :                                    &translog_callback_search_first))
    3624                 :       {
    3625                 :         /*
    3626                 :           Files was deleted, just start from the next log number, so that
    3627                 :           existing tables are in the past.
    3628                 :         */
    3629               0 :         start_file_num= last_logno + 1;
    3630               0 :         checkpoint_lsn= LSN_IMPOSSIBLE; /* no log so no checkpoint */
    3631               0 :         logs_found= 0;
    3632                 :       }
    3633                 :       else
    3634               0 :         goto err;
    3635                 :     }
    3636               0 :     else if (LSN_OFFSET(last_page) == 0)
    3637                 :     {
    3638               0 :       if (LSN_FILE_NO(last_page) == 1)
    3639                 :       {
    3640               0 :         logs_found= 0;                          /* file #1 has no pages */
    3641               0 :         DBUG_PRINT("info", ("log found. But is is empty => no log assumed"));
    3642                 :       }
    3643                 :       else
    3644                 :       {
    3645               0 :         last_page-= LSN_ONE_FILE;
    3646               0 :         if (translog_get_last_page_addr(&last_page, &pageok, 0))
    3647               0 :           goto err;
    3648                 :       }
    3649                 :     }
    3650               0 :     if (logs_found)
    3651                 :     {
    3652                 :       uint32 i;
    3653               0 :       log_descriptor.min_file= translog_first_file(log_descriptor.horizon, 1);
    3654               0 :       log_descriptor.max_file= last_logno;
    3655                 :       /* Open all files */
    3656               0 :       if (allocate_dynamic(&log_descriptor.open_files,
    3657                 :                            log_descriptor.max_file -
    3658                 :                            log_descriptor.min_file + 1))
    3659               0 :         goto err;
    3660               0 :       for (i = log_descriptor.max_file; i >= log_descriptor.min_file; i--)
    3661                 :       {
    3662                 :         /*
    3663                 :           We can't allocate all file together because they will be freed
    3664                 :           one by one
    3665                 :         */
    3666               0 :         TRANSLOG_FILE *file= (TRANSLOG_FILE *)my_malloc(sizeof(TRANSLOG_FILE),
    3667                 :                                                         MYF(0));
    3668                 : 
    3669                 :         compile_time_assert(MY_FILEPOS_ERROR > ULL(0xffffffff));
    3670               0 :         if (file == NULL ||
    3671                 :             (file->handler.file=
    3672                 :              open_logfile_by_number_no_cache(i)) < 0 ||
    3673                 :             my_seek(file->handler.file, 0, SEEK_END, MYF(0)) >=
    3674                 :             ULL(0xffffffff))
    3675                 :         {
    3676                 :           int j;
    3677               0 :           for (j= i - log_descriptor.min_file - 1; j > 0; j--)
    3678                 :           {
    3679                 :             TRANSLOG_FILE *el=
    3680               0 :               *dynamic_element(&log_descriptor.open_files, j,
    3681                 :                                TRANSLOG_FILE **);
    3682               0 :             my_close(el->handler.file, MYF(MY_WME));
    3683               0 :             my_free(el, MYF(0));
    3684                 :           }
    3685               0 :           if (file)
    3686                 :           {
    3687               0 :             free(file);
    3688               0 :             goto err;
    3689                 :           }
    3690                 :           else
    3691               0 :             goto err;
    3692                 :         }
    3693               0 :         translog_file_init(file, i, 1);
    3694                 :         /* we allocated space so it can't fail */
    3695               0 :         insert_dynamic(&log_descriptor.open_files, (uchar *)&file);
    3696                 :       }
    3697               0 :       DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
    3698                 :                   log_descriptor.open_files.elements);
    3699                 :     }
    3700                 :   }
    3701               5 :   else if (readonly)
    3702                 :   {
    3703                 :     /* There is no logs and there is read-only mode => nothing to read */
    3704               0 :     DBUG_PRINT("error", ("No logs and read-only mode"));
    3705               0 :     goto err;
    3706                 :   }
    3707                 : 
    3708               5 :   if (logs_found)
    3709                 :   {
    3710               0 :     TRANSLOG_ADDRESS current_page= sure_page;
    3711                 :     my_bool pageok;
    3712                 : 
    3713               0 :     DBUG_PRINT("info", ("The log is really present"));
    3714               0 :     DBUG_ASSERT(sure_page <= last_page);
    3715                 : 
    3716                 :     /* TODO: check page size */
    3717                 : 
    3718               0 :     last_valid_page= LSN_IMPOSSIBLE;
    3719                 :     /*
    3720                 :       Scans and validate pages. We need it to show "outside" only for sure
    3721                 :       valid part of the log. If the log was damaged then fixed we have to
    3722                 :       cut off damaged part before some other process start write something
    3723                 :       in the log.
    3724                 :     */
    3725                 :     do
    3726                 :     {
    3727                 :       TRANSLOG_ADDRESS current_file_last_page;
    3728               0 :       current_file_last_page= current_page;
    3729               0 :       if (translog_get_last_page_addr(&current_file_last_page, &pageok, 0))
    3730               0 :         goto err;
    3731               0 :       if (!pageok)
    3732                 :       {
    3733               0 :         DBUG_PRINT("error", ("File %lu have no complete last page",
    3734                 :                              (ulong) LSN_FILE_NO(current_file_last_page)));
    3735               0 :         old_log_was_recovered= 1;
    3736                 :         /* This file is not written till the end so it should be last */
    3737               0 :         last_page= current_file_last_page;
    3738                 :         /* TODO: issue warning */
    3739                 :       }
    3740                 :       do
    3741                 :       {
    3742                 :         TRANSLOG_VALIDATOR_DATA data;
    3743                 :         TRANSLOG_PAGE_SIZE_BUFF psize_buff;
    3744                 :         uchar *page;
    3745               0 :         data.addr= &current_page;
    3746               0 :         if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL)
    3747               0 :           goto err;
    3748               0 :         if (data.was_recovered)
    3749                 :         {
    3750               0 :           DBUG_PRINT("error", ("file no: %lu (%d)  "
    3751                 :                                "rec_offset: 0x%lx (%lu) (%d)",
    3752                 :                                (ulong) LSN_FILE_NO(current_page),
    3753                 :                                (uint3korr(page + 3) !=
    3754                 :                                 LSN_FILE_NO(current_page)),
    3755                 :                                (ulong) LSN_OFFSET(current_page),
    3756                 :                                (ulong) (LSN_OFFSET(current_page) /
    3757                 :                                         TRANSLOG_PAGE_SIZE),
    3758                 :                                (uint3korr(page) !=
    3759                 :                                 LSN_OFFSET(current_page) /
    3760                 :                                 TRANSLOG_PAGE_SIZE)));
    3761               0 :           old_log_was_recovered= 1;
    3762               0 :           break;
    3763                 :         }
    3764               0 :         old_flags= page[TRANSLOG_PAGE_FLAGS];
    3765               0 :         last_valid_page= current_page;
    3766               0 :         current_page+= TRANSLOG_PAGE_SIZE; /* increase offset */
    3767               0 :       } while (current_page <= current_file_last_page);
    3768               0 :       current_page+= LSN_ONE_FILE;
    3769               0 :       current_page= LSN_REPLACE_OFFSET(current_page, TRANSLOG_PAGE_SIZE);
    3770                 :     } while (LSN_FILE_NO(current_page) <= LSN_FILE_NO(last_page) &&
    3771               0 :              !old_log_was_recovered);
    3772               0 :     if (last_valid_page == LSN_IMPOSSIBLE)
    3773                 :     {
    3774                 :       /* Panic!!! Even page which should be valid is invalid */
    3775                 :       /* TODO: issue error */
    3776               0 :       goto err;
    3777                 :     }
    3778               0 :     DBUG_PRINT("info", ("Last valid page is in file: %lu  "
    3779                 :                         "offset: %lu (0x%lx)  "
    3780                 :                         "Logs found: %d  was recovered: %d  "
    3781                 :                         "flags match: %d",
    3782                 :                         (ulong) LSN_FILE_NO(last_valid_page),
    3783                 :                         (ulong) LSN_OFFSET(last_valid_page),
    3784                 :                         (ulong) LSN_OFFSET(last_valid_page),
    3785                 :                         logs_found, old_log_was_recovered,
    3786                 :                         (old_flags == flags)));
    3787                 : 
    3788                 :     /* TODO: check server ID */
    3789               0 :     if (logs_found && !old_log_was_recovered && old_flags == flags)
    3790                 :     {
    3791                 :       TRANSLOG_VALIDATOR_DATA data;
    3792                 :       TRANSLOG_PAGE_SIZE_BUFF psize_buff;
    3793                 :       uchar *page;
    3794                 :       uint16 chunk_offset;
    3795               0 :       data.addr= &last_valid_page;
    3796                 :       /* continue old log */
    3797               0 :       DBUG_ASSERT(LSN_FILE_NO(last_valid_page)==
    3798                 :                   LSN_FILE_NO(log_descriptor.horizon));
    3799               0 :       if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL ||
    3800                 :           (chunk_offset= translog_get_first_chunk_offset(page)) == 0)
    3801                 :         goto err;
    3802                 : 
    3803                 :       /* Puts filled part of old page in the buffer */
    3804               0 :       log_descriptor.horizon= last_valid_page;
    3805               0 :       translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
    3806                 :       /*
    3807                 :          Free space if filled with TRANSLOG_FILLER and first uchar of
    3808                 :          real chunk can't be TRANSLOG_FILLER
    3809                 :       */
    3810               0 :       while (chunk_offset < TRANSLOG_PAGE_SIZE &&
    3811                 :              page[chunk_offset] != TRANSLOG_FILLER)
    3812                 :       {
    3813                 :         uint16 chunk_length;
    3814               0 :         if ((chunk_length=
    3815                 :              translog_get_total_chunk_length(page, chunk_offset)) == 0)
    3816               0 :           goto err;
    3817               0 :         DBUG_PRINT("info", ("chunk: offset: %u  length: %u",
    3818                 :                             (uint) chunk_offset, (uint) chunk_length));
    3819               0 :         chunk_offset+= chunk_length;
    3820                 : 
    3821                 :         /* chunk can't cross the page border */
    3822               0 :         DBUG_ASSERT(chunk_offset <= TRANSLOG_PAGE_SIZE);
    3823                 :       }
    3824               0 :       memcpy(log_descriptor.buffers->buffer, page, chunk_offset);
    3825               0 :       log_descriptor.bc.buffer->size+= chunk_offset;
    3826               0 :       log_descriptor.bc.ptr+= chunk_offset;
    3827               0 :       log_descriptor.bc.current_page_fill= chunk_offset;
    3828               0 :       log_descriptor.horizon= LSN_REPLACE_OFFSET(log_descriptor.horizon,
    3829                 :                                                  (chunk_offset +
    3830                 :                                                   LSN_OFFSET(last_valid_page)));
    3831               0 :       DBUG_PRINT("info", ("Move Page #%u: 0x%lx  chaser: %d  Size: %lu (%lu)",
    3832                 :                           (uint) log_descriptor.bc.buffer_no,
    3833                 :                           (ulong) log_descriptor.bc.buffer,
    3834                 :                           log_descriptor.bc.chaser,
    3835                 :                           (ulong) log_descriptor.bc.buffer->size,
    3836                 :                           (ulong) (log_descriptor.bc.ptr - log_descriptor.bc.
    3837                 :                                    buffer->buffer)));
    3838               0 :       translog_check_cursor(&log_descriptor.bc);
    3839                 :     }
    3840               0 :     if (!old_log_was_recovered && old_flags == flags)
    3841                 :     {
    3842                 :       LOGHANDLER_FILE_INFO info;
    3843                 :       /*
    3844                 :         Accessing &log_descriptor.open_files without mutex is safe
    3845                 :         because it is initialization
    3846                 :       */
    3847               0 :       if (translog_read_file_header(&info,
    3848                 :                                     (*dynamic_element(&log_descriptor.
    3849                 :                                                       open_files,
    3850                 :                                                       0, TRANSLOG_FILE **))->
    3851                 :                                     handler.file))
    3852               0 :         goto err;
    3853               0 :       version_changed= (info.maria_version != TRANSLOG_VERSION_ID);
    3854                 :     }
    3855                 :   }
    3856               5 :   DBUG_PRINT("info", ("Logs found: %d  was recovered: %d",
    3857                 :                       logs_found, old_log_was_recovered));
    3858               5 :   if (!logs_found)
    3859                 :   {
    3860               5 :     TRANSLOG_FILE *file= (TRANSLOG_FILE*)my_malloc(sizeof(TRANSLOG_FILE),
    3861                 :                                                    MYF(0));
    3862               5 :     DBUG_PRINT("info", ("The log is not found => we will create new log"));
    3863               5 :     if (file == NULL)
    3864               5 :        goto err;
    3865                 :     /* Start new log system from scratch */
    3866               5 :     log_descriptor.horizon= MAKE_LSN(start_file_num,
    3867                 :                                      TRANSLOG_PAGE_SIZE); /* header page */
    3868               5 :     if ((file->handler.file=
    3869                 :          create_logfile_by_number_no_cache(start_file_num)) == -1)
    3870               5 :       goto err;
    3871               5 :     translog_file_init(file, start_file_num, 0);
    3872               5 :     if (insert_dynamic(&log_descriptor.open_files, (uchar*)&file))
    3873               5 :       goto err;
    3874               5 :     log_descriptor.min_file= log_descriptor.max_file= start_file_num;
    3875               5 :     if (translog_write_file_header())
    3876               5 :       goto err;
    3877               5 :     DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
    3878                 :                 log_descriptor.open_files.elements);
    3879                 : 
    3880               5 :     if (ma_control_file_write_and_force(checkpoint_lsn, start_file_num,
    3881                 :                                         max_trid_in_control_file,
    3882                 :                                         recovery_failures))
    3883               5 :       goto err;
    3884                 :     /* assign buffer 0 */
    3885               5 :     translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
    3886               5 :     translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
    3887                 :   }
    3888               0 :   else if ((old_log_was_recovered || old_flags != flags || version_changed) &&
    3889                 :            !readonly)
    3890                 :   {
    3891                 :     /* leave the damaged file untouched */
    3892               0 :     log_descriptor.horizon+= LSN_ONE_FILE;
    3893                 :     /* header page */
    3894               0 :     log_descriptor.horizon= LSN_REPLACE_OFFSET(log_descriptor.horizon,
    3895                 :                                                TRANSLOG_PAGE_SIZE);
    3896               0 :     if (translog_create_new_file())
    3897               0 :       goto err;
    3898                 :     /*
    3899                 :       Buffer system left untouched after recovery => we should init it
    3900                 :       (starting from buffer 0)
    3901                 :     */
    3902               0 :     translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
    3903               0 :     translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
    3904                 :   }
    3905                 : 
    3906                 :   /* all LSNs that are on disk are flushed */
    3907               5 :   log_descriptor.log_start= log_descriptor.sent_to_disk=
    3908                 :     log_descriptor.flushed= log_descriptor.horizon;
    3909               5 :   log_descriptor.in_buffers_only= log_descriptor.bc.buffer->offset;
    3910               5 :   log_descriptor.max_lsn= LSN_IMPOSSIBLE; /* set to 0 */
    3911               5 :   log_descriptor.previous_flush_horizon= log_descriptor.horizon;
    3912                 :   /*
    3913                 :     Now 'flushed' is set to 'horizon' value, but 'horizon' is (potentially)
    3914                 :     address of the next LSN and we want indicate that all LSNs that are
    3915                 :     already on the disk are flushed so we need decrease horizon on 1 (we are
    3916                 :     sure that there is no LSN on the disk which is greater then 'flushed'
    3917                 :     and there will not be LSN created that is equal or less then the value
    3918                 :     of the 'flushed').
    3919                 :   */
    3920               5 :   log_descriptor.flushed--; /* offset decreased */
    3921               5 :   log_descriptor.sent_to_disk--; /* offset decreased */
    3922                 :   /*
    3923                 :     Log records will refer to a MARIA_SHARE by a unique 2-byte id; set up
    3924                 :     structures for generating 2-byte ids:
    3925                 :   */
    3926                 :   my_atomic_rwlock_init(&LOCK_id_to_share);
    3927               5 :   id_to_share= (MARIA_SHARE **) my_malloc(SHARE_ID_MAX * sizeof(MARIA_SHARE*),
    3928                 :                                           MYF(MY_WME | MY_ZEROFILL));
    3929               5 :   if (unlikely(!id_to_share))
    3930               5 :     goto err;
    3931               5 :   id_to_share--; /* min id is 1 */
    3932                 : 
    3933                 :   /* Check the last LSN record integrity */
    3934               5 :   if (logs_found)
    3935                 :   {
    3936                 :     TRANSLOG_SCANNER_DATA scanner;
    3937                 :     TRANSLOG_ADDRESS page_addr;
    3938               0 :     LSN last_lsn= LSN_IMPOSSIBLE;
    3939                 :     /*
    3940                 :       take very last page address and try to find LSN record on it
    3941                 :       if it fail take address of previous page and so on
    3942                 :     */
    3943               0 :     page_addr= (log_descriptor.horizon -
    3944                 :                 ((log_descriptor.horizon - 1) % TRANSLOG_PAGE_SIZE + 1));
    3945               0 :     if (translog_scanner_init(page_addr, 1, &scanner, 1))
    3946               0 :       goto err;
    3947               0 :     scanner.page_offset= page_overhead[scanner.page[TRANSLOG_PAGE_FLAGS]];
    3948                 :     for (;;)
    3949                 :     {
    3950                 :       uint chunk_1byte;
    3951               0 :       chunk_1byte= scanner.page[scanner.page_offset];
    3952               0 :       while (!translog_is_LSN_chunk(chunk_1byte) &&
    3953                 :              scanner.page != END_OF_LOG &&
    3954                 :              scanner.page[scanner.page_offset] != TRANSLOG_FILLER &&
    3955                 :              scanner.page_addr == page_addr)
    3956                 :       {
    3957               0 :         if (translog_get_next_chunk(&scanner))
    3958                 :         {
    3959               0 :           translog_destroy_scanner(&scanner);
    3960               0 :           goto err;
    3961                 :         }
    3962               0 :         if (scanner.page != END_OF_LOG)
    3963               0 :           chunk_1byte= scanner.page[scanner.page_offset];
    3964                 :       }
    3965               0 :       if (translog_is_LSN_chunk(chunk_1byte))
    3966                 :       {
    3967               0 :         last_lsn= scanner.page_addr + scanner.page_offset;
    3968               0 :         if (translog_get_next_chunk(&scanner))
    3969                 :         {
    3970               0 :           translog_destroy_scanner(&scanner);
    3971               0 :           goto err;
    3972                 :         }
    3973               0 :         if (scanner.page == END_OF_LOG)
    3974               0 :           break; /* it was the last record */
    3975               0 :         chunk_1byte= scanner.page[scanner.page_offset];
    3976               0 :         continue; /* try to find other record on this page */
    3977                 :       }
    3978                 : 
    3979               0 :       if (last_lsn != LSN_IMPOSSIBLE)
    3980               0 :         break; /* there is no more records on the page */
    3981                 : 
    3982                 :       /* We have to make step back */
    3983               0 :       if (unlikely(LSN_OFFSET(page_addr) == TRANSLOG_PAGE_SIZE))
    3984                 :       {
    3985               0 :         uint32 file_no= LSN_FILE_NO(page_addr);
    3986                 :         my_bool last_page_ok;
    3987                 :         /* it is beginning of the current file */
    3988               0 :         if (unlikely(file_no == 1))
    3989                 :         {
    3990                 :           /*
    3991                 :             It is beginning of the log => there is no LSNs in the log =>
    3992                 :             There is no harm in leaving it "as-is".
    3993                 :           */
    3994               0 :           DBUG_RETURN(0);
    3995                 :         }
    3996               0 :         file_no--;
    3997               0 :         page_addr= MAKE_LSN(file_no, TRANSLOG_PAGE_SIZE);
    3998               0 :         translog_get_last_page_addr(&page_addr, &last_page_ok, 0);
    3999                 :         /* page should be OK as it is not the last file */
    4000               0 :         DBUG_ASSERT(last_page_ok);
    4001                 :       }
    4002                 :       else
    4003                 :       {
    4004               0 :          page_addr-= TRANSLOG_PAGE_SIZE;
    4005                 :       }
    4006               0 :       translog_destroy_scanner(&scanner);
    4007               0 :       if (translog_scanner_init(page_addr, 1, &scanner, 1))
    4008               0 :         goto err;
    4009               0 :       scanner.page_offset= page_overhead[scanner.page[TRANSLOG_PAGE_FLAGS]];
    4010                 :     }
    4011               0 :     translog_destroy_scanner(&scanner);
    4012                 : 
    4013                 :     /* Now scanner points to the last LSN chunk, lets check it */
    4014                 :     {
    4015                 :       TRANSLOG_HEADER_BUFFER rec;
    4016                 :       translog_size_t rec_len;
    4017                 :       int len;
    4018                 :       uchar buffer[1];
    4019               0 :       DBUG_PRINT("info", ("going to check the last found record (%lu,0x%lx)",
    4020                 :                           LSN_IN_PARTS(last_lsn)));
    4021                 : 
    4022               0 :       len=
    4023                 :         translog_read_record_header(last_lsn, &rec);
    4024               0 :       if (unlikely (len == RECHEADER_READ_ERROR ||
    4025                 :                     len == RECHEADER_READ_EOF))
    4026                 :       {
    4027               0 :         DBUG_PRINT("error", ("unexpected end of log or record during "
    4028                 :                              "reading record header: (%lu,0x%lx)  len: %d",
    4029                 :                              LSN_IN_PARTS(last_lsn), len));
    4030               0 :         if (readonly)
    4031               0 :           log_descriptor.log_start= log_descriptor.horizon= last_lsn;
    4032               0 :         else if (translog_truncate_log(last_lsn))
    4033                 :         {
    4034               0 :           translog_free_record_header(&rec);
    4035               0 :           goto err;
    4036                 :         }
    4037                 :       }
    4038                 :       else
    4039                 :       {
    4040               0 :         DBUG_ASSERT(last_lsn == rec.lsn);
    4041               0 :         if (likely(rec.record_length != 0))
    4042                 :         {
    4043                 :           /*
    4044                 :             Reading the last byte of record will trigger scanning all
    4045                 :             record chunks for now
    4046                 :           */
    4047               0 :           rec_len= translog_read_record(rec.lsn, rec.record_length - 1, 1,
    4048                 :                                         buffer, NULL);
    4049               0 :           if (rec_len != 1)
    4050                 :           {
    4051               0 :             DBUG_PRINT("error", ("unexpected end of log or record during "
    4052                 :                                  "reading record body: (%lu,0x%lx)  len: %d",
    4053                 :                                  LSN_IN_PARTS(rec.lsn),
    4054                 :                                  len));
    4055               0 :             if (readonly)
    4056               0 :               log_descriptor.log_start= log_descriptor.horizon= last_lsn;
    4057                 : 
    4058               0 :             else if (translog_truncate_log(last_lsn))
    4059                 :             {
    4060               0 :               translog_free_record_header(&rec);
    4061               0 :               goto err;
    4062                 :             }
    4063                 :           }
    4064                 :         }
    4065                 :       }
    4066               0 :       translog_free_record_header(&rec);
    4067                 :     }
    4068                 :   }
    4069               5 :   DBUG_RETURN(0);
    4070               0 : err:
    4071               0 :   ma_message_no_user(0, "log initialization failed");
    4072               0 :   DBUG_RETURN(1);
    4073                 : }
    4074                 : 
    4075                 : 
    4076                 : /*
    4077                 :   @brief Free transaction log file buffer.
    4078                 : 
    4079                 :   @param buffer_no       The buffer to free
    4080                 : */
    4081                 : 
    4082                 : static void translog_buffer_destroy(struct st_translog_buffer *buffer)
    4083              32 : {
    4084              32 :   DBUG_ENTER("translog_buffer_destroy");
    4085              32 :   DBUG_PRINT("enter",
    4086                 :              ("Buffer #%u: 0x%lx  file: %d  offset: (%lu,0x%lx)  size: %lu",
    4087                 :               (uint) buffer->buffer_no, (ulong) buffer,
    4088                 :               (buffer->file ? buffer->file->handler.file : -1),
    4089                 :               LSN_IN_PARTS(buffer->offset),
    4090                 :               (ulong) buffer->size));
    4091              32 :   if (buffer->file != NULL)
    4092                 :   {
    4093                 :     /*
    4094                 :       We ignore errors here, because we can't do something about it
    4095                 :       (it is shutting down)
    4096                 : 
    4097                 :       We also have to take the locks even if there can't be any other
    4098                 :       threads running, because translog_buffer_flush()
    4099                 :       requires that we have the buffer locked.
    4100                 :     */
    4101               4 :     translog_buffer_lock(buffer);
    4102               4 :     translog_buffer_flush(buffer);
    4103               4 :     translog_buffer_unlock(buffer);
    4104                 :   }
    4105              32 :   DBUG_PRINT("info", ("Destroy mutex: 0x%lx", (ulong) &buffer->mutex));
    4106              32 :   pthread_mutex_destroy(&buffer->mutex);
    4107              32 :   pthread_cond_destroy(&buffer->waiting_filling_buffer);
    4108              32 :   DBUG_VOID_RETURN;
    4109                 : }
    4110                 : 
    4111                 : 
    4112                 : /*
    4113                 :   Free log handler resources
    4114                 : 
    4115                 :   SYNOPSIS
    4116                 :     translog_destroy()
    4117                 : */
    4118                 : 
    4119                 : void translog_destroy()
    4120               4 : {
    4121                 :   TRANSLOG_FILE **file;
    4122                 :   uint i;
    4123                 :   uint8 current_buffer;
    4124               4 :   DBUG_ENTER("translog_destroy");
    4125                 : 
    4126               4 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    4127                 :               translog_status == TRANSLOG_READONLY);
    4128               4 :   translog_lock();
    4129               4 :   current_buffer= log_descriptor.bc.buffer_no;
    4130               4 :   translog_status= (translog_status == TRANSLOG_READONLY ?
    4131                 :                     TRANSLOG_UNINITED :
    4132                 :                     TRANSLOG_SHUTDOWN);
    4133               4 :   if (log_descriptor.bc.buffer->file != NULL)
    4134               4 :     translog_finish_page(&log_descriptor.horizon, &log_descriptor.bc);
    4135               4 :   translog_unlock();
    4136                 : 
    4137              36 :   for (i= 0; i < TRANSLOG_BUFFERS_NO; i++)
    4138                 :   {
    4139                 :     struct st_translog_buffer *buffer= (log_descriptor.buffers +
    4140                 :                                         ((i + current_buffer + 1) %
    4141              32 :                                          TRANSLOG_BUFFERS_NO));
    4142              32 :     translog_buffer_destroy(buffer);
    4143                 :   }
    4144               4 :   translog_status= TRANSLOG_UNINITED;
    4145                 : 
    4146                 :   /* close files */
    4147              12 :   while ((file= (TRANSLOG_FILE **)pop_dynamic(&log_descriptor.open_files)))
    4148               4 :     translog_close_log_file(*file);
    4149               4 :   pthread_mutex_destroy(&log_descriptor.sent_to_disk_lock);
    4150               4 :   pthread_mutex_destroy(&log_descriptor.file_header_lock);
    4151               4 :   pthread_mutex_destroy(&log_descriptor.unfinished_files_lock);
    4152               4 :   pthread_mutex_destroy(&log_descriptor.purger_lock);
    4153               4 :   pthread_mutex_destroy(&log_descriptor.log_flush_lock);
    4154               4 :   pthread_mutex_destroy(&log_descriptor.dirty_buffer_mask_lock);
    4155               4 :   pthread_cond_destroy(&log_descriptor.log_flush_cond);
    4156               4 :   rwlock_destroy(&log_descriptor.open_files_lock);
    4157               4 :   delete_dynamic(&log_descriptor.open_files);
    4158               4 :   delete_dynamic(&log_descriptor.unfinished_files);
    4159                 : 
    4160               4 :   if (log_descriptor.directory_fd >= 0)
    4161               4 :     my_close(log_descriptor.directory_fd, MYF(MY_WME));
    4162                 :   my_atomic_rwlock_destroy(&LOCK_id_to_share);
    4163               4 :   if (id_to_share != NULL)
    4164               4 :     my_free((id_to_share + 1), MYF(MY_WME));
    4165               4 :   DBUG_VOID_RETURN;
    4166                 : }
    4167                 : 
    4168                 : 
    4169                 : /*
    4170                 :   @brief Starts new page.
    4171                 : 
    4172                 :   @param horizon         \ Position in file and buffer where we are
    4173                 :   @param cursor          /
    4174                 :   @param prev_buffer     Buffer which should be flushed will be assigned here.
    4175                 :                          This is always set (to NULL if nothing to flush).
    4176                 : 
    4177                 :   @note We do not want to flush the buffer immediately because we want to
    4178                 :   let caller of this function first advance 'horizon' pointer and unlock the
    4179                 :   loghandler and only then flush the log which can take some time.
    4180                 : 
    4181                 :   @retval 0 OK
    4182                 :   @retval 1 Error
    4183                 : */
    4184                 : 
    4185                 : static my_bool translog_page_next(TRANSLOG_ADDRESS *horizon,
    4186                 :                                   struct st_buffer_cursor *cursor,
    4187                 :                                   struct st_translog_buffer **prev_buffer)
    4188               0 : {
    4189               0 :   struct st_translog_buffer *buffer= cursor->buffer;
    4190               0 :   DBUG_ENTER("translog_page_next");
    4191                 : 
    4192               0 :   *prev_buffer= NULL;
    4193               0 :   if ((cursor->ptr + TRANSLOG_PAGE_SIZE >
    4194                 :        cursor->buffer->buffer + TRANSLOG_WRITE_BUFFER) ||
    4195                 :       (LSN_OFFSET(*horizon) >
    4196                 :        log_descriptor.log_file_max_size - TRANSLOG_PAGE_SIZE))
    4197                 :   {
    4198               0 :     DBUG_PRINT("info", ("Switch to next buffer  Buffer Size: %lu (%lu) => %d  "
    4199                 :                         "File size: %lu  max: %lu => %d",
    4200                 :                         (ulong) cursor->buffer->size,
    4201                 :                         (ulong) (cursor->ptr - cursor->buffer->buffer),
    4202                 :                         (cursor->ptr + TRANSLOG_PAGE_SIZE >
    4203                 :                          cursor->buffer->buffer + TRANSLOG_WRITE_BUFFER),
    4204                 :                         (ulong) LSN_OFFSET(*horizon),
    4205                 :                         (ulong) log_descriptor.log_file_max_size,
    4206                 :                         (LSN_OFFSET(*horizon) >
    4207                 :                          (log_descriptor.log_file_max_size -
    4208                 :                           TRANSLOG_PAGE_SIZE))));
    4209               0 :     if (translog_buffer_next(horizon, cursor,
    4210                 :                              LSN_OFFSET(*horizon) >
    4211                 :                              (log_descriptor.log_file_max_size -
    4212                 :                               TRANSLOG_PAGE_SIZE)))
    4213               0 :       DBUG_RETURN(1);
    4214               0 :     *prev_buffer= buffer;
    4215               0 :     DBUG_PRINT("info", ("Buffer #%u (0x%lu): have to be flushed",
    4216                 :                         (uint) buffer->buffer_no, (ulong) buffer));
    4217                 :   }
    4218                 :   else
    4219                 :   {
    4220               0 :     DBUG_PRINT("info", ("Use the same buffer #%u (0x%lu): "
    4221                 :                         "Buffer Size: %lu (%lu)",
    4222                 :                         (uint) buffer->buffer_no,
    4223                 :                         (ulong) buffer,
    4224                 :                         (ulong) cursor->buffer->size,
    4225                 :                         (ulong) (cursor->ptr - cursor->buffer->buffer)));
    4226               0 :     translog_finish_page(horizon, cursor);
    4227               0 :     translog_new_page_header(horizon, cursor);
    4228                 :   }
    4229               0 :   DBUG_RETURN(0);
    4230                 : }
    4231                 : 
    4232                 : 
    4233                 : /*
    4234                 :   Write data of given length to the current page
    4235                 : 
    4236                 :   SYNOPSIS
    4237                 :     translog_write_data_on_page()
    4238                 :     horizon              \ Pointers on file and buffer
    4239                 :     cursor               /
    4240                 :     length               IN     length of the chunk
    4241                 :     buffer               buffer with data
    4242                 : 
    4243                 :   RETURN
    4244                 :     0  OK
    4245                 :     1  Error
    4246                 : */
    4247                 : 
    4248                 : static my_bool translog_write_data_on_page(TRANSLOG_ADDRESS *horizon,
    4249                 :                                            struct st_buffer_cursor *cursor,
    4250                 :                                            translog_size_t length,
    4251                 :                                            uchar *buffer)
    4252               0 : {
    4253               0 :   DBUG_ENTER("translog_write_data_on_page");
    4254               0 :   DBUG_PRINT("enter", ("Chunk length: %lu  Page size %u",
    4255                 :                        (ulong) length, (uint) cursor->current_page_fill));
    4256               0 :   DBUG_ASSERT(length > 0);
    4257               0 :   DBUG_ASSERT(length + cursor->current_page_fill <= TRANSLOG_PAGE_SIZE);
    4258               0 :   DBUG_ASSERT(length + cursor->ptr <= cursor->buffer->buffer +
    4259                 :               TRANSLOG_WRITE_BUFFER);
    4260                 : 
    4261               0 :   memcpy(cursor->ptr, buffer, length);
    4262               0 :   cursor->ptr+= length;
    4263               0 :   (*horizon)+= length; /* adds offset */
    4264               0 :   cursor->current_page_fill+= length;
    4265               0 :   if (!cursor->chaser)
    4266               0 :     cursor->buffer->size+= length;
    4267               0 :   DBUG_PRINT("info", ("Write data buffer #%u: 0x%lx  "
    4268                 :                       "chaser: %d  Size: %lu (%lu)",
    4269                 :                       (uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
    4270                 :                       cursor->chaser, (ulong) cursor->buffer->size,
    4271                 :                       (ulong) (cursor->ptr - cursor->buffer->buffer)));
    4272               0 :   translog_check_cursor(cursor);
    4273                 : 
    4274               0 :   DBUG_RETURN(0);
    4275                 : }
    4276                 : 
    4277                 : 
    4278                 : /*
    4279                 :   Write data from parts of given length to the current page
    4280                 : 
    4281                 :   SYNOPSIS
    4282                 :     translog_write_parts_on_page()
    4283                 :     horizon              \ Pointers on file and buffer
    4284                 :     cursor               /
    4285                 :     length               IN     length of the chunk
    4286                 :     parts                IN/OUT chunk source
    4287                 : 
    4288                 :   RETURN
    4289                 :     0  OK
    4290                 :     1  Error
    4291                 : */
    4292                 : 
    4293                 : static my_bool translog_write_parts_on_page(TRANSLOG_ADDRESS *horizon,
    4294                 :                                             struct st_buffer_cursor *cursor,
    4295                 :                                             translog_size_t length,
    4296                 :                                             struct st_translog_parts *parts)
    4297              18 : {
    4298              18 :   translog_size_t left= length;
    4299              18 :   uint cur= (uint) parts->current;
    4300              18 :   DBUG_ENTER("translog_write_parts_on_page");
    4301              18 :   DBUG_PRINT("enter", ("Chunk length: %lu  parts: %u of %u. Page size: %u  "
    4302                 :                        "Buffer size: %lu (%lu)",
    4303                 :                        (ulong) length,
    4304                 :                        (uint) (cur + 1), (uint) parts->elements,
    4305                 :                        (uint) cursor->current_page_fill,
    4306                 :                        (ulong) cursor->buffer->size,
    4307                 :                        (ulong) (cursor->ptr - cursor->buffer->buffer)));
    4308              18 :   DBUG_ASSERT(length > 0);
    4309              18 :   DBUG_ASSERT(length + cursor->current_page_fill <= TRANSLOG_PAGE_SIZE);
    4310              18 :   DBUG_ASSERT(length + cursor->ptr <= cursor->buffer->buffer +
    4311                 :               TRANSLOG_WRITE_BUFFER);
    4312                 : 
    4313                 :   do
    4314                 :   {
    4315                 :     translog_size_t len;
    4316                 :     LEX_CUSTRING *part;
    4317                 :     const uchar *buff;
    4318                 : 
    4319              61 :     DBUG_ASSERT(cur < parts->elements);
    4320              61 :     part= parts->parts + cur;
    4321              61 :     buff= part->str;
    4322              61 :     DBUG_PRINT("info", ("Part: %u  Length: %lu  left: %lu  buff: 0x%lx",
    4323                 :                         (uint) (cur + 1), (ulong) part->length, (ulong) left,
    4324                 :                         (ulong) buff));
    4325                 : 
    4326              61 :     if (part->length > left)
    4327                 :     {
    4328                 :       /* we should write less then the current part */
    4329               0 :       len= left;
    4330               0 :       part->length-= len;
    4331               0 :       part->str+= len;
    4332               0 :       DBUG_PRINT("info", ("Set new part: %u  Length: %lu",
    4333                 :                           (uint) (cur + 1), (ulong) part->length));
    4334                 :     }
    4335                 :     else
    4336                 :     {
    4337              61 :       len= (translog_size_t) part->length;
    4338              61 :       cur++;
    4339              61 :       DBUG_PRINT("info", ("moved to next part (len: %lu)", (ulong) len));
    4340                 :     }
    4341              61 :     DBUG_PRINT("info", ("copy: 0x%lx <- 0x%lx  %u",
    4342                 :                         (ulong) cursor->ptr, (ulong)buff, (uint)len));
    4343              61 :     if (likely(len))
    4344                 :     {
    4345              61 :       memcpy(cursor->ptr, buff, len);
    4346              61 :       left-= len;
    4347              61 :       cursor->ptr+= len;
    4348                 :     }
    4349              61 :   } while (left);
    4350                 : 
    4351              18 :   DBUG_PRINT("info", ("Horizon: (%lu,0x%lx)  Length %lu(0x%lx)",
    4352                 :                       LSN_IN_PARTS(*horizon),
    4353                 :                       (ulong) length, (ulong) length));
    4354              18 :   parts->current= cur;
    4355              18 :   (*horizon)+= length; /* offset increasing */
    4356              18 :   cursor->current_page_fill+= length;
    4357              18 :   if (!cursor->chaser)
    4358              18 :     cursor->buffer->size+= length;
    4359                 :   /*
    4360                 :     We do not not updating parts->total_record_length here because it is
    4361                 :     need only before writing record to have total length
    4362                 :   */
    4363              18 :   DBUG_PRINT("info", ("Write parts buffer #%u: 0x%lx  "
    4364                 :                       "chaser: %d  Size: %lu (%lu)  "
    4365                 :                       "Horizon: (%lu,0x%lx)  buff offset: 0x%lx",
    4366                 :                       (uint) cursor->buffer->buffer_no, (ulong) cursor->buffer,
    4367                 :                       cursor->chaser, (ulong) cursor->buffer->size,
    4368                 :                       (ulong) (cursor->ptr - cursor->buffer->buffer),
    4369                 :                       LSN_IN_PARTS(*horizon),
    4370                 :                       (ulong) (LSN_OFFSET(cursor->buffer->offset) +
    4371                 :                                cursor->buffer->size)));
    4372              18 :   translog_check_cursor(cursor);
    4373                 : 
    4374              18 :   DBUG_RETURN(0);
    4375                 : }
    4376                 : 
    4377                 : 
    4378                 : /*
    4379                 :   Put 1 group chunk type 0 header into parts array
    4380                 : 
    4381                 :   SYNOPSIS
    4382                 :     translog_write_variable_record_1group_header()
    4383                 :     parts                Descriptor of record source parts
    4384                 :     type                 The log record type
    4385                 :     short_trid           Short transaction ID or 0 if it has no sense
    4386                 :     header_length        Calculated header length of chunk type 0
    4387                 :     chunk0_header        Buffer for the chunk header writing
    4388                 : */
    4389                 : 
    4390                 : static void
    4391                 : translog_write_variable_record_1group_header(struct st_translog_parts *parts,
    4392                 :                                              enum translog_record_type type,
    4393                 :                                              SHORT_TRANSACTION_ID short_trid,
    4394                 :                                              uint16 header_length,
    4395                 :                                              uchar *chunk0_header)
    4396              13 : {
    4397                 :   LEX_CUSTRING *part;
    4398              13 :   DBUG_ASSERT(parts->current != 0);     /* first part is left for header */
    4399              13 :   part= parts->parts + (--parts->current);
    4400              13 :   parts->total_record_length+= (translog_size_t) (part->length= header_length);
    4401              13 :   part->str= chunk0_header;
    4402                 :   /* puts chunk type */
    4403              13 :   *chunk0_header= (uchar) (type | TRANSLOG_CHUNK_LSN);
    4404              13 :   int2store(chunk0_header + 1, short_trid);
    4405                 :   /* puts record length */
    4406              13 :   translog_write_variable_record_1group_code_len(chunk0_header + 3,
    4407                 :                                                  parts->record_length,
    4408                 :                                                  header_length);
    4409                 :   /* puts 0 as chunk length which indicate 1 group record */
    4410              13 :   int2store(chunk0_header + header_length - 2, 0);
    4411                 : }
    4412                 : 
    4413                 : 
    4414                 : /*
    4415                 :   Increase number of writers for this buffer
    4416                 : 
    4417                 :   SYNOPSIS
    4418                 :     translog_buffer_increase_writers()
    4419                 :     buffer               target buffer
    4420                 : */
    4421                 : 
    4422                 : static inline void
    4423                 : translog_buffer_increase_writers(struct st_translog_buffer *buffer)
    4424               4 : {
    4425               4 :   DBUG_ENTER("translog_buffer_increase_writers");
    4426               4 :   translog_buffer_lock_assert_owner(buffer);
    4427               4 :   buffer->copy_to_buffer_in_progress++;
    4428               4 :   DBUG_PRINT("info", ("copy_to_buffer_in_progress. Buffer #%u  0x%lx  progress: %d",
    4429                 :                       (uint) buffer->buffer_no, (ulong) buffer,
    4430                 :                       buffer->copy_to_buffer_in_progress));
    4431               4 :   DBUG_VOID_RETURN;
    4432                 : }
    4433                 : 
    4434                 : 
    4435                 : /*
    4436                 :   Decrease number of writers for this buffer
    4437                 : 
    4438                 :   SYNOPSIS
    4439                 :     translog_buffer_decrease_writers()
    4440                 :     buffer               target buffer
    4441                 : */
    4442                 : 
    4443                 : static void translog_buffer_decrease_writers(struct st_translog_buffer *buffer)
    4444               4 : {
    4445               4 :   DBUG_ENTER("translog_buffer_decrease_writers");
    4446               4 :   translog_buffer_lock_assert_owner(buffer);
    4447               4 :   buffer->copy_to_buffer_in_progress--;
    4448               4 :   DBUG_PRINT("info",
    4449                 :              ("copy_to_buffer_in_progress. Buffer #%u  0x%lx  progress: %d",
    4450                 :               (uint) buffer->buffer_no, (ulong) buffer,
    4451                 :               buffer->copy_to_buffer_in_progress));
    4452               4 :   if (buffer->copy_to_buffer_in_progress == 0)
    4453               4 :     pthread_cond_broadcast(&buffer->waiting_filling_buffer);
    4454               4 :   DBUG_VOID_RETURN;
    4455                 : }
    4456                 : 
    4457                 : 
    4458                 : /**
    4459                 :   @brief Skip to the next page for chaser (thread which advanced horizon
    4460                 :   pointer and now feeling the buffer)
    4461                 : 
    4462                 :   @param horizon         \ Pointers on file position and buffer
    4463                 :   @param cursor          /
    4464                 : 
    4465                 :   @retval 1 OK
    4466                 :   @retval 0 Error
    4467                 : */
    4468                 : 
    4469                 : static my_bool translog_chaser_page_next(TRANSLOG_ADDRESS *horizon,
    4470                 :                                          struct st_buffer_cursor *cursor)
    4471               0 : {
    4472                 :   struct st_translog_buffer *buffer_to_flush;
    4473                 :   my_bool rc;
    4474               0 :   DBUG_ENTER("translog_chaser_page_next");
    4475               0 :   DBUG_ASSERT(cursor->chaser);
    4476               0 :   rc= translog_page_next(horizon, cursor, &buffer_to_flush);
    4477               0 :   if (buffer_to_flush != NULL)
    4478                 :   {
    4479               0 :     translog_buffer_lock(buffer_to_flush);
    4480               0 :     translog_buffer_decrease_writers(buffer_to_flush);
    4481               0 :     if (!rc)
    4482               0 :       rc= translog_buffer_flush(buffer_to_flush);
    4483               0 :     translog_buffer_unlock(buffer_to_flush);
    4484                 :   }
    4485               0 :   DBUG_RETURN(rc);
    4486                 : }
    4487                 : 
    4488                 : /*
    4489                 :   Put chunk 2 from new page beginning
    4490                 : 
    4491                 :   SYNOPSIS
    4492                 :     translog_write_variable_record_chunk2_page()
    4493                 :     parts                Descriptor of record source parts
    4494                 :     horizon              \ Pointers on file position and buffer
    4495                 :     cursor               /
    4496                 : 
    4497                 :   RETURN
    4498                 :     0  OK
    4499                 :     1  Error
    4500                 : */
    4501                 : 
    4502                 : static my_bool
    4503                 : translog_write_variable_record_chunk2_page(struct st_translog_parts *parts,
    4504                 :                                            TRANSLOG_ADDRESS *horizon,
    4505                 :                                            struct st_buffer_cursor *cursor)
    4506               0 : {
    4507                 :   uchar chunk2_header[1];
    4508               0 :   DBUG_ENTER("translog_write_variable_record_chunk2_page");
    4509               0 :   chunk2_header[0]= TRANSLOG_CHUNK_NOHDR;
    4510                 : 
    4511               0 :   if (translog_chaser_page_next(horizon, cursor))
    4512               0 :     DBUG_RETURN(1);
    4513                 : 
    4514                 :   /* Puts chunk type */
    4515               0 :   translog_write_data_on_page(horizon, cursor, 1, chunk2_header);
    4516                 :   /* Puts chunk body */
    4517               0 :   translog_write_parts_on_page(horizon, cursor,
    4518                 :                                log_descriptor.page_capacity_chunk_2, parts);
    4519               0 :   DBUG_RETURN(0);
    4520                 : }
    4521                 : 
    4522                 : 
    4523                 : /*
    4524                 :   Put chunk 3 of requested length in the buffer from new page beginning
    4525                 : 
    4526                 :   SYNOPSIS
    4527                 :     translog_write_variable_record_chunk3_page()
    4528                 :     parts                Descriptor of record source parts
    4529                 :     length               Length of this chunk
    4530                 :     horizon              \ Pointers on file position and buffer
    4531                 :     cursor               /
    4532                 : 
    4533                 :   RETURN
    4534                 :     0  OK
    4535                 :     1  Error
    4536                 : */
    4537                 : 
    4538                 : static my_bool
    4539                 : translog_write_variable_record_chunk3_page(struct st_translog_parts *parts,
    4540                 :                                            uint16 length,
    4541                 :                                            TRANSLOG_ADDRESS *horizon,
    4542                 :                                            struct st_buffer_cursor *cursor)
    4543               0 : {
    4544                 :   LEX_CUSTRING *part;
    4545                 :   uchar chunk3_header[1 + 2];
    4546               0 :   DBUG_ENTER("translog_write_variable_record_chunk3_page");
    4547                 : 
    4548               0 :   if (translog_chaser_page_next(horizon, cursor))
    4549               0 :     DBUG_RETURN(1);
    4550                 : 
    4551               0 :   if (length == 0)
    4552                 :   {
    4553                 :     /* It was call to write page header only (no data for chunk 3) */
    4554               0 :     DBUG_PRINT("info", ("It is a call to make page header only"));
    4555               0 :     DBUG_RETURN(0);
    4556                 :   }
    4557                 : 
    4558               0 :   DBUG_ASSERT(parts->current != 0);       /* first part is left for header */
    4559               0 :   part= parts->parts + (--parts->current);
    4560               0 :   parts->total_record_length+= (translog_size_t) (part->length= 1 + 2);
    4561               0 :   part->str= chunk3_header;
    4562                 :   /* Puts chunk type */
    4563               0 :   *chunk3_header= (uchar) (TRANSLOG_CHUNK_LNGTH);
    4564                 :   /* Puts chunk length */
    4565               0 :   int2store(chunk3_header + 1, length);
    4566                 : 
    4567               0 :   translog_write_parts_on_page(horizon, cursor, length + 1 + 2, parts);
    4568               0 :   DBUG_RETURN(0);
    4569                 : }
    4570                 : 
    4571                 : /*
    4572                 :   Move log pointer (horizon) on given number pages starting from next page,
    4573                 :   and given offset on the last page
    4574                 : 
    4575                 :   SYNOPSIS
    4576                 :     translog_advance_pointer()
    4577                 :     pages                Number of full pages starting from the next one
    4578                 :     last_page_data       Plus this data on the last page
    4579                 : 
    4580                 :   RETURN
    4581                 :     0  OK
    4582                 :     1  Error
    4583                 : */
    4584                 : 
    4585                 : static my_bool translog_advance_pointer(int pages, uint16 last_page_data)
    4586               0 : {
    4587                 :   translog_size_t last_page_offset= (log_descriptor.page_overhead +
    4588               0 :                                      last_page_data);
    4589                 :   translog_size_t offset= (TRANSLOG_PAGE_SIZE -
    4590                 :                            log_descriptor.bc.current_page_fill +
    4591               0 :                            pages * TRANSLOG_PAGE_SIZE + last_page_offset);
    4592                 :   translog_size_t buffer_end_offset, file_end_offset, min_offset;
    4593               0 :   DBUG_ENTER("translog_advance_pointer");
    4594               0 :   DBUG_PRINT("enter", ("Pointer:  (%lu, 0x%lx) + %u + %u pages + %u + %u",
    4595                 :                        LSN_IN_PARTS(log_descriptor.horizon),
    4596                 :                        (uint) (TRANSLOG_PAGE_SIZE -
    4597                 :                                log_descriptor.bc.current_page_fill),
    4598                 :                        pages, (uint) log_descriptor.page_overhead,
    4599                 :                        (uint) last_page_data));
    4600               0 :   translog_lock_assert_owner();
    4601                 : 
    4602               0 :   if (pages == -1)
    4603                 :   {
    4604                 :     /*
    4605                 :       It is special case when we advance the pointer on the same page.
    4606                 :       It can happened when we write last part of multi-group record.
    4607                 :     */
    4608               0 :     DBUG_ASSERT(last_page_data + log_descriptor.bc.current_page_fill <=
    4609                 :                 TRANSLOG_PAGE_SIZE);
    4610               0 :     offset= last_page_data;
    4611               0 :     last_page_offset= log_descriptor.bc.current_page_fill + last_page_data;
    4612               0 :     goto end;
    4613                 :   }
    4614               0 :   DBUG_PRINT("info", ("last_page_offset %lu", (ulong) last_page_offset));
    4615               0 :   DBUG_ASSERT(last_page_offset <= TRANSLOG_PAGE_SIZE);
    4616                 : 
    4617                 :   /*
    4618                 :     The loop will be executed 1-3 times. Usually we advance the
    4619                 :     pointer to fill only the current buffer (if we have more then 1/2 of
    4620                 :     buffer free or 2 buffers (rest of current and all next). In case of
    4621                 :     really huge record end where we write last group with "table of
    4622                 :     content" of all groups and ignore buffer borders we can occupy
    4623                 :     3 buffers.
    4624                 :   */
    4625                 :   for (;;)
    4626                 :   {
    4627                 :     uint8 new_buffer_no;
    4628                 :     struct st_translog_buffer *new_buffer;
    4629                 :     struct st_translog_buffer *old_buffer;
    4630               0 :     buffer_end_offset= TRANSLOG_WRITE_BUFFER - log_descriptor.bc.buffer->size;
    4631               0 :     if (likely(log_descriptor.log_file_max_size >=
    4632                 :                LSN_OFFSET(log_descriptor.horizon)))
    4633               0 :       file_end_offset= (log_descriptor.log_file_max_size -
    4634                 :                         LSN_OFFSET(log_descriptor.horizon));
    4635                 :     else
    4636                 :     {
    4637                 :       /*
    4638                 :         We already have written more then current file limit allow,
    4639                 :         So we will finish this page and start new file
    4640                 :       */
    4641               0 :       file_end_offset= (TRANSLOG_PAGE_SIZE -
    4642                 :                         log_descriptor.bc.current_page_fill);
    4643                 :     }
    4644               0 :     DBUG_PRINT("info", ("offset: %lu  buffer_end_offs: %lu, "
    4645                 :                         "file_end_offs:  %lu",
    4646                 :                         (ulong) offset, (ulong) buffer_end_offset,
    4647                 :                         (ulong) file_end_offset));
    4648               0 :     DBUG_PRINT("info", ("Buff #%u %u (0x%lx) offset 0x%lx + size 0x%lx = "
    4649                 :                         "0x%lx (0x%lx)",
    4650                 :                         (uint) log_descriptor.bc.buffer->buffer_no,
    4651                 :                         (uint) log_descriptor.bc.buffer_no,
    4652                 :                         (ulong) log_descriptor.bc.buffer,
    4653                 :                         (ulong) LSN_OFFSET(log_descriptor.bc.buffer->offset),
    4654                 :                         (ulong) log_descriptor.bc.buffer->size,
    4655                 :                         (ulong) (LSN_OFFSET(log_descriptor.bc.buffer->offset) +
    4656                 :                                  log_descriptor.bc.buffer->size),
    4657                 :                         (ulong) LSN_OFFSET(log_descriptor.horizon)));
    4658               0 :     DBUG_ASSERT(LSN_OFFSET(log_descriptor.bc.buffer->offset) +
    4659                 :                 log_descriptor.bc.buffer->size ==
    4660                 :                 LSN_OFFSET(log_descriptor.horizon));
    4661                 : 
    4662               0 :     if (offset <= buffer_end_offset && offset <= file_end_offset)
    4663               0 :       break;
    4664               0 :     old_buffer= log_descriptor.bc.buffer;
    4665               0 :     new_buffer_no= (log_descriptor.bc.buffer_no + 1) % TRANSLOG_BUFFERS_NO;
    4666               0 :     new_buffer= log_descriptor.buffers + new_buffer_no;
    4667                 : 
    4668               0 :     translog_buffer_lock(new_buffer);
    4669                 : #ifndef DBUG_OFF
    4670                 :     {
    4671               0 :       TRANSLOG_ADDRESS offset= new_buffer->offset;
    4672               0 :       TRANSLOG_FILE *file= new_buffer->file;
    4673               0 :       uint8 ver= new_buffer->ver;
    4674               0 :       translog_lock_assert_owner();
    4675                 : #endif
    4676               0 :       translog_wait_for_buffer_free(new_buffer);
    4677                 : #ifndef DBUG_OFF
    4678                 :       /* We keep the handler locked so nobody can start this new buffer */
    4679               0 :       DBUG_ASSERT(offset == new_buffer->offset && new_buffer->file == NULL &&
    4680                 :                   (file == NULL ? ver : (uint8)(ver + 1)) == new_buffer->ver);
    4681                 :     }
    4682                 : #endif
    4683                 : 
    4684               0 :     min_offset= min(buffer_end_offset, file_end_offset);
    4685                 :     /* TODO: check is it ptr or size enough */
    4686               0 :     log_descriptor.bc.buffer->size+= min_offset;
    4687               0 :     log_descriptor.bc.ptr+= min_offset;
    4688               0 :     DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx  chaser: %d  Size: %lu (%lu)",
    4689                 :                         (uint) log_descriptor.bc.buffer->buffer_no,
    4690                 :                         (ulong) log_descriptor.bc.buffer,
    4691                 :                         log_descriptor.bc.chaser,
    4692                 :                         (ulong) log_descriptor.bc.buffer->size,
    4693                 :                         (ulong) (log_descriptor.bc.ptr -log_descriptor.bc.
    4694                 :                                  buffer->buffer)));
    4695               0 :     DBUG_ASSERT((ulong) (log_descriptor.bc.ptr -
    4696                 :                          log_descriptor.bc.buffer->buffer) ==
    4697                 :                 log_descriptor.bc.buffer->size);
    4698               0 :     DBUG_ASSERT(log_descriptor.bc.buffer->buffer_no ==
    4699                 :                 log_descriptor.bc.buffer_no);
    4700               0 :     translog_buffer_increase_writers(log_descriptor.bc.buffer);
    4701                 : 
    4702               0 :     if (file_end_offset <= buffer_end_offset)
    4703                 :     {
    4704               0 :       log_descriptor.horizon+= LSN_ONE_FILE;
    4705               0 :       log_descriptor.horizon= LSN_REPLACE_OFFSET(log_descriptor.horizon,
    4706                 :                                                  TRANSLOG_PAGE_SIZE);
    4707               0 :       DBUG_PRINT("info", ("New file: %lu",
    4708                 :                           (ulong) LSN_FILE_NO(log_descriptor.horizon)));
    4709               0 :       if (translog_create_new_file())
    4710                 :       {
    4711               0 :         DBUG_RETURN(1);
    4712                 :       }
    4713                 :     }
    4714                 :     else
    4715                 :     {
    4716               0 :       DBUG_PRINT("info", ("The same file"));
    4717               0 :       log_descriptor.horizon+= min_offset; /* offset increasing */
    4718                 :     }
    4719               0 :     translog_start_buffer(new_buffer, &log_descriptor.bc, new_buffer_no);
    4720               0 :     old_buffer->next_buffer_offset= new_buffer->offset;
    4721               0 :     new_buffer->prev_buffer_offset= old_buffer->offset;
    4722               0 :     translog_buffer_unlock(old_buffer);
    4723               0 :     offset-= min_offset;
    4724               0 :   }
    4725               0 :   DBUG_PRINT("info", ("drop write_counter"));
    4726               0 :   log_descriptor.bc.write_counter= 0;
    4727               0 :   log_descriptor.bc.previous_offset= 0;
    4728               0 : end:
    4729               0 :   log_descriptor.bc.ptr+= offset;
    4730               0 :   log_descriptor.bc.buffer->size+= offset;
    4731               0 :   translog_buffer_increase_writers(log_descriptor.bc.buffer);
    4732               0 :   log_descriptor.horizon+= offset; /* offset increasing */
    4733               0 :   log_descriptor.bc.current_page_fill= last_page_offset;
    4734               0 :   DBUG_PRINT("info", ("NewP buffer #%u: 0x%lx  chaser: %d  Size: %lu (%lu)  "
    4735                 :                       "offset: %u  last page: %u",
    4736                 :                       (uint) log_descriptor.bc.buffer->buffer_no,
    4737                 :                       (ulong) log_descriptor.bc.buffer,
    4738                 :                       log_descriptor.bc.chaser,
    4739                 :                       (ulong) log_descriptor.bc.buffer->size,
    4740                 :                       (ulong) (log_descriptor.bc.ptr -
    4741                 :                                log_descriptor.bc.buffer->
    4742                 :                                buffer), (uint) offset,
    4743                 :                       (uint) last_page_offset));
    4744               0 :   DBUG_PRINT("info",
    4745                 :              ("pointer moved to: (%lu, 0x%lx)",
    4746                 :               LSN_IN_PARTS(log_descriptor.horizon)));
    4747               0 :   translog_check_cursor(&log_descriptor.bc);
    4748               0 :   log_descriptor.bc.protected= 0;
    4749               0 :   DBUG_RETURN(0);
    4750                 : }
    4751                 : 
    4752                 : 
    4753                 : /*
    4754                 :   Get page rest
    4755                 : 
    4756                 :   SYNOPSIS
    4757                 :     translog_get_current_page_rest()
    4758                 : 
    4759                 :   NOTE loghandler should be locked
    4760                 : 
    4761                 :   RETURN
    4762                 :     number of bytes left on the current page
    4763                 : */
    4764                 : 
    4765                 : static uint translog_get_current_page_rest()
    4766               0 : {
    4767               0 :   return (TRANSLOG_PAGE_SIZE - log_descriptor.bc.current_page_fill);
    4768                 : }
    4769                 : 
    4770                 : 
    4771                 : /*
    4772                 :   Get buffer rest in full pages
    4773                 : 
    4774                 :   SYNOPSIS
    4775                 :      translog_get_current_buffer_rest()
    4776                 : 
    4777                 :   NOTE loghandler should be locked
    4778                 : 
    4779                 :   RETURN
    4780                 :     number of full pages left on the current buffer
    4781                 : */
    4782                 : 
    4783                 : static uint translog_get_current_buffer_rest()
    4784               0 : {
    4785               0 :   return ((log_descriptor.bc.buffer->buffer + TRANSLOG_WRITE_BUFFER -
    4786                 :            log_descriptor.bc.ptr) /
    4787                 :           TRANSLOG_PAGE_SIZE);
    4788                 : }
    4789                 : 
    4790                 : /*
    4791                 :   Calculate possible group size without first (current) page
    4792                 : 
    4793                 :   SYNOPSIS
    4794                 :     translog_get_current_group_size()
    4795                 : 
    4796                 :   NOTE loghandler should be locked
    4797                 : 
    4798                 :   RETURN
    4799                 :     group size without first (current) page
    4800                 : */
    4801                 : 
    4802                 : static translog_size_t translog_get_current_group_size()
    4803               0 : {
    4804                 :   /* buffer rest in full pages */
    4805               0 :   translog_size_t buffer_rest= translog_get_current_buffer_rest();
    4806               0 :   DBUG_ENTER("translog_get_current_group_size");
    4807               0 :   DBUG_PRINT("info", ("buffer_rest in pages: %u", buffer_rest));
    4808                 : 
    4809               0 :   buffer_rest*= log_descriptor.page_capacity_chunk_2;
    4810                 :   /* in case of only half of buffer free we can write this and next buffer */
    4811               0 :   if (buffer_rest < log_descriptor.half_buffer_capacity_chunk_2)
    4812                 :   {
    4813               0 :     DBUG_PRINT("info", ("buffer_rest: %lu -> add %lu",
    4814                 :                         (ulong) buffer_rest,
    4815                 :                         (ulong) log_descriptor.buffer_capacity_chunk_2));
    4816               0 :     buffer_rest+= log_descriptor.buffer_capacity_chunk_2;
    4817                 :   }
    4818                 : 
    4819               0 :   DBUG_PRINT("info", ("buffer_rest: %lu", (ulong) buffer_rest));
    4820                 : 
    4821               0 :   DBUG_RETURN(buffer_rest);
    4822                 : }
    4823                 : 
    4824                 : 
    4825                 : static inline void set_lsn(LSN *lsn, LSN value)
    4826              18 : {
    4827              18 :   DBUG_ENTER("set_lsn");
    4828              18 :   translog_lock_assert_owner();
    4829              18 :   *lsn= value;
    4830                 :   /* we generate LSN so something is not flushed in log */
    4831              18 :   log_descriptor.is_everything_flushed= 0;
    4832              18 :   DBUG_PRINT("info", ("new LSN appeared: (%lu,0x%lx)", LSN_IN_PARTS(value)));
    4833              18 :   DBUG_VOID_RETURN;
    4834                 : }
    4835                 : 
    4836                 : 
    4837                 : /**
    4838                 :    @brief Write variable record in 1 group.
    4839                 : 
    4840                 :    @param  lsn             LSN of the record will be written here
    4841                 :    @param  type            the log record type
    4842                 :    @param  short_trid      Short transaction ID or 0 if it has no sense
    4843                 :    @param  parts           Descriptor of record source parts
    4844                 :    @param  buffer_to_flush Buffer which have to be flushed if it is not 0
    4845                 :    @param  header_length   Calculated header length of chunk type 0
    4846                 :    @param  trn             Transaction structure pointer for hooks by
    4847                 :                            record log type, for short_id
    4848                 :    @param  hook_arg        Argument which will be passed to pre-write and
    4849                 :                            in-write hooks of this record.
    4850                 : 
    4851                 :    @note
    4852                 :      We must have a translog_lock() when entering this function
    4853                 :      We must have buffer_to_flush locked (if not null)
    4854                 : 
    4855                 :    @return Operation status
    4856                 :      @retval 0      OK
    4857                 :      @retval 1      Error
    4858                 : */
    4859                 : 
    4860                 : static my_bool
    4861                 : translog_write_variable_record_1group(LSN *lsn,
    4862                 :                                       enum translog_record_type type,
    4863                 :                                       MARIA_HA *tbl_info,
    4864                 :                                       SHORT_TRANSACTION_ID short_trid,
    4865                 :                                       struct st_translog_parts *parts,
    4866                 :                                       struct st_translog_buffer
    4867                 :                                       *buffer_to_flush, uint16 header_length,
    4868                 :                                       TRN *trn, void *hook_arg)
    4869               0 : {
    4870                 :   TRANSLOG_ADDRESS horizon;
    4871                 :   struct st_buffer_cursor cursor;
    4872               0 :   int rc= 0;
    4873                 :   uint i;
    4874                 :   translog_size_t record_rest, full_pages, first_page;
    4875               0 :   uint additional_chunk3_page= 0;
    4876                 :   uchar chunk0_header[1 + 2 + 5 + 2];
    4877               0 :   DBUG_ENTER("translog_write_variable_record_1group");
    4878               0 :   translog_lock_assert_owner();
    4879               0 :   if (buffer_to_flush)
    4880               0 :     translog_buffer_lock_assert_owner(buffer_to_flush);
    4881                 : 
    4882               0 :   set_lsn(lsn, horizon= log_descriptor.horizon);
    4883               0 :   if (translog_set_lsn_for_files(LSN_FILE_NO(*lsn), LSN_FILE_NO(*lsn),
    4884                 :                                  *lsn, TRUE) ||
    4885                 :       (log_record_type_descriptor[type].inwrite_hook &&
    4886                 :        (*log_record_type_descriptor[type].inwrite_hook)(type, trn, tbl_info,
    4887                 :                                                         lsn, hook_arg)))
    4888                 :   {
    4889               0 :     translog_unlock();
    4890               0 :     DBUG_RETURN(1);
    4891                 :   }
    4892               0 :   cursor= log_descriptor.bc;
    4893               0 :   cursor.chaser= 1;
    4894                 : 
    4895                 :   /* Advance pointer to be able unlock the loghandler */
    4896               0 :   first_page= translog_get_current_page_rest();
    4897               0 :   record_rest= parts->record_length - (first_page - header_length);
    4898               0 :   full_pages= record_rest / log_descriptor.page_capacity_chunk_2;
    4899               0 :   record_rest= (record_rest % log_descriptor.page_capacity_chunk_2);
    4900                 : 
    4901               0 :   if (record_rest + 1 == log_descriptor.page_capacity_chunk_2)
    4902                 :   {
    4903               0 :     DBUG_PRINT("info", ("2 chunks type 3 is needed"));
    4904                 :     /* We will write 2 chunks type 3 at the end of this group */
    4905               0 :     additional_chunk3_page= 1;
    4906               0 :     record_rest= 1;
    4907                 :   }
    4908                 : 
    4909               0 :   DBUG_PRINT("info", ("first_page: %u (%u)  full_pages: %u (%lu)  "
    4910                 :                       "additional: %u (%u)  rest %u = %u",
    4911                 :                       first_page, first_page - header_length,
    4912                 :                       full_pages,
    4913                 :                       (ulong) full_pages *
    4914                 :                       log_descriptor.page_capacity_chunk_2,
    4915                 :                       additional_chunk3_page,
    4916                 :                       additional_chunk3_page *
    4917                 :                       (log_descriptor.page_capacity_chunk_2 - 1),
    4918                 :                       record_rest, parts->record_length));
    4919                 :   /* record_rest + 3 is chunk type 3 overhead + record_rest */
    4920               0 :   rc|= translog_advance_pointer((int)(full_pages + additional_chunk3_page),
    4921                 :                                 (record_rest ? record_rest + 3 : 0));
    4922               0 :   log_descriptor.bc.buffer->last_lsn= *lsn;
    4923               0 :   DBUG_PRINT("info", ("last_lsn set to (%lu,0x%lx)  buffer: 0x%lx",
    4924                 :                       LSN_IN_PARTS(log_descriptor.bc.buffer->last_lsn),
    4925                 :                       (ulong) log_descriptor.bc.buffer));
    4926                 : 
    4927               0 :   translog_unlock();
    4928                 : 
    4929                 :   /*
    4930                 :      Check if we switched buffer and need process it (current buffer is
    4931                 :      unlocked already => we will not delay other threads
    4932                 :   */
    4933               0 :   if (buffer_to_flush != NULL)
    4934                 :   {
    4935               0 :     if (!rc)
    4936               0 :       rc= translog_buffer_flush(buffer_to_flush);
    4937               0 :     translog_buffer_unlock(buffer_to_flush);
    4938                 :   }
    4939               0 :   if (rc)
    4940               0 :     DBUG_RETURN(1);
    4941                 : 
    4942               0 :   translog_write_variable_record_1group_header(parts, type, short_trid,
    4943                 :                                                header_length, chunk0_header);
    4944                 : 
    4945                 :   /* fill the pages */
    4946               0 :   translog_write_parts_on_page(&horizon, &cursor, first_page, parts);
    4947                 : 
    4948               0 :   DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx)",
    4949                 :                       LSN_IN_PARTS(log_descriptor.horizon),
    4950                 :                       LSN_IN_PARTS(horizon)));
    4951                 : 
    4952               0 :   for (i= 0; i < full_pages; i++)
    4953                 :   {
    4954               0 :     if (translog_write_variable_record_chunk2_page(parts, &horizon, &cursor))
    4955               0 :       DBUG_RETURN(1);
    4956                 : 
    4957               0 :     DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx)",
    4958                 :                         LSN_IN_PARTS(log_descriptor.horizon),
    4959                 :                         LSN_IN_PARTS(horizon)));
    4960                 :   }
    4961                 : 
    4962               0 :   if (additional_chunk3_page)
    4963                 :   {
    4964               0 :     if (translog_write_variable_record_chunk3_page(parts,
    4965                 :                                                    log_descriptor.
    4966                 :                                                    page_capacity_chunk_2 - 2,
    4967                 :                                                    &horizon, &cursor))
    4968               0 :       DBUG_RETURN(1);
    4969               0 :     DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx)",
    4970                 :                         LSN_IN_PARTS(log_descriptor.horizon),
    4971                 :                         LSN_IN_PARTS(horizon)));
    4972               0 :     DBUG_ASSERT(cursor.current_page_fill == TRANSLOG_PAGE_SIZE);
    4973                 :   }
    4974                 : 
    4975               0 :   if (translog_write_variable_record_chunk3_page(parts,
    4976                 :                                                  record_rest,
    4977                 :                                                  &horizon, &cursor))
    4978               0 :     DBUG_RETURN(1);
    4979               0 :     DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx)",
    4980                 :                         (ulong) LSN_FILE_NO(log_descriptor.horizon),
    4981                 :                         (ulong) LSN_OFFSET(log_descriptor.horizon),
    4982                 :                         (ulong) LSN_FILE_NO(horizon),
    4983                 :                         (ulong) LSN_OFFSET(horizon)));
    4984                 : 
    4985               0 :   translog_buffer_lock(cursor.buffer);
    4986               0 :   translog_buffer_decrease_writers(cursor.buffer);
    4987               0 :   translog_buffer_unlock(cursor.buffer);
    4988               0 :   DBUG_RETURN(rc);
    4989                 : }
    4990                 : 
    4991                 : 
    4992                 : /**
    4993                 :    @brief Write variable record in 1 chunk.
    4994                 : 
    4995                 :    @param  lsn             LSN of the record will be written here
    4996                 :    @param  type            the log record type
    4997                 :    @param  short_trid      Short transaction ID or 0 if it has no sense
    4998                 :    @param  parts           Descriptor of record source parts
    4999                 :    @param  buffer_to_flush Buffer which have to be flushed if it is not 0
    5000                 :    @param  header_length   Calculated header length of chunk type 0
    5001                 :    @param  trn             Transaction structure pointer for hooks by
    5002                 :                            record log type, for short_id
    5003                 :    @param  hook_arg        Argument which will be passed to pre-write and
    5004                 :                            in-write hooks of this record.
    5005                 : 
    5006                 :    @note
    5007                 :      We must have a translog_lock() when entering this function
    5008                 :      We must have buffer_to_flush locked (if not null)
    5009                 : 
    5010                 :    @return Operation status
    5011                 :      @retval 0      OK
    5012                 :      @retval 1      Error
    5013                 : */
    5014                 : 
    5015                 : static my_bool
    5016                 : translog_write_variable_record_1chunk(LSN *lsn,
    5017                 :                                       enum translog_record_type type,
    5018                 :                                       MARIA_HA *tbl_info,
    5019                 :                                       SHORT_TRANSACTION_ID short_trid,
    5020                 :                                       struct st_translog_parts *parts,
    5021                 :                                       struct st_translog_buffer
    5022                 :                                       *buffer_to_flush, uint16 header_length,
    5023                 :                                       TRN *trn, void *hook_arg)
    5024              13 : {
    5025                 :   int rc;
    5026                 :   uchar chunk0_header[1 + 2 + 5 + 2];
    5027              13 :   DBUG_ENTER("translog_write_variable_record_1chunk");
    5028              13 :   translog_lock_assert_owner();
    5029              13 :   if (buffer_to_flush)
    5030               0 :     translog_buffer_lock_assert_owner(buffer_to_flush);
    5031                 : 
    5032              13 :   translog_write_variable_record_1group_header(parts, type, short_trid,
    5033                 :                                                header_length, chunk0_header);
    5034              13 :   set_lsn(lsn, log_descriptor.horizon);
    5035              13 :   if (translog_set_lsn_for_files(LSN_FILE_NO(*lsn), LSN_FILE_NO(*lsn),
    5036                 :                                  *lsn, TRUE) ||
    5037                 :       (log_record_type_descriptor[type].inwrite_hook &&
    5038                 :        (*log_record_type_descriptor[type].inwrite_hook)(type, trn, tbl_info,
    5039                 :                                                         lsn, hook_arg)))
    5040                 :   {
    5041               0 :     translog_unlock();
    5042               0 :     DBUG_RETURN(1);
    5043                 :   }
    5044                 : 
    5045              13 :   rc= translog_write_parts_on_page(&log_descriptor.horizon,
    5046                 :                                    &log_descriptor.bc,
    5047                 :                                    parts->total_record_length, parts);
    5048              13 :   log_descriptor.bc.buffer->last_lsn= *lsn;
    5049              13 :   DBUG_PRINT("info", ("last_lsn set to (%lu,0x%lx)  buffer: 0x%lx",
    5050                 :                       LSN_IN_PARTS(log_descriptor.bc.buffer->last_lsn),
    5051                 :                       (ulong) log_descriptor.bc.buffer));
    5052              13 :   translog_unlock();
    5053                 : 
    5054                 :   /*
    5055                 :      check if we switched buffer and need process it (current buffer is
    5056                 :      unlocked already => we will not delay other threads
    5057                 :   */
    5058              13 :   if (buffer_to_flush != NULL)
    5059                 :   {
    5060               0 :     if (!rc)
    5061               0 :       rc= translog_buffer_flush(buffer_to_flush);
    5062               0 :     translog_buffer_unlock(buffer_to_flush);
    5063                 :   }
    5064                 : 
    5065              13 :   DBUG_RETURN(rc);
    5066                 : }
    5067                 : 
    5068                 : 
    5069                 : /*
    5070                 :   @brief Calculates and write LSN difference (compressed LSN).
    5071                 : 
    5072                 :   @param base_lsn        LSN from which we calculate difference
    5073                 :   @param lsn             LSN for codding
    5074                 :   @param dst             Result will be written to dst[-pack_length] .. dst[-1]
    5075                 : 
    5076                 :   @note To store an LSN in a compact way we will use the following compression:
    5077                 :     If a log record has LSN1, and it contains the LSN2 as a back reference,
    5078                 :     Instead of LSN2 we write LSN1-LSN2, encoded as:
    5079                 :      two bits     the number N (see below)
    5080                 :      14 bits
    5081                 :      N bytes
    5082                 :      That is, LSN is encoded in 2..5 bytes, and the number of bytes minus 2
    5083                 :      is stored in the first two bits.
    5084                 : 
    5085                 :   @note function made to write the result in backward direction with no
    5086                 :   special sense or tricks both directions are equal in complicity
    5087                 : 
    5088                 :   @retval #    pointer on coded LSN
    5089                 : */
    5090                 : 
    5091                 : static uchar *translog_put_LSN_diff(LSN base_lsn, LSN lsn, uchar *dst)
    5092               0 : {
    5093                 :   uint64 diff;
    5094               0 :   DBUG_ENTER("translog_put_LSN_diff");
    5095               0 :   DBUG_PRINT("enter", ("Base: (%lu,0x%lx)  val: (%lu,0x%lx)  dst: 0x%lx",
    5096                 :                        LSN_IN_PARTS(base_lsn), LSN_IN_PARTS(lsn),
    5097                 :                        (ulong) dst));
    5098               0 :   DBUG_ASSERT(base_lsn > lsn);
    5099               0 :   diff= base_lsn - lsn;
    5100               0 :   DBUG_PRINT("info", ("Diff: 0x%llx", (ulonglong) diff));
    5101               0 :   if (diff <= 0x3FFF)
    5102                 :   {
    5103               0 :     dst-= 2;
    5104                 :     /*
    5105                 :       Note we store this high uchar first to ensure that first uchar has
    5106                 :       0 in the 3 upper bits.
    5107                 :     */
    5108               0 :     dst[0]= (uchar)(diff >> 8);
    5109               0 :     dst[1]= (uchar)(diff & 0xFF);
    5110                 :   }
    5111               0 :   else if (diff <= 0x3FFFFFL)
    5112                 :   {
    5113               0 :     dst-= 3;
    5114               0 :     dst[0]= (uchar)(0x40 | (diff >> 16));
    5115               0 :     int2store(dst + 1, diff & 0xFFFF);
    5116                 :   }
    5117               0 :   else if (diff <= 0x3FFFFFFFL)
    5118                 :   {
    5119               0 :     dst-= 4;
    5120               0 :     dst[0]= (uchar)(0x80 | (diff >> 24));
    5121               0 :     int3store(dst + 1, diff & 0xFFFFFFL);
    5122                 :   }
    5123               0 :   else if (diff <= LL(0x3FFFFFFFFF))
    5124                 : 
    5125                 :   {
    5126               0 :     dst-= 5;
    5127               0 :     dst[0]= (uchar)(0xC0 | (diff >> 32));
    5128               0 :     int4store(dst + 1, diff & 0xFFFFFFFFL);
    5129                 :   }
    5130                 :   else
    5131                 :   {
    5132                 :     /*
    5133                 :       It is full LSN after special 1 diff (which is impossible
    5134                 :       in real life)
    5135                 :     */
    5136               0 :     dst-= 2 + LSN_STORE_SIZE;
    5137               0 :     dst[0]= 0;
    5138               0 :     dst[1]= 1;
    5139               0 :     lsn_store(dst + 2, lsn);
    5140                 :   }
    5141               0 :   DBUG_PRINT("info", ("new dst: 0x%lx", (ulong) dst));
    5142               0 :   DBUG_RETURN(dst);
    5143                 : }
    5144                 : 
    5145                 : 
    5146                 : /*
    5147                 :   Get LSN from LSN-difference (compressed LSN)
    5148                 : 
    5149                 :   SYNOPSIS
    5150                 :     translog_get_LSN_from_diff()
    5151                 :     base_lsn             LSN from which we calculate difference
    5152                 :     src                  pointer to coded lsn
    5153                 :     dst                  pointer to buffer where to write 7byte LSN
    5154                 : 
    5155                 :   NOTE:
    5156                 :     To store an LSN in a compact way we will use the following compression:
    5157                 : 
    5158                 :     If a log record has LSN1, and it contains the lSN2 as a back reference,
    5159                 :     Instead of LSN2 we write LSN1-LSN2, encoded as:
    5160                 : 
    5161                 :      two bits     the number N (see below)
    5162                 :      14 bits
    5163                 :      N bytes
    5164                 : 
    5165                 :     That is, LSN is encoded in 2..5 bytes, and the number of bytes minus 2
    5166                 :     is stored in the first two bits.
    5167                 : 
    5168                 :   RETURN
    5169                 :     pointer to buffer after decoded LSN
    5170                 : */
    5171                 : 
    5172                 : static uchar *translog_get_LSN_from_diff(LSN base_lsn, uchar *src, uchar *dst)
    5173               0 : {
    5174                 :   LSN lsn;
    5175                 :   uint32 diff;
    5176                 :   uint32 first_byte;
    5177                 :   uint32 file_no, rec_offset;
    5178                 :   uint8 code;
    5179               0 :   DBUG_ENTER("translog_get_LSN_from_diff");
    5180               0 :   DBUG_PRINT("enter", ("Base: (%lu,0x%lx)  src: 0x%lx  dst 0x%lx",
    5181                 :                        LSN_IN_PARTS(base_lsn), (ulong) src, (ulong) dst));
    5182               0 :   first_byte= *((uint8*) src);
    5183               0 :   code= first_byte >> 6; /* Length is in 2 most significant bits */
    5184               0 :   first_byte&= 0x3F;
    5185               0 :   src++;                                        /* Skip length + encode */
    5186               0 :   file_no= LSN_FILE_NO(base_lsn);               /* Assume relative */
    5187               0 :   DBUG_PRINT("info", ("code: %u  first byte: %lu",
    5188                 :                       (uint) code, (ulong) first_byte));
    5189               0 :   switch (code) {
    5190                 :   case 0:
    5191               0 :     if (first_byte == 0 && *((uint8*)src) == 1)
    5192                 :     {
    5193                 :       /*
    5194                 :         It is full LSN after special 1 diff (which is impossible
    5195                 :         in real life)
    5196                 :       */
    5197               0 :       memcpy(dst, src + 1, LSN_STORE_SIZE);
    5198               0 :       DBUG_PRINT("info", ("Special case of full LSN, new src: 0x%lx",
    5199                 :                           (ulong) (src + 1 + LSN_STORE_SIZE)));
    5200               0 :       DBUG_RETURN(src + 1 + LSN_STORE_SIZE);
    5201                 :     }
    5202               0 :     rec_offset= LSN_OFFSET(base_lsn) - ((first_byte << 8) + *((uint8*)src));
    5203               0 :     break;
    5204                 :   case 1:
    5205               0 :     diff= uint2korr(src);
    5206               0 :     rec_offset= LSN_OFFSET(base_lsn) - ((first_byte << 16) + diff);
    5207               0 :     break;
    5208                 :   case 2:
    5209               0 :     diff= uint3korr(src);
    5210               0 :     rec_offset= LSN_OFFSET(base_lsn) - ((first_byte << 24) + diff);
    5211               0 :     break;
    5212                 :   case 3:
    5213                 :   {
    5214               0 :     ulonglong base_offset= LSN_OFFSET(base_lsn);
    5215               0 :     diff= uint4korr(src);
    5216               0 :     if (diff > LSN_OFFSET(base_lsn))
    5217                 :     {
    5218                 :       /* take 1 from file offset */
    5219               0 :       first_byte++;
    5220               0 :       base_offset+= LL(0x100000000);
    5221                 :     }
    5222               0 :     file_no= LSN_FILE_NO(base_lsn) - first_byte;
    5223               0 :     DBUG_ASSERT(base_offset - diff <= UINT_MAX);
    5224               0 :     rec_offset= (uint32)(base_offset - diff);
    5225               0 :     break;
    5226                 :   }
    5227                 :   default:
    5228               0 :     DBUG_ASSERT(0);
    5229                 :     DBUG_RETURN(NULL);
    5230                 :   }
    5231               0 :   lsn= MAKE_LSN(file_no, rec_offset);
    5232               0 :   src+= code + 1;
    5233               0 :   lsn_store(dst, lsn);
    5234               0 :   DBUG_PRINT("info", ("new src: 0x%lx", (ulong) src));
    5235               0 :   DBUG_RETURN(src);
    5236                 : }
    5237                 : 
    5238                 : 
    5239                 : /**
    5240                 :   @brief Encodes relative LSNs listed in the parameters.
    5241                 : 
    5242                 :   @param parts           Parts list with encoded LSN(s)
    5243                 :   @param base_lsn        LSN which is base for encoding
    5244                 :   @param lsns            number of LSN(s) to encode
    5245                 :   @param compressed_LSNs buffer which can be used for storing compressed LSN(s)
    5246                 : */
    5247                 : 
    5248                 : static void  translog_relative_LSN_encode(struct st_translog_parts *parts,
    5249                 :                                           LSN base_lsn,
    5250                 :                                           uint lsns, uchar *compressed_LSNs)
    5251               0 : {
    5252                 :   LEX_CUSTRING *part;
    5253               0 :   uint lsns_len= lsns * LSN_STORE_SIZE;
    5254                 :   uchar buffer_src[MAX_NUMBER_OF_LSNS_PER_RECORD * LSN_STORE_SIZE];
    5255               0 :   uchar *buffer= buffer_src;
    5256                 :   const uchar *cbuffer;
    5257                 : 
    5258               0 :   DBUG_ENTER("translog_relative_LSN_encode");
    5259                 : 
    5260               0 :   DBUG_ASSERT(parts->current != 0);
    5261               0 :   part= parts->parts + parts->current;
    5262                 : 
    5263                 :   /* collect all LSN(s) in one chunk if it (they) is (are) divided */
    5264               0 :   if (part->length < lsns_len)
    5265                 :   {
    5266               0 :     uint copied= part->length;
    5267                 :     LEX_CUSTRING *next_part;
    5268               0 :     DBUG_PRINT("info", ("Using buffer: 0x%lx", (ulong) compressed_LSNs));
    5269               0 :     memcpy(buffer, part->str, part->length);
    5270               0 :     next_part= parts->parts + parts->current + 1;
    5271                 :     do
    5272                 :     {
    5273               0 :       DBUG_ASSERT(next_part < parts->parts + parts->elements);
    5274               0 :       if ((next_part->length + copied) < lsns_len)
    5275                 :       {
    5276               0 :         memcpy(buffer + copied, next_part->str,
    5277                 :                next_part->length);
    5278               0 :         copied+= next_part->length;
    5279               0 :         next_part->length= 0; next_part->str= 0;
    5280                 :         /* delete_dynamic_element(&parts->parts, parts->current + 1); */
    5281               0 :         next_part++;
    5282               0 :         parts->current++;
    5283               0 :         part= parts->parts + parts->current;
    5284                 :       }
    5285                 :       else
    5286                 :       {
    5287               0 :         uint len= lsns_len - copied;
    5288               0 :         memcpy(buffer + copied, next_part->str, len);
    5289               0 :         copied= lsns_len;
    5290               0 :         next_part->str+= len;
    5291               0 :         next_part->length-= len;
    5292                 :       }
    5293               0 :     } while (copied < lsns_len);
    5294               0 :     cbuffer= buffer;
    5295                 :   }
    5296                 :   else
    5297                 :   {
    5298               0 :     cbuffer= part->str;
    5299               0 :     part->str+= lsns_len;
    5300               0 :     part->length-= lsns_len;
    5301               0 :     parts->current--;
    5302               0 :     part= parts->parts + parts->current;
    5303                 :   }
    5304                 : 
    5305                 :   {
    5306                 :     /* Compress */
    5307                 :     LSN ref;
    5308                 :     int economy;
    5309                 :     const uchar *src_ptr;
    5310                 :     uchar *dst_ptr= compressed_LSNs + (MAX_NUMBER_OF_LSNS_PER_RECORD *
    5311               0 :                                       COMPRESSED_LSN_MAX_STORE_SIZE);
    5312                 :     /*
    5313                 :       We write the result in backward direction with no special sense or
    5314                 :       tricks both directions are equal in complicity
    5315                 :     */
    5316               0 :     for (src_ptr= cbuffer + lsns_len - LSN_STORE_SIZE;
    5317               0 :          src_ptr >= (const uchar*)cbuffer;
    5318               0 :          src_ptr-= LSN_STORE_SIZE)
    5319                 :     {
    5320               0 :       ref= lsn_korr(src_ptr);
    5321               0 :       dst_ptr= translog_put_LSN_diff(base_lsn, ref, dst_ptr);
    5322                 :     }
    5323               0 :     part->length= (uint)((compressed_LSNs +
    5324                 :                           (MAX_NUMBER_OF_LSNS_PER_RECORD *
    5325                 :                            COMPRESSED_LSN_MAX_STORE_SIZE)) -
    5326                 :                          dst_ptr);
    5327               0 :     parts->record_length-= (economy= lsns_len - part->length);
    5328               0 :     DBUG_PRINT("info", ("new length of LSNs: %lu  economy: %d",
    5329                 :                         (ulong)part->length, economy));
    5330               0 :     parts->total_record_length-= economy;
    5331               0 :     part->str= dst_ptr;
    5332                 :   }
    5333               0 :   DBUG_VOID_RETURN;
    5334                 : }
    5335                 : 
    5336                 : 
    5337                 : /**
    5338                 :    @brief Write multi-group variable-size record.
    5339                 : 
    5340                 :    @param  lsn             LSN of the record will be written here
    5341                 :    @param  type            the log record type
    5342                 :    @param  short_trid      Short transaction ID or 0 if it has no sense
    5343                 :    @param  parts           Descriptor of record source parts
    5344                 :    @param  buffer_to_flush Buffer which have to be flushed if it is not 0
    5345                 :    @param  header_length   Header length calculated for 1 group
    5346                 :    @param  buffer_rest     Beginning from which we plan to write in full pages
    5347                 :    @param  trn             Transaction structure pointer for hooks by
    5348                 :                            record log type, for short_id
    5349                 :    @param  hook_arg        Argument which will be passed to pre-write and
    5350                 :                            in-write hooks of this record.
    5351                 : 
    5352                 :    @note
    5353                 :      We must have a translog_lock() when entering this function
    5354                 : 
    5355                 :      We must have buffer_to_flush locked (if not null)
    5356                 :      buffer_to_flush should *NOT* be locked when calling this function.
    5357                 :      (This is note is here as this is different from most other
    5358                 :      translog_write...() functions which require the buffer to be locked)
    5359                 : 
    5360                 :    @return Operation status
    5361                 :      @retval 0      OK
    5362                 :      @retval 1      Error
    5363                 : */
    5364                 : 
    5365                 : static my_bool
    5366                 : translog_write_variable_record_mgroup(LSN *lsn,
    5367                 :                                       enum translog_record_type type,
    5368                 :                                       MARIA_HA *tbl_info,
    5369                 :                                       SHORT_TRANSACTION_ID short_trid,
    5370                 :                                       struct st_translog_parts *parts,
    5371                 :                                       struct st_translog_buffer
    5372                 :                                       *buffer_to_flush,
    5373                 :                                       uint16 header_length,
    5374                 :                                       translog_size_t buffer_rest,
    5375                 :                                       TRN *trn, void *hook_arg)
    5376               0 : {
    5377                 :   TRANSLOG_ADDRESS horizon;
    5378                 :   struct st_buffer_cursor cursor;
    5379               0 :   int rc= 0;
    5380                 :   uint i, chunk2_page, full_pages;
    5381               0 :   uint curr_group= 0;
    5382               0 :   translog_size_t record_rest, first_page, chunk3_pages, chunk0_pages= 1;
    5383               0 :   translog_size_t done= 0;
    5384                 :   struct st_translog_group_descriptor group;
    5385                 :   DYNAMIC_ARRAY groups;
    5386                 :   uint16 chunk3_size;
    5387               0 :   uint16 page_capacity= log_descriptor.page_capacity_chunk_2 + 1;
    5388                 :   uint16 last_page_capacity;
    5389               0 :   my_bool new_page_before_chunk0= 1, first_chunk0= 1;
    5390                 :   uchar chunk0_header[1 + 2 + 5 + 2 + 2], group_desc[7 + 1];
    5391                 :   uchar chunk2_header[1];
    5392               0 :   uint header_fixed_part= header_length + 2;
    5393               0 :   uint groups_per_page= (page_capacity - header_fixed_part) / (7 + 1);
    5394                 :   uint file_of_the_first_group;
    5395                 :   int pages_to_skip;
    5396                 :   struct st_translog_buffer *buffer_of_last_lsn;
    5397               0 :   DBUG_ENTER("translog_write_variable_record_mgroup");
    5398               0 :   translog_lock_assert_owner();
    5399                 : 
    5400               0 :   chunk2_header[0]= TRANSLOG_CHUNK_NOHDR;
    5401                 : 
    5402               0 :   if (my_init_dynamic_array(&groups,
    5403                 :                             sizeof(struct st_translog_group_descriptor),
    5404                 :                             10, 10))
    5405                 :   {
    5406               0 :     translog_unlock();
    5407               0 :     DBUG_PRINT("error", ("init array failed"));
    5408               0 :     DBUG_RETURN(1);
    5409                 :   }
    5410                 : 
    5411               0 :   first_page= translog_get_current_page_rest();
    5412               0 :   record_rest= parts->record_length - (first_page - 1);
    5413               0 :   DBUG_PRINT("info", ("Record Rest: %lu", (ulong) record_rest));
    5414                 : 
    5415               0 :   if (record_rest < buffer_rest)
    5416                 :   {
    5417                 :     /*
    5418                 :       The record (group 1 type) is larger than the free space on the page
    5419                 :       - we need to split it in two. But when we split it in two, the first
    5420                 :       part is big enough to hold all the data of the record (because the
    5421                 :       header of the first part of the split is smaller than the header of
    5422                 :       the record as a whole when it takes only one chunk)
    5423                 :     */
    5424               0 :     DBUG_PRINT("info", ("too many free space because changing header"));
    5425               0 :     buffer_rest-= log_descriptor.page_capacity_chunk_2;
    5426               0 :     DBUG_ASSERT(record_rest >= buffer_rest);
    5427                 :   }
    5428                 : 
    5429               0 :   file_of_the_first_group= LSN_FILE_NO(log_descriptor.horizon);
    5430               0 :   translog_mark_file_unfinished(file_of_the_first_group);
    5431                 :   do
    5432                 :   {
    5433               0 :     group.addr= horizon= log_descriptor.horizon;
    5434               0 :     cursor= log_descriptor.bc;
    5435               0 :     cursor.chaser= 1;
    5436               0 :     if ((full_pages= buffer_rest / log_descriptor.page_capacity_chunk_2) > 255)
    5437                 :     {
    5438                 :       /* sizeof(uint8) == 256 is max number of chunk in multi-chunks group */
    5439               0 :       full_pages= 255;
    5440               0 :       buffer_rest= full_pages * log_descriptor.page_capacity_chunk_2;
    5441                 :     }
    5442                 :     /*
    5443                 :        group chunks =
    5444                 :        full pages + first page (which actually can be full, too).
    5445                 :        But here we assign number of chunks - 1
    5446                 :     */
    5447               0 :     group.num= full_pages;
    5448               0 :     if (insert_dynamic(&groups, (uchar*) &group))
    5449                 :     {
    5450               0 :       DBUG_PRINT("error", ("insert into array failed"));
    5451               0 :       goto err_unlock;
    5452                 :     }
    5453                 : 
    5454               0 :     DBUG_PRINT("info", ("chunk: #%u  first_page: %u (%u)  "
    5455                 :                         "full_pages: %lu (%lu)  "
    5456                 :                         "Left %lu",
    5457                 :                         groups.elements,
    5458                 :                         first_page, first_page - 1,
    5459                 :                         (ulong) full_pages,
    5460                 :                         (ulong) (full_pages *
    5461                 :                                  log_descriptor.page_capacity_chunk_2),
    5462                 :                         (ulong)(parts->record_length - (first_page - 1 +
    5463                 :                                                         buffer_rest) -
    5464                 :                                 done)));
    5465               0 :     rc|= translog_advance_pointer((int)full_pages, 0);
    5466                 : 
    5467               0 :     translog_unlock();
    5468                 : 
    5469               0 :     if (buffer_to_flush != NULL)
    5470                 :     {
    5471               0 :       translog_buffer_decrease_writers(buffer_to_flush);
    5472               0 :       if (!rc)
    5473               0 :         rc= translog_buffer_flush(buffer_to_flush);
    5474               0 :       translog_buffer_unlock(buffer_to_flush);
    5475               0 :       buffer_to_flush= NULL;
    5476                 :     }
    5477               0 :     if (rc)
    5478                 :     {
    5479               0 :       DBUG_PRINT("error", ("flush of unlock buffer failed"));
    5480               0 :       goto err;
    5481                 :     }
    5482                 : 
    5483               0 :     translog_write_data_on_page(&horizon, &cursor, 1, chunk2_header);
    5484               0 :     translog_write_parts_on_page(&horizon, &cursor, first_page - 1, parts);
    5485               0 :     DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx)  "
    5486                 :                         "Left  %lu",
    5487                 :                         LSN_IN_PARTS(log_descriptor.horizon),
    5488                 :                         LSN_IN_PARTS(horizon),
    5489                 :                         (ulong) (parts->record_length - (first_page - 1) -
    5490                 :                                  done)));
    5491                 : 
    5492               0 :     for (i= 0; i < full_pages; i++)
    5493                 :     {
    5494               0 :       if (translog_write_variable_record_chunk2_page(parts, &horizon, &cursor))
    5495               0 :         goto err;
    5496                 : 
    5497               0 :       DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  "
    5498                 :                           "local: (%lu,0x%lx)  "
    5499                 :                           "Left: %lu",
    5500                 :                           LSN_IN_PARTS(log_descriptor.horizon),
    5501                 :                           LSN_IN_PARTS(horizon),
    5502                 :                           (ulong) (parts->record_length - (first_page - 1) -
    5503                 :                                    i * log_descriptor.page_capacity_chunk_2 -
    5504                 :                                    done)));
    5505                 :     }
    5506                 : 
    5507               0 :     done+= (first_page - 1 + buffer_rest);
    5508                 : 
    5509               0 :     if (translog_chaser_page_next(&horizon, &cursor))
    5510                 :     {
    5511               0 :       DBUG_PRINT("error", ("flush of unlock buffer failed"));
    5512               0 :       goto err;
    5513                 :     }
    5514               0 :     translog_buffer_lock(cursor.buffer);
    5515               0 :     translog_buffer_decrease_writers(cursor.buffer);
    5516               0 :     translog_buffer_unlock(cursor.buffer);
    5517                 : 
    5518               0 :     translog_lock();
    5519                 : 
    5520                 :     /* Check that we have place for chunk type 2 */
    5521               0 :     first_page= translog_get_current_page_rest();
    5522               0 :     if (first_page <= 1)
    5523                 :     {
    5524               0 :       if (translog_page_next(&log_descriptor.horizon, &log_descriptor.bc,
    5525                 :                              &buffer_to_flush))
    5526               0 :         goto err_unlock;
    5527               0 :       first_page= translog_get_current_page_rest();
    5528                 :     }
    5529               0 :     buffer_rest= translog_get_current_group_size();
    5530               0 :   } while ((translog_size_t)(first_page + buffer_rest) <
    5531               0 :            (translog_size_t)(parts->record_length - done));
    5532                 : 
    5533               0 :   group.addr= horizon= log_descriptor.horizon;
    5534               0 :   cursor= log_descriptor.bc;
    5535               0 :   cursor.chaser= 1;
    5536               0 :   group.num= 0;                       /* 0 because it does not matter */
    5537               0 :   if (insert_dynamic(&groups, (uchar*) &group))
    5538                 :   {
    5539               0 :     DBUG_PRINT("error", ("insert into array failed"));
    5540               0 :     goto err_unlock;
    5541                 :   }
    5542               0 :   record_rest= parts->record_length - done;
    5543               0 :   DBUG_PRINT("info", ("Record rest: %lu", (ulong) record_rest));
    5544               0 :   if (first_page > record_rest + 1)
    5545                 :   {
    5546                 :     /*
    5547                 :       We have not so much data to fill all first page
    5548                 :       (no speaking about full pages)
    5549                 :       so it will be:
    5550                 :       <chunk0 <data>>
    5551                 :       or
    5552                 :       <chunk0>...<chunk0><chunk0 <data>>
    5553                 :       or
    5554                 :       <chunk3 <data>><chunk0>...<chunk0><chunk0 <possible data of 1 byte>>
    5555                 :     */
    5556               0 :     chunk2_page= full_pages= 0;
    5557               0 :     last_page_capacity= first_page;
    5558               0 :     pages_to_skip= -1;
    5559                 :   }
    5560                 :   else
    5561                 :   {
    5562                 :     /*
    5563                 :       We will have:
    5564                 :       <chunk2 <data>>...<chunk2 <data>><chunk0 <data>>
    5565                 :       or
    5566                 :       <chunk2 <data>>...<chunk2 <data>><chunk0>...<chunk0><chunk0 <data>>
    5567                 :       or
    5568                 :       <chunk3 <data>><chunk0>...<chunk0><chunk0 <possible data of 1 byte>>
    5569                 :     */
    5570               0 :     chunk2_page= 1;
    5571               0 :     record_rest-= (first_page - 1);
    5572               0 :     pages_to_skip= full_pages=
    5573                 :       record_rest / log_descriptor.page_capacity_chunk_2;
    5574               0 :     record_rest= (record_rest % log_descriptor.page_capacity_chunk_2);
    5575               0 :     last_page_capacity= page_capacity;
    5576                 :   }
    5577               0 :   chunk3_size= 0;
    5578               0 :   chunk3_pages= 0;
    5579               0 :   if (last_page_capacity > record_rest + 1 && record_rest != 0)
    5580                 :   {
    5581               0 :     if (last_page_capacity >
    5582                 :         record_rest + header_fixed_part + groups.elements * (7 + 1))
    5583                 :     {
    5584                 :       /* 1 record of type 0 */
    5585               0 :       chunk3_pages= 0;
    5586                 :     }
    5587                 :     else
    5588                 :     {
    5589               0 :       pages_to_skip++;
    5590               0 :       chunk3_pages= 1;
    5591               0 :       if (record_rest + 2 == last_page_capacity)
    5592                 :       {
    5593               0 :         chunk3_size= record_rest - 1;
    5594               0 :         record_rest= 1;
    5595                 :       }
    5596                 :       else
    5597                 :       {
    5598               0 :         chunk3_size= record_rest;
    5599               0 :         record_rest= 0;
    5600                 :       }
    5601                 :     }
    5602                 :   }
    5603                 :   /*
    5604                 :      A first non-full page will hold type 0 chunk only if it fit in it with
    5605                 :      all its headers
    5606                 :   */
    5607               0 :   while (page_capacity <
    5608                 :          record_rest + header_fixed_part +
    5609                 :          (groups.elements - groups_per_page * (chunk0_pages - 1)) * (7 + 1))
    5610               0 :     chunk0_pages++;
    5611               0 :   DBUG_PRINT("info", ("chunk0_pages: %u  groups %u  groups per full page: %u  "
    5612                 :                       "Group on last page: %u",
    5613                 :                       chunk0_pages, groups.elements,
    5614                 :                       groups_per_page,
    5615                 :                       (groups.elements -
    5616                 :                        ((page_capacity - header_fixed_part) / (7 + 1)) *
    5617                 :                        (chunk0_pages - 1))));
    5618               0 :   DBUG_PRINT("info", ("first_page: %u  chunk2: %u  full_pages: %u (%lu)  "
    5619                 :                       "chunk3: %u (%u)  rest: %u",
    5620                 :                       first_page,
    5621                 :                       chunk2_page, full_pages,
    5622                 :                       (ulong) full_pages *
    5623                 :                       log_descriptor.page_capacity_chunk_2,
    5624                 :                       chunk3_pages, (uint) chunk3_size, (uint) record_rest));
    5625               0 :   rc= translog_advance_pointer(pages_to_skip + (int)(chunk0_pages - 1),
    5626                 :                                record_rest + header_fixed_part +
    5627                 :                                (groups.elements -
    5628                 :                                 ((page_capacity -
    5629                 :                                   header_fixed_part) / (7 + 1)) *
    5630                 :                                 (chunk0_pages - 1)) * (7 + 1));
    5631               0 :   buffer_of_last_lsn= log_descriptor.bc.buffer;
    5632               0 :   translog_unlock();
    5633                 : 
    5634               0 :   if (buffer_to_flush != NULL)
    5635                 :   {
    5636               0 :     translog_buffer_decrease_writers(buffer_to_flush);
    5637               0 :     if (!rc)
    5638               0 :       rc= translog_buffer_flush(buffer_to_flush);
    5639               0 :     translog_buffer_unlock(buffer_to_flush);
    5640               0 :     buffer_to_flush= NULL;
    5641                 :   }
    5642               0 :   if (rc)
    5643                 :   {
    5644               0 :     DBUG_PRINT("error", ("flush of unlock buffer failed"));
    5645               0 :     goto err;
    5646                 :   }
    5647                 : 
    5648               0 :   if (rc)
    5649               0 :     goto err;
    5650                 : 
    5651               0 :   if (chunk2_page)
    5652                 :   {
    5653               0 :     DBUG_PRINT("info", ("chunk 2 to finish first page"));
    5654               0 :     translog_write_data_on_page(&horizon, &cursor, 1, chunk2_header);
    5655               0 :     translog_write_parts_on_page(&horizon, &cursor, first_page - 1, parts);
    5656               0 :     DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx) "
    5657                 :                         "Left: %lu",
    5658                 :                         LSN_IN_PARTS(log_descriptor.horizon),
    5659                 :                         LSN_IN_PARTS(horizon),
    5660                 :                         (ulong) (parts->record_length - (first_page - 1) -
    5661                 :                                  done)));
    5662                 :   }
    5663               0 :   else if (chunk3_pages)
    5664                 :   {
    5665                 :     uchar chunk3_header[3];
    5666               0 :     DBUG_PRINT("info", ("chunk 3"));
    5667               0 :     DBUG_ASSERT(full_pages == 0);
    5668               0 :     chunk3_pages= 0;
    5669               0 :     chunk3_header[0]= TRANSLOG_CHUNK_LNGTH;
    5670               0 :     int2store(chunk3_header + 1, chunk3_size);
    5671               0 :     translog_write_data_on_page(&horizon, &cursor, 3, chunk3_header);
    5672               0 :     translog_write_parts_on_page(&horizon, &cursor, chunk3_size, parts);
    5673               0 :     DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx) "
    5674                 :                         "Left: %lu",
    5675                 :                         LSN_IN_PARTS(log_descriptor.horizon),
    5676                 :                         LSN_IN_PARTS(horizon),
    5677                 :                         (ulong) (parts->record_length - chunk3_size - done)));
    5678                 :   }
    5679                 :   else
    5680                 :   {
    5681               0 :     DBUG_PRINT("info", ("no new_page_before_chunk0"));
    5682               0 :     new_page_before_chunk0= 0;
    5683                 :   }
    5684                 : 
    5685               0 :   for (i= 0; i < full_pages; i++)
    5686                 :   {
    5687               0 :     DBUG_ASSERT(chunk2_page != 0);
    5688               0 :     if (translog_write_variable_record_chunk2_page(parts, &horizon, &cursor))
    5689               0 :       goto err;
    5690                 : 
    5691               0 :     DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx) "
    5692                 :                         "Left: %lu",
    5693                 :                         LSN_IN_PARTS(log_descriptor.horizon),
    5694                 :                         LSN_IN_PARTS(horizon),
    5695                 :                         (ulong) (parts->record_length - (first_page - 1) -
    5696                 :                                  i * log_descriptor.page_capacity_chunk_2 -
    5697                 :                                  done)));
    5698                 :   }
    5699                 : 
    5700               0 :   if (chunk3_pages &&
    5701                 :       translog_write_variable_record_chunk3_page(parts,
    5702                 :                                                  chunk3_size,
    5703                 :                                                  &horizon, &cursor))
    5704               0 :     goto err;
    5705               0 :   DBUG_PRINT("info", ("absolute horizon: (%lu,0x%lx)  local: (%lu,0x%lx)",
    5706                 :                       LSN_IN_PARTS(log_descriptor.horizon),
    5707                 :                       LSN_IN_PARTS(horizon)));
    5708                 : 
    5709               0 :   *chunk0_header= (uchar) (type | TRANSLOG_CHUNK_LSN);
    5710               0 :   int2store(chunk0_header + 1, short_trid);
    5711               0 :   translog_write_variable_record_1group_code_len(chunk0_header + 3,
    5712                 :                                                  parts->record_length,
    5713                 :                                                  header_length);
    5714                 :   do
    5715                 :   {
    5716                 :     int limit;
    5717               0 :     if (new_page_before_chunk0 &&
    5718                 :         translog_chaser_page_next(&horizon, &cursor))
    5719                 :     {
    5720               0 :       DBUG_PRINT("error", ("flush of unlock buffer failed"));
    5721               0 :       goto err;
    5722                 :     }
    5723               0 :     new_page_before_chunk0= 1;
    5724                 : 
    5725               0 :     if (first_chunk0)
    5726                 :     {
    5727               0 :       first_chunk0= 0;
    5728                 : 
    5729                 :       /*
    5730                 :         We can drop "log_descriptor.is_everything_flushed" earlier when have
    5731                 :         lock on loghandler and assign initial value of "horizon" variable or
    5732                 :         before unlocking loghandler (because we will increase writers
    5733                 :         counter on the buffer and every thread which wanted flush the buffer
    5734                 :         will wait till we finish with it). But IMHO better here take short
    5735                 :         lock and do not bother other threads with waiting.
    5736                 :       */
    5737               0 :       translog_lock();
    5738               0 :       set_lsn(lsn, horizon);
    5739               0 :       buffer_of_last_lsn->last_lsn= *lsn;
    5740               0 :       DBUG_PRINT("info", ("last_lsn set to (%lu,0x%lx)  buffer: 0x%lx",
    5741                 :                           LSN_IN_PARTS(buffer_of_last_lsn->last_lsn),
    5742                 :                           (ulong) buffer_of_last_lsn));
    5743               0 :       if (log_record_type_descriptor[type].inwrite_hook &&
    5744                 :           (*log_record_type_descriptor[type].inwrite_hook) (type, trn,
    5745                 :                                                             tbl_info,
    5746                 :                                                             lsn, hook_arg))
    5747               0 :         goto err_unlock;
    5748               0 :       translog_unlock();
    5749                 :     }
    5750                 : 
    5751                 :     /*
    5752                 :        A first non-full page will hold type 0 chunk only if it fit in it with
    5753                 :        all its headers => the fist page is full or number of groups less then
    5754                 :        possible number of full page.
    5755                 :     */
    5756               0 :     limit= (groups_per_page < groups.elements - curr_group ?
    5757                 :             groups_per_page : groups.elements - curr_group);
    5758               0 :     DBUG_PRINT("info", ("Groups: %u  curr: %u  limit: %u",
    5759                 :                         (uint) groups.elements, (uint) curr_group,
    5760                 :                         (uint) limit));
    5761                 : 
    5762               0 :     if (chunk0_pages == 1)
    5763                 :     {
    5764               0 :       DBUG_PRINT("info", ("chunk_len: 2 + %u * (7+1) + %u = %u",
    5765                 :                           (uint) limit, (uint) record_rest,
    5766                 :                           (uint) (2 + limit * (7 + 1) + record_rest)));
    5767               0 :       int2store(chunk0_header + header_length - 2,
    5768                 :                 2 + limit * (7 + 1) + record_rest);
    5769                 :     }
    5770                 :     else
    5771                 :     {
    5772               0 :       DBUG_PRINT("info", ("chunk_len: 2 + %u * (7+1) = %u",
    5773                 :                           (uint) limit, (uint) (2 + limit * (7 + 1))));
    5774               0 :       int2store(chunk0_header + header_length - 2, 2 + limit * (7 + 1));
    5775                 :     }
    5776               0 :     int2store(chunk0_header + header_length, groups.elements - curr_group);
    5777               0 :     translog_write_data_on_page(&horizon, &cursor, header_fixed_part,
    5778                 :                                 chunk0_header);
    5779               0 :     for (i= curr_group; i < limit + curr_group; i++)
    5780                 :     {
    5781                 :       struct st_translog_group_descriptor *grp_ptr;
    5782               0 :       grp_ptr= dynamic_element(&groups, i,
    5783                 :                                struct st_translog_group_descriptor *);
    5784               0 :       lsn_store(group_desc, grp_ptr->addr);
    5785               0 :       group_desc[7]= grp_ptr->num;
    5786               0 :       translog_write_data_on_page(&horizon, &cursor, (7 + 1), group_desc);
    5787                 :     }
    5788                 : 
    5789               0 :     if (chunk0_pages == 1 && record_rest != 0)
    5790               0 :       translog_write_parts_on_page(&horizon, &cursor, record_rest, parts);
    5791                 : 
    5792               0 :     chunk0_pages--;
    5793               0 :     curr_group+= limit;
    5794                 :     /* put special type to indicate that it is not LSN chunk */
    5795               0 :     *chunk0_header= (uchar) (TRANSLOG_CHUNK_LSN | TRANSLOG_CHUNK_0_CONT);
    5796               0 :   } while (chunk0_pages != 0);
    5797               0 :   translog_buffer_lock(cursor.buffer);
    5798               0 :   translog_buffer_decrease_writers(cursor.buffer);
    5799               0 :   translog_buffer_unlock(cursor.buffer);
    5800               0 :   rc= 0;
    5801                 : 
    5802               0 :   if (translog_set_lsn_for_files(file_of_the_first_group, LSN_FILE_NO(*lsn),
    5803                 :                                  *lsn, FALSE))
    5804               0 :     goto err;
    5805                 : 
    5806               0 :   translog_mark_file_finished(file_of_the_first_group);
    5807                 : 
    5808               0 :   delete_dynamic(&groups);
    5809               0 :   DBUG_RETURN(rc);
    5810                 : 
    5811               0 : err_unlock:
    5812                 : 
    5813               0 :   translog_unlock();
    5814                 : 
    5815               0 : err:
    5816               0 :   if (buffer_to_flush != NULL)
    5817                 :   {
    5818                 :     /* This is to prevent locking buffer forever in case of error */
    5819               0 :     translog_buffer_decrease_writers(buffer_to_flush);
    5820               0 :     if (!rc)
    5821               0 :       rc= translog_buffer_flush(buffer_to_flush);
    5822               0 :     translog_buffer_unlock(buffer_to_flush);
    5823               0 :     buffer_to_flush= NULL;
    5824                 :   }
    5825                 : 
    5826                 : 
    5827               0 :   translog_mark_file_finished(file_of_the_first_group);
    5828                 : 
    5829               0 :   delete_dynamic(&groups);
    5830               0 :   DBUG_RETURN(1);
    5831                 : }
    5832                 : 
    5833                 : 
    5834                 : /**
    5835                 :    @brief Write the variable length log record.
    5836                 : 
    5837                 :    @param  lsn             LSN of the record will be written here
    5838                 :    @param  type            the log record type
    5839                 :    @param  short_trid      Short transaction ID or 0 if it has no sense
    5840                 :    @param  parts           Descriptor of record source parts
    5841                 :    @param  trn             Transaction structure pointer for hooks by
    5842                 :                            record log type, for short_id
    5843                 :    @param  hook_arg        Argument which will be passed to pre-write and
    5844                 :                            in-write hooks of this record.
    5845                 : 
    5846                 :    @return Operation status
    5847                 :      @retval 0      OK
    5848                 :      @retval 1      Error
    5849                 : */
    5850                 : 
    5851                 : static my_bool translog_write_variable_record(LSN *lsn,
    5852                 :                                               enum translog_record_type type,
    5853                 :                                               MARIA_HA *tbl_info,
    5854                 :                                               SHORT_TRANSACTION_ID short_trid,
    5855                 :                                               struct st_translog_parts *parts,
    5856                 :                                               TRN *trn, void *hook_arg)
    5857              13 : {
    5858              13 :   struct st_translog_buffer *buffer_to_flush= NULL;
    5859                 :   uint header_length1= 1 + 2 + 2 +
    5860              13 :     translog_variable_record_length_bytes(parts->record_length);
    5861                 :   ulong buffer_rest;
    5862                 :   uint page_rest;
    5863                 :   /* Max number of such LSNs per record is 2 */
    5864                 :   uchar compressed_LSNs[MAX_NUMBER_OF_LSNS_PER_RECORD *
    5865                 :     COMPRESSED_LSN_MAX_STORE_SIZE];
    5866                 :   my_bool res;
    5867              13 :   DBUG_ENTER("translog_write_variable_record");
    5868                 : 
    5869              13 :   translog_lock();
    5870              13 :   DBUG_PRINT("info", ("horizon: (%lu,0x%lx)",
    5871                 :                       LSN_IN_PARTS(log_descriptor.horizon)));
    5872              13 :   page_rest= TRANSLOG_PAGE_SIZE - log_descriptor.bc.current_page_fill;
    5873              13 :   DBUG_PRINT("info", ("header length: %u  page_rest: %u",
    5874                 :                       header_length1, page_rest));
    5875                 : 
    5876                 :   /*
    5877                 :     header and part which we should read have to fit in one chunk
    5878                 :     TODO: allow to divide readable header
    5879                 :   */
    5880              13 :   if (page_rest <
    5881                 :       (header_length1 + log_record_type_descriptor[type].read_header_len))
    5882                 :   {
    5883               0 :     DBUG_PRINT("info",
    5884                 :                ("Next page, size: %u  header: %u + %u",
    5885                 :                 log_descriptor.bc.current_page_fill,
    5886                 :                 header_length1,
    5887                 :                 log_record_type_descriptor[type].read_header_len));
    5888               0 :     translog_page_next(&log_descriptor.horizon, &log_descriptor.bc,
    5889                 :                        &buffer_to_flush);
    5890                 :     /* Chunk 2 header is 1 byte, so full page capacity will be one uchar more */
    5891               0 :     page_rest= log_descriptor.page_capacity_chunk_2 + 1;
    5892               0 :     DBUG_PRINT("info", ("page_rest: %u", page_rest));
    5893                 :   }
    5894                 : 
    5895                 :   /*
    5896                 :      To minimize compressed size we will compress always relative to
    5897                 :      very first chunk address (log_descriptor.horizon for now)
    5898                 :   */
    5899              13 :   if (log_record_type_descriptor[type].compressed_LSN > 0)
    5900                 :   {
    5901               0 :     translog_relative_LSN_encode(parts, log_descriptor.horizon,
    5902                 :                                  log_record_type_descriptor[type].
    5903                 :                                  compressed_LSN, compressed_LSNs);
    5904                 :     /* recalculate header length after compression */
    5905               0 :     header_length1= 1 + 2 + 2 +
    5906                 :       translog_variable_record_length_bytes(parts->record_length);
    5907               0 :     DBUG_PRINT("info", ("after compressing LSN(s) header length: %u  "
    5908                 :                         "record length: %lu",
    5909                 :                         header_length1, (ulong)parts->record_length));
    5910                 :   }
    5911                 : 
    5912                 :   /* TODO: check space on current page for header + few bytes */
    5913              13 :   if (page_rest >= parts->record_length + header_length1)
    5914                 :   {
    5915                 :     /* following function makes translog_unlock(); */
    5916              13 :     res= translog_write_variable_record_1chunk(lsn, type, tbl_info,
    5917                 :                                                short_trid,
    5918                 :                                                parts, buffer_to_flush,
    5919                 :                                                header_length1, trn, hook_arg);
    5920              13 :     DBUG_RETURN(res);
    5921                 :   }
    5922                 : 
    5923               0 :   buffer_rest= translog_get_current_group_size();
    5924                 : 
    5925               0 :   if (buffer_rest >= parts->record_length + header_length1 - page_rest)
    5926                 :   {
    5927                 :     /* following function makes translog_unlock(); */
    5928               0 :     res= translog_write_variable_record_1group(lsn, type, tbl_info,
    5929                 :                                                short_trid,
    5930                 :                                                parts, buffer_to_flush,
    5931                 :                                                header_length1, trn, hook_arg);
    5932               0 :     DBUG_RETURN(res);
    5933                 :   }
    5934                 :   /* following function makes translog_unlock(); */
    5935               0 :   res= translog_write_variable_record_mgroup(lsn, type, tbl_info,
    5936                 :                                              short_trid,
    5937                 :                                              parts, buffer_to_flush,
    5938                 :                                              header_length1,
    5939                 :                                              buffer_rest, trn, hook_arg);
    5940               0 :   DBUG_RETURN(res);
    5941                 : }
    5942                 : 
    5943                 : 
    5944                 : /**
    5945                 :    @brief Write the fixed and pseudo-fixed log record.
    5946                 : 
    5947                 :    @param  lsn             LSN of the record will be written here
    5948                 :    @param  type            the log record type
    5949                 :    @param  short_trid      Short transaction ID or 0 if it has no sense
    5950                 :    @param  parts           Descriptor of record source parts
    5951                 :    @param  trn             Transaction structure pointer for hooks by
    5952                 :                            record log type, for short_id
    5953                 :    @param  hook_arg        Argument which will be passed to pre-write and
    5954                 :                            in-write hooks of this record.
    5955                 : 
    5956                 :    @return Operation status
    5957                 :      @retval 0      OK
    5958                 :      @retval 1      Error
    5959                 : */
    5960                 : 
    5961                 : static my_bool translog_write_fixed_record(LSN *lsn,
    5962                 :                                            enum translog_record_type type,
    5963                 :                                            MARIA_HA *tbl_info,
    5964                 :                                            SHORT_TRANSACTION_ID short_trid,
    5965                 :                                            struct st_translog_parts *parts,
    5966                 :                                            TRN *trn, void *hook_arg)
    5967               5 : {
    5968               5 :   struct st_translog_buffer *buffer_to_flush= NULL;
    5969                 :   uchar chunk1_header[1 + 2];
    5970                 :   /* Max number of such LSNs per record is 2 */
    5971                 :   uchar compressed_LSNs[MAX_NUMBER_OF_LSNS_PER_RECORD *
    5972                 :     COMPRESSED_LSN_MAX_STORE_SIZE];
    5973                 :   LEX_CUSTRING *part;
    5974               5 :   int rc= 1;
    5975               5 :   DBUG_ENTER("translog_write_fixed_record");
    5976               5 :   DBUG_ASSERT((log_record_type_descriptor[type].rclass ==
    5977                 :                LOGRECTYPE_FIXEDLENGTH &&
    5978                 :                parts->record_length ==
    5979                 :                log_record_type_descriptor[type].fixed_length) ||
    5980                 :               (log_record_type_descriptor[type].rclass ==
    5981                 :                LOGRECTYPE_PSEUDOFIXEDLENGTH &&
    5982                 :                parts->record_length ==
    5983                 :                log_record_type_descriptor[type].fixed_length));
    5984                 : 
    5985               5 :   translog_lock();
    5986               5 :   DBUG_PRINT("info", ("horizon: (%lu,0x%lx)",
    5987                 :                       LSN_IN_PARTS(log_descriptor.horizon)));
    5988                 : 
    5989               5 :   DBUG_ASSERT(log_descriptor.bc.current_page_fill <= TRANSLOG_PAGE_SIZE);
    5990               5 :   DBUG_PRINT("info",
    5991                 :              ("Page size: %u  record: %u  next cond: %d",
    5992                 :               log_descriptor.bc.current_page_fill,
    5993                 :               (parts->record_length +
    5994                 :                log_record_type_descriptor[type].compressed_LSN * 2 + 3),
    5995                 :               ((((uint) log_descriptor.bc.current_page_fill) +
    5996                 :                 (parts->record_length +
    5997                 :                  log_record_type_descriptor[type].compressed_LSN * 2 + 3)) >
    5998                 :                TRANSLOG_PAGE_SIZE)));
    5999                 :   /*
    6000                 :     check that there is enough place on current page.
    6001                 :     NOTE: compressing may increase page LSN size on two bytes for every LSN
    6002                 :   */
    6003               5 :   if ((((uint) log_descriptor.bc.current_page_fill) +
    6004                 :        (parts->record_length +
    6005                 :         log_record_type_descriptor[type].compressed_LSN * 2 + 3)) >
    6006                 :       TRANSLOG_PAGE_SIZE)
    6007                 :   {
    6008               0 :     DBUG_PRINT("info", ("Next page"));
    6009               0 :     if (translog_page_next(&log_descriptor.horizon, &log_descriptor.bc,
    6010                 :                            &buffer_to_flush))
    6011               0 :       goto err;                                 /* rc == 1 */
    6012               0 :     if (buffer_to_flush)
    6013               0 :       translog_buffer_lock_assert_owner(buffer_to_flush);
    6014                 :   }
    6015                 : 
    6016               5 :   set_lsn(lsn, log_descriptor.horizon);
    6017               5 :   if (translog_set_lsn_for_files(LSN_FILE_NO(*lsn), LSN_FILE_NO(*lsn),
    6018                 :                              *lsn, TRUE) ||
    6019                 :       (log_record_type_descriptor[type].inwrite_hook &&
    6020                 :        (*log_record_type_descriptor[type].inwrite_hook)(type, trn, tbl_info,
    6021                 :                                                         lsn, hook_arg)))
    6022                 :     goto err;
    6023                 : 
    6024                 :   /* compress LSNs */
    6025               5 :   if (log_record_type_descriptor[type].rclass ==
    6026                 :       LOGRECTYPE_PSEUDOFIXEDLENGTH)
    6027                 :   {
    6028               0 :     DBUG_ASSERT(log_record_type_descriptor[type].compressed_LSN > 0);
    6029               0 :     translog_relative_LSN_encode(parts, *lsn,
    6030                 :                                  log_record_type_descriptor[type].
    6031                 :                                  compressed_LSN, compressed_LSNs);
    6032                 :   }
    6033                 : 
    6034                 :   /*
    6035                 :     Write the whole record at once (we know that there is enough place on
    6036                 :     the destination page)
    6037                 :   */
    6038               5 :   DBUG_ASSERT(parts->current != 0);       /* first part is left for header */
    6039               5 :   part= parts->parts + (--parts->current);
    6040               5 :   parts->total_record_length+= (translog_size_t) (part->length= 1 + 2);
    6041               5 :   part->str= chunk1_header;
    6042               5 :   *chunk1_header= (uchar) (type | TRANSLOG_CHUNK_FIXED);
    6043               5 :   int2store(chunk1_header + 1, short_trid);
    6044                 : 
    6045               5 :   rc= translog_write_parts_on_page(&log_descriptor.horizon,
    6046                 :                                    &log_descriptor.bc,
    6047                 :                                    parts->total_record_length, parts);
    6048                 : 
    6049               5 :   log_descriptor.bc.buffer->last_lsn= *lsn;
    6050               5 :   DBUG_PRINT("info", ("last_lsn set to (%lu,0x%lx)  buffer: 0x%lx",
    6051                 :                       LSN_IN_PARTS(log_descriptor.bc.buffer->last_lsn),
    6052                 :                       (ulong) log_descriptor.bc.buffer));
    6053                 : 
    6054               5 : err:
    6055               5 :   translog_unlock();
    6056                 : 
    6057                 :   /*
    6058                 :     check if we switched buffer and need process it (current buffer is
    6059                 :     unlocked already => we will not delay other threads
    6060                 :   */
    6061               5 :   if (buffer_to_flush != NULL)
    6062                 :   {
    6063               0 :     if (!rc)
    6064               0 :       rc= translog_buffer_flush(buffer_to_flush);
    6065               0 :     translog_buffer_unlock(buffer_to_flush);
    6066                 :   }
    6067                 : 
    6068               5 :   DBUG_RETURN(rc);
    6069                 : }
    6070                 : 
    6071                 : 
    6072                 : /**
    6073                 :    @brief Writes the log record
    6074                 : 
    6075                 :    If share has no 2-byte-id yet, gives an id to the share and logs
    6076                 :    LOGREC_FILE_ID. If transaction has not logged LOGREC_LONG_TRANSACTION_ID
    6077                 :    yet, logs it.
    6078                 : 
    6079                 :    @param  lsn             LSN of the record will be written here
    6080                 :    @param  type            the log record type
    6081                 :    @param  trn             Transaction structure pointer for hooks by
    6082                 :                            record log type, for short_id
    6083                 :    @param  tbl_info        MARIA_HA of table or NULL
    6084                 :    @param  rec_len         record length or 0 (count it)
    6085                 :    @param  part_no         number of parts or 0 (count it)
    6086                 :    @param  parts_data      zero ended (in case of number of parts is 0)
    6087                 :                            array of LEX_STRINGs (parts), first
    6088                 :                            TRANSLOG_INTERNAL_PARTS positions in the log
    6089                 :                            should be unused (need for loghandler)
    6090                 :    @param  store_share_id  if tbl_info!=NULL then share's id will
    6091                 :                            automatically be stored in the two first bytes
    6092                 :                            pointed (so pointer is assumed to be !=NULL)
    6093                 :    @param  hook_arg        argument which will be passed to pre-write and
    6094                 :                            in-write hooks of this record.
    6095                 : 
    6096                 :    @return Operation status
    6097                 :      @retval 0      OK
    6098                 :      @retval 1      Error
    6099                 : */
    6100                 : 
    6101                 : my_bool translog_write_record(LSN *lsn,
    6102                 :                               enum translog_record_type type,
    6103                 :                               TRN *trn, MARIA_HA *tbl_info,
    6104                 :                               translog_size_t rec_len,
    6105                 :                               uint part_no,
    6106                 :                               LEX_CUSTRING *parts_data,
    6107                 :                               uchar *store_share_id,
    6108                 :                               void *hook_arg)
    6109              18 : {
    6110                 :   struct st_translog_parts parts;
    6111                 :   LEX_CUSTRING *part;
    6112                 :   int rc;
    6113              18 :   uint short_trid= trn->short_id;
    6114              18 :   DBUG_ENTER("translog_write_record");
    6115              18 :   DBUG_PRINT("enter", ("type: %u (%s)  ShortTrID: %u  rec_len: %lu",
    6116                 :                        (uint) type, log_record_type_descriptor[type].name,
    6117                 :                        (uint) short_trid, (ulong) rec_len));
    6118              18 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    6119                 :               translog_status == TRANSLOG_READONLY);
    6120              18 :   if (unlikely(translog_status != TRANSLOG_OK))
    6121                 :   {
    6122               0 :     DBUG_PRINT("error", ("Transaction log is write protected"));
    6123               0 :     DBUG_RETURN(1);
    6124                 :   }
    6125                 : 
    6126              18 :   if (tbl_info)
    6127                 :   {
    6128               0 :     MARIA_SHARE *share= tbl_info->s;
    6129               0 :     DBUG_ASSERT(share->now_transactional);
    6130               0 :     if (unlikely(share->id == 0))
    6131                 :     {
    6132                 :       /*
    6133                 :         First log write for this MARIA_SHARE; give it a short id.
    6134                 :         When the lock manager is enabled and needs a short id, it should be
    6135                 :         assigned in the lock manager (because row locks will be taken before
    6136                 :         log records are written; for example SELECT FOR UPDATE takes locks but
    6137                 :         writes no log record.
    6138                 :       */
    6139               0 :       if (unlikely(translog_assign_id_to_share(tbl_info, trn)))
    6140               0 :         DBUG_RETURN(1);
    6141                 :     }
    6142               0 :     fileid_store(store_share_id, share->id);
    6143                 :   }
    6144              18 :   if (unlikely(!(trn->first_undo_lsn & TRANSACTION_LOGGED_LONG_ID)))
    6145                 :   {
    6146                 :     LSN dummy_lsn;
    6147                 :     LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 1];
    6148                 :     uchar log_data[6];
    6149               5 :     int6store(log_data, trn->trid);
    6150               5 :     log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
    6151               5 :     log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
    6152               5 :     trn->first_undo_lsn|= TRANSACTION_LOGGED_LONG_ID; /* no recursion */
    6153               5 :     if (unlikely(translog_write_record(&dummy_lsn, LOGREC_LONG_TRANSACTION_ID,
    6154                 :                                        trn, NULL, sizeof(log_data),
    6155                 :                                        sizeof(log_array)/sizeof(log_array[0]),
    6156                 :                                        log_array, NULL, NULL)))
    6157               0 :       DBUG_RETURN(1);
    6158                 :   }
    6159                 : 
    6160              18 :   parts.parts= parts_data;
    6161                 : 
    6162                 :   /* count parts if they are not counted by upper level */
    6163              18 :   if (part_no == 0)
    6164                 :   {
    6165               0 :     for (part_no= TRANSLOG_INTERNAL_PARTS;
    6166               0 :          parts_data[part_no].length != 0;
    6167               0 :          part_no++);
    6168                 :   }
    6169              18 :   parts.elements= part_no;
    6170              18 :   parts.current= TRANSLOG_INTERNAL_PARTS;
    6171                 : 
    6172                 :   /* clear TRANSLOG_INTERNAL_PARTS */
    6173                 :   compile_time_assert(TRANSLOG_INTERNAL_PARTS != 0);
    6174              18 :   parts_data[0].str= 0;
    6175              18 :   parts_data[0].length= 0;
    6176                 : 
    6177                 :   /* count length of the record */
    6178              18 :   if (rec_len == 0)
    6179                 :   {
    6180               0 :     for(part= parts_data + TRANSLOG_INTERNAL_PARTS;\
    6181                 :         part < parts_data + part_no;
    6182               0 :         part++)
    6183                 :     {
    6184               0 :       rec_len+= (translog_size_t) part->length;
    6185                 :     }
    6186                 :   }
    6187              18 :   parts.record_length= rec_len;
    6188                 : 
    6189                 : #ifndef DBUG_OFF
    6190                 :   {
    6191                 :     uint i;
    6192              18 :     uint len= 0;
    6193                 : #ifdef HAVE_purify
    6194                 :     ha_checksum checksum= 0;
    6195                 : #endif
    6196              61 :     for (i= TRANSLOG_INTERNAL_PARTS; i < part_no; i++)
    6197                 :     {
    6198                 : #ifdef HAVE_purify
    6199                 :       /* Find unitialized bytes early */
    6200                 :       checksum+= my_checksum(checksum, parts_data[i].str,
    6201                 :                              parts_data[i].length);
    6202                 : #endif
    6203              43 :       len+= parts_data[i].length;
    6204                 :     }
    6205              18 :     DBUG_ASSERT(len == rec_len);
    6206                 :   }
    6207                 : #endif
    6208                 :   /*
    6209                 :     Start total_record_length from record_length then overhead will
    6210                 :     be add
    6211                 :   */
    6212              18 :   parts.total_record_length= parts.record_length;
    6213              18 :   DBUG_PRINT("info", ("record length: %lu", (ulong) parts.record_length));
    6214                 : 
    6215                 :   /* process this parts */
    6216              18 :   if (!(rc= (log_record_type_descriptor[type].prewrite_hook &&
    6217                 :              (*log_record_type_descriptor[type].prewrite_hook) (type, trn,
    6218                 :                                                                 tbl_info,
    6219                 :                                                                 hook_arg))))
    6220                 :   {
    6221              18 :     switch (log_record_type_descriptor[type].rclass) {
    6222                 :     case LOGRECTYPE_VARIABLE_LENGTH:
    6223              13 :       rc= translog_write_variable_record(lsn, type, tbl_info,
    6224                 :                                          short_trid, &parts, trn, hook_arg);
    6225              13 :       break;
    6226                 :     case LOGRECTYPE_PSEUDOFIXEDLENGTH:
    6227                 :     case LOGRECTYPE_FIXEDLENGTH:
    6228               5 :       rc= translog_write_fixed_record(lsn, type, tbl_info,
    6229                 :                                       short_trid, &parts, trn, hook_arg);
    6230               5 :       break;
    6231                 :     case LOGRECTYPE_NOT_ALLOWED:
    6232                 :     default:
    6233               0 :       DBUG_ASSERT(0);
    6234                 :       rc= 1;
    6235                 :     }
    6236                 :   }
    6237                 : 
    6238              18 :   DBUG_PRINT("info", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(*lsn)));
    6239              18 :   DBUG_RETURN(rc);
    6240                 : }
    6241                 : 
    6242                 : 
    6243                 : /*
    6244                 :   Decode compressed (relative) LSN(s)
    6245                 : 
    6246                 :   SYNOPSIS
    6247                 :    translog_relative_lsn_decode()
    6248                 :    base_lsn              LSN for encoding
    6249                 :    src                   Decode LSN(s) from here
    6250                 :    dst                   Put decoded LSNs here
    6251                 :    lsns                  number of LSN(s)
    6252                 : 
    6253                 :    RETURN
    6254                 :      position in sources after decoded LSN(s)
    6255                 : */
    6256                 : 
    6257                 : static uchar *translog_relative_LSN_decode(LSN base_lsn,
    6258                 :                                           uchar *src, uchar *dst, uint lsns)
    6259               0 : {
    6260                 :   uint i;
    6261               0 :   for (i= 0; i < lsns; i++, dst+= LSN_STORE_SIZE)
    6262                 :   {
    6263               0 :     src= translog_get_LSN_from_diff(base_lsn, src, dst);
    6264                 :   }
    6265               0 :   return src;
    6266                 : }
    6267                 : 
    6268                 : /**
    6269                 :    @brief Get header of fixed/pseudo length record and call hook for
    6270                 :    it processing
    6271                 : 
    6272                 :    @param page            Pointer to the buffer with page where LSN chunk is
    6273                 :                           placed
    6274                 :    @param page_offset     Offset of the first chunk in the page
    6275                 :    @param buff            Buffer to be filled with header data
    6276                 : 
    6277                 :    @return Length of header or operation status
    6278                 :      @retval #  number of bytes in TRANSLOG_HEADER_BUFFER::header where
    6279                 :                 stored decoded part of the header
    6280                 : */
    6281                 : 
    6282                 : static int translog_fixed_length_header(uchar *page,
    6283                 :                                         translog_size_t page_offset,
    6284                 :                                         TRANSLOG_HEADER_BUFFER *buff)
    6285               0 : {
    6286                 :   struct st_log_record_type_descriptor *desc=
    6287               0 :     log_record_type_descriptor + buff->type;
    6288               0 :   uchar *src= page + page_offset + 3;
    6289               0 :   uchar *dst= buff->header;
    6290               0 :   uchar *start= src;
    6291               0 :   int lsns= desc->compressed_LSN;
    6292               0 :   uint length= desc->fixed_length;
    6293               0 :   DBUG_ENTER("translog_fixed_length_header");
    6294                 : 
    6295               0 :   buff->record_length= length;
    6296                 : 
    6297               0 :   if (desc->rclass == LOGRECTYPE_PSEUDOFIXEDLENGTH)
    6298                 :   {
    6299               0 :     DBUG_ASSERT(lsns > 0);
    6300               0 :     src= translog_relative_LSN_decode(buff->lsn, src, dst, lsns);
    6301               0 :     lsns*= LSN_STORE_SIZE;
    6302               0 :     dst+= lsns;
    6303               0 :     length-= lsns;
    6304               0 :     buff->compressed_LSN_economy= (lsns - (int) (src - start));
    6305                 :   }
    6306                 :   else
    6307               0 :     buff->compressed_LSN_economy= 0;
    6308                 : 
    6309               0 :   memcpy(dst, src, length);
    6310               0 :   buff->non_header_data_start_offset= (uint16) (page_offset +
    6311                 :                                                 ((src + length) -
    6312                 :                                                  (page + page_offset)));
    6313               0 :   buff->non_header_data_len= 0;
    6314               0 :   DBUG_RETURN(buff->record_length);
    6315                 : }
    6316                 : 
    6317                 : 
    6318                 : /*
    6319                 :   Free resources used by TRANSLOG_HEADER_BUFFER
    6320                 : 
    6321                 :   SYNOPSIS
    6322                 :     translog_free_record_header();
    6323                 : */
    6324                 : 
    6325                 : void translog_free_record_header(TRANSLOG_HEADER_BUFFER *buff)
    6326               0 : {
    6327               0 :   DBUG_ENTER("translog_free_record_header");
    6328               0 :   if (buff->groups_no != 0)
    6329                 :   {
    6330               0 :     my_free(buff->groups, MYF(0));
    6331               0 :     buff->groups_no= 0;
    6332                 :   }
    6333               0 :   DBUG_VOID_RETURN;
    6334                 : }
    6335                 : 
    6336                 : 
    6337                 : /**
    6338                 :    @brief Returns the current horizon at the end of the current log
    6339                 : 
    6340                 :    @return Horizon
    6341                 :    @retval LSN_ERROR     error
    6342                 :    @retvar #             Horizon
    6343                 : */
    6344                 : 
    6345                 : TRANSLOG_ADDRESS translog_get_horizon()
    6346              26 : {
    6347                 :   TRANSLOG_ADDRESS res;
    6348              26 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    6349                 :               translog_status == TRANSLOG_READONLY);
    6350              26 :   translog_lock();
    6351              26 :   res= log_descriptor.horizon;
    6352              26 :   translog_unlock();
    6353              26 :   return res;
    6354                 : }
    6355                 : 
    6356                 : 
    6357                 : /**
    6358                 :    @brief Returns the current horizon at the end of the current log, caller is
    6359                 :    assumed to already hold the lock
    6360                 : 
    6361                 :    @return Horizon
    6362                 :    @retval LSN_ERROR     error
    6363                 :    @retvar #             Horizon
    6364                 : */
    6365                 : 
    6366                 : TRANSLOG_ADDRESS translog_get_horizon_no_lock()
    6367               0 : {
    6368               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    6369                 :               translog_status == TRANSLOG_READONLY);
    6370               0 :   translog_lock_assert_owner();
    6371               0 :   return log_descriptor.horizon;
    6372                 : }
    6373                 : 
    6374                 : 
    6375                 : /*
    6376                 :   Set last page in the scanner data structure
    6377                 : 
    6378                 :   SYNOPSIS
    6379                 :     translog_scanner_set_last_page()
    6380                 :     scanner              Information about current chunk during scanning
    6381                 : 
    6382                 :   RETURN
    6383                 :     0  OK
    6384                 :     1  Error
    6385                 : */
    6386                 : 
    6387                 : static my_bool translog_scanner_set_last_page(TRANSLOG_SCANNER_DATA *scanner)
    6388               0 : {
    6389                 :   my_bool page_ok;
    6390               0 :   if (LSN_FILE_NO(scanner->page_addr) == LSN_FILE_NO(scanner->horizon))
    6391                 :   {
    6392                 :     /* It is last file => we can easy find last page address by horizon */
    6393               0 :     uint pagegrest= LSN_OFFSET(scanner->horizon) % TRANSLOG_PAGE_SIZE;
    6394               0 :     scanner->last_file_page= (scanner->horizon -
    6395                 :                               (pagegrest ? pagegrest : TRANSLOG_PAGE_SIZE));
    6396               0 :     return (0);
    6397                 :   }
    6398               0 :   scanner->last_file_page= scanner->page_addr;
    6399               0 :   return (translog_get_last_page_addr(&scanner->last_file_page, &page_ok, 0));
    6400                 : }
    6401                 : 
    6402                 : 
    6403                 : /**
    6404                 :   @brief Get page from page cache according to requested method
    6405                 : 
    6406                 :   @param scanner         The scanner data
    6407                 : 
    6408                 :   @return operation status
    6409                 :   @retval 0 OK
    6410                 :   @retval 1 Error
    6411                 : */
    6412                 : 
    6413                 : static my_bool
    6414                 : translog_scanner_get_page(TRANSLOG_SCANNER_DATA *scanner)
    6415               0 : {
    6416                 :   TRANSLOG_VALIDATOR_DATA data;
    6417               0 :   DBUG_ENTER("translog_scanner_get_page");
    6418               0 :   data.addr= &scanner->page_addr;
    6419               0 :   data.was_recovered= 0;
    6420               0 :   DBUG_RETURN((scanner->page=
    6421                 :                translog_get_page(&data, scanner->buffer,
    6422                 :                                  (scanner->use_direct_link ?
    6423                 :                                   &scanner->direct_link :
    6424                 :                                   NULL))) ==
    6425                 :                NULL);
    6426                 : }
    6427                 : 
    6428                 : 
    6429                 : /**
    6430                 :   @brief Initialize reader scanner.
    6431                 : 
    6432                 :   @param lsn             LSN with which it have to be inited
    6433                 :   @param fixed_horizon   true if it is OK do not read records which was written
    6434                 :                          after scanning beginning
    6435                 :   @param scanner         scanner which have to be inited
    6436                 :   @param use_direct      prefer using direct lings from page handler
    6437                 :                          where it is possible.
    6438                 : 
    6439                 :   @note If direct link was used translog_destroy_scanner should be
    6440                 :         called after it using
    6441                 : 
    6442                 :   @return status of the operation
    6443                 :   @retval 0 OK
    6444                 :   @retval 1 Error
    6445                 : */
    6446                 : 
    6447                 : my_bool translog_scanner_init(LSN lsn,
    6448                 :                               my_bool fixed_horizon,
    6449                 :                               TRANSLOG_SCANNER_DATA *scanner,
    6450                 :                               my_bool use_direct)
    6451               0 : {
    6452                 :   TRANSLOG_VALIDATOR_DATA data;
    6453               0 :   DBUG_ENTER("translog_scanner_init");
    6454               0 :   DBUG_PRINT("enter", ("Scanner: 0x%lx  LSN: (%lu,0x%lx)",
    6455                 :                        (ulong) scanner, LSN_IN_PARTS(lsn)));
    6456               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    6457                 :               translog_status == TRANSLOG_READONLY);
    6458                 : 
    6459               0 :   data.addr= &scanner->page_addr;
    6460               0 :   data.was_recovered= 0;
    6461                 : 
    6462               0 :   scanner->page_offset= LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE;
    6463                 : 
    6464               0 :   scanner->fixed_horizon= fixed_horizon;
    6465               0 :   scanner->use_direct_link= use_direct;
    6466               0 :   scanner->direct_link= NULL;
    6467                 : 
    6468               0 :   scanner->horizon= translog_get_horizon();
    6469               0 :   DBUG_PRINT("info", ("horizon: (%lu,0x%lx)", LSN_IN_PARTS(scanner->horizon)));
    6470                 : 
    6471                 :   /* lsn < horizon */
    6472               0 :   DBUG_ASSERT(lsn <= scanner->horizon);
    6473                 : 
    6474               0 :   scanner->page_addr= lsn;
    6475               0 :   scanner->page_addr-= scanner->page_offset; /*decrease offset */
    6476                 : 
    6477               0 :   if (translog_scanner_set_last_page(scanner))
    6478               0 :     DBUG_RETURN(1);
    6479                 : 
    6480               0 :   if (translog_scanner_get_page(scanner))
    6481               0 :     DBUG_RETURN(1);
    6482               0 :   DBUG_RETURN(0);
    6483                 : }
    6484                 : 
    6485                 : 
    6486                 : /**
    6487                 :   @brief Destroy scanner object;
    6488                 : 
    6489                 :   @param scanner         The scanner object to destroy
    6490                 : */
    6491                 : 
    6492                 : void translog_destroy_scanner(TRANSLOG_SCANNER_DATA *scanner)
    6493               0 : {
    6494               0 :   DBUG_ENTER("translog_destroy_scanner");
    6495               0 :   DBUG_PRINT("enter", ("Scanner: 0x%lx", (ulong)scanner));
    6496               0 :   translog_free_link(scanner->direct_link);
    6497               0 :   DBUG_VOID_RETURN;
    6498                 : }
    6499                 : 
    6500                 : 
    6501                 : /*
    6502                 :   Checks End of the Log
    6503                 : 
    6504                 :   SYNOPSIS
    6505                 :     translog_scanner_eol()
    6506                 :     scanner              Information about current chunk during scanning
    6507                 : 
    6508                 :   RETURN
    6509                 :     1  End of the Log
    6510                 :     0  OK
    6511                 : */
    6512                 : 
    6513                 : static my_bool translog_scanner_eol(TRANSLOG_SCANNER_DATA *scanner)
    6514               0 : {
    6515               0 :   DBUG_ENTER("translog_scanner_eol");
    6516               0 :   DBUG_PRINT("enter",
    6517                 :              ("Horizon: (%lu, 0x%lx)  Current: (%lu, 0x%lx+0x%x=0x%lx)",
    6518                 :               LSN_IN_PARTS(scanner->horizon),
    6519                 :               LSN_IN_PARTS(scanner->page_addr),
    6520                 :               (uint) scanner->page_offset,
    6521                 :               (ulong) (LSN_OFFSET(scanner->page_addr) + scanner->page_offset)));
    6522               0 :   if (scanner->horizon > (scanner->page_addr +
    6523                 :                           scanner->page_offset))
    6524                 :   {
    6525               0 :     DBUG_PRINT("info", ("Horizon is not reached"));
    6526               0 :     DBUG_RETURN(0);
    6527                 :   }
    6528               0 :   if (scanner->fixed_horizon)
    6529                 :   {
    6530               0 :     DBUG_PRINT("info", ("Horizon is fixed and reached"));
    6531               0 :     DBUG_RETURN(1);
    6532                 :   }
    6533               0 :   scanner->horizon= translog_get_horizon();
    6534               0 :   DBUG_PRINT("info",
    6535                 :              ("Horizon is re-read, EOL: %d",
    6536                 :               scanner->horizon <= (scanner->page_addr +
    6537                 :                                    scanner->page_offset)));
    6538               0 :   DBUG_RETURN(scanner->horizon <= (scanner->page_addr +
    6539                 :                                    scanner->page_offset));
    6540                 : }
    6541                 : 
    6542                 : 
    6543                 : /**
    6544                 :   @brief Cheks End of the Page
    6545                 : 
    6546                 :   @param scanner         Information about current chunk during scanning
    6547                 : 
    6548                 :   @retval 1  End of the Page
    6549                 :   @retval 0  OK
    6550                 : */
    6551                 : 
    6552                 : static my_bool translog_scanner_eop(TRANSLOG_SCANNER_DATA *scanner)
    6553               0 : {
    6554               0 :   DBUG_ENTER("translog_scanner_eop");
    6555               0 :   DBUG_RETURN(scanner->page_offset >= TRANSLOG_PAGE_SIZE ||
    6556                 :               scanner->page[scanner->page_offset] == TRANSLOG_FILLER);
    6557                 : }
    6558                 : 
    6559                 : 
    6560                 : /**
    6561                 :   @brief Checks End of the File (i.e. we are scanning last page, which do not
    6562                 :     mean end of this page)
    6563                 : 
    6564                 :   @param scanner         Information about current chunk during scanning
    6565                 : 
    6566                 :   @retval 1 End of the File
    6567                 :   @retval 0 OK
    6568                 : */
    6569                 : 
    6570                 : static my_bool translog_scanner_eof(TRANSLOG_SCANNER_DATA *scanner)
    6571               0 : {
    6572               0 :   DBUG_ENTER("translog_scanner_eof");
    6573               0 :   DBUG_ASSERT(LSN_FILE_NO(scanner->page_addr) ==
    6574                 :               LSN_FILE_NO(scanner->last_file_page));
    6575               0 :   DBUG_PRINT("enter", ("curr Page: 0x%lx  last page: 0x%lx  "
    6576                 :                        "normal EOF: %d",
    6577                 :                        (ulong) LSN_OFFSET(scanner->page_addr),
    6578                 :                        (ulong) LSN_OFFSET(scanner->last_file_page),
    6579                 :                        LSN_OFFSET(scanner->page_addr) ==
    6580                 :                        LSN_OFFSET(scanner->last_file_page)));
    6581                 :   /*
    6582                 :      TODO: detect damaged file EOF,
    6583                 :      TODO: issue warning if damaged file EOF detected
    6584                 :   */
    6585               0 :   DBUG_RETURN(scanner->page_addr ==
    6586                 :               scanner->last_file_page);
    6587                 : }
    6588                 : 
    6589                 : /*
    6590                 :   Move scanner to the next chunk
    6591                 : 
    6592                 :   SYNOPSIS
    6593                 :     translog_get_next_chunk()
    6594                 :     scanner              Information about current chunk during scanning
    6595                 : 
    6596                 :   RETURN
    6597                 :     0  OK
    6598                 :     1  Error
    6599                 : */
    6600                 : 
    6601                 : static my_bool
    6602                 : translog_get_next_chunk(TRANSLOG_SCANNER_DATA *scanner)
    6603               0 : {
    6604                 :   uint16 len;
    6605               0 :   DBUG_ENTER("translog_get_next_chunk");
    6606                 : 
    6607               0 :   if (translog_scanner_eop(scanner))
    6608               0 :     len= TRANSLOG_PAGE_SIZE - scanner->page_offset;
    6609               0 :   else if ((len= translog_get_total_chunk_length(scanner->page,
    6610                 :                                                  scanner->page_offset)) == 0)
    6611               0 :     DBUG_RETURN(1);
    6612               0 :   scanner->page_offset+= len;
    6613                 : 
    6614               0 :   if (translog_scanner_eol(scanner))
    6615                 :   {
    6616               0 :     scanner->page= END_OF_LOG;
    6617               0 :     scanner->page_offset= 0;
    6618               0 :     DBUG_RETURN(0);
    6619                 :   }
    6620               0 :   if (translog_scanner_eop(scanner))
    6621                 :   {
    6622                 :     /* before reading next page we should unpin current one if it was pinned */
    6623               0 :     translog_free_link(scanner->direct_link);
    6624               0 :     if (translog_scanner_eof(scanner))
    6625                 :     {
    6626               0 :       DBUG_PRINT("info", ("horizon: (%lu,0x%lx)  pageaddr: (%lu,0x%lx)",
    6627                 :                           LSN_IN_PARTS(scanner->horizon),
    6628                 :                           LSN_IN_PARTS(scanner->page_addr)));
    6629                 :       /* if it is log end it have to be caught before */
    6630               0 :       DBUG_ASSERT(LSN_FILE_NO(scanner->horizon) >
    6631                 :                   LSN_FILE_NO(scanner->page_addr));
    6632               0 :       scanner->page_addr+= LSN_ONE_FILE;
    6633               0 :       scanner->page_addr= LSN_REPLACE_OFFSET(scanner->page_addr,
    6634                 :                                              TRANSLOG_PAGE_SIZE);
    6635               0 :       if (translog_scanner_set_last_page(scanner))
    6636               0 :         DBUG_RETURN(1);
    6637                 :     }
    6638                 :     else
    6639                 :     {
    6640               0 :       scanner->page_addr+= TRANSLOG_PAGE_SIZE; /* offset increased */
    6641                 :     }
    6642                 : 
    6643               0 :     if (translog_scanner_get_page(scanner))
    6644               0 :       DBUG_RETURN(1);
    6645                 : 
    6646               0 :     scanner->page_offset= translog_get_first_chunk_offset(scanner->page);
    6647               0 :     if (translog_scanner_eol(scanner))
    6648                 :     {
    6649               0 :       scanner->page= END_OF_LOG;
    6650               0 :       scanner->page_offset= 0;
    6651               0 :       DBUG_RETURN(0);
    6652                 :     }
    6653               0 :     DBUG_ASSERT(scanner->page[scanner->page_offset] != TRANSLOG_FILLER);
    6654                 :   }
    6655               0 :   DBUG_RETURN(0);
    6656                 : }
    6657                 : 
    6658                 : 
    6659                 : /**
    6660                 :    @brief Get header of variable length record and call hook for it processing
    6661                 : 
    6662                 :    @param page            Pointer to the buffer with page where LSN chunk is
    6663                 :                           placed
    6664                 :    @param page_offset     Offset of the first chunk in the page
    6665                 :    @param buff            Buffer to be filled with header data
    6666                 :    @param scanner         If present should be moved to the header page if
    6667                 :                           it differ from LSN page
    6668                 : 
    6669                 :    @return                Length of header or operation status
    6670                 :      @retval RECHEADER_READ_ERROR  error
    6671                 :      @retval RECHEADER_READ_EOF    End of the log reached during the read
    6672                 :      @retval #                     number of bytes in
    6673                 :                                    TRANSLOG_HEADER_BUFFER::header where
    6674                 :                                    stored decoded part of the header
    6675                 : */
    6676                 : 
    6677                 : static int
    6678                 : translog_variable_length_header(uchar *page, translog_size_t page_offset,
    6679                 :                                 TRANSLOG_HEADER_BUFFER *buff,
    6680                 :                                 TRANSLOG_SCANNER_DATA *scanner)
    6681               0 : {
    6682                 :   struct st_log_record_type_descriptor *desc= (log_record_type_descriptor +
    6683               0 :                                                buff->type);
    6684               0 :   uchar *src= page + page_offset + 1 + 2;
    6685               0 :   uchar *dst= buff->header;
    6686                 :   LSN base_lsn;
    6687               0 :   uint lsns= desc->compressed_LSN;
    6688                 :   uint16 chunk_len;
    6689               0 :   uint16 length= desc->read_header_len;
    6690               0 :   uint16 buffer_length= length;
    6691                 :   uint16 body_len;
    6692                 :   int rc;
    6693                 :   TRANSLOG_SCANNER_DATA internal_scanner;
    6694               0 :   DBUG_ENTER("translog_variable_length_header");
    6695                 : 
    6696               0 :   buff->record_length= translog_variable_record_1group_decode_len(&src);
    6697               0 :   chunk_len= uint2korr(src);
    6698               0 :   DBUG_PRINT("info", ("rec len: %lu  chunk len: %u  length: %u  bufflen: %u",
    6699                 :                       (ulong) buff->record_length, (uint) chunk_len,
    6700                 :                       (uint) length, (uint) buffer_length));
    6701               0 :   if (chunk_len == 0)
    6702                 :   {
    6703                 :     uint16 page_rest;
    6704               0 :     DBUG_PRINT("info", ("1 group"));
    6705               0 :     src+= 2;
    6706               0 :     page_rest= (uint16) (TRANSLOG_PAGE_SIZE - (src - page));
    6707                 : 
    6708               0 :     base_lsn= buff->lsn;
    6709               0 :     body_len= min(page_rest, buff->record_length);
    6710                 :   }
    6711                 :   else
    6712                 :   {
    6713                 :     uint grp_no, curr;
    6714                 :     uint header_to_skip;
    6715                 :     uint16 page_rest;
    6716                 : 
    6717               0 :     DBUG_PRINT("info", ("multi-group"));
    6718               0 :     grp_no= buff->groups_no= uint2korr(src + 2);
    6719               0 :     if (!(buff->groups=
    6720                 :           (TRANSLOG_GROUP*) my_malloc(sizeof(TRANSLOG_GROUP) * grp_no,
    6721                 :                                       MYF(0))))
    6722               0 :       DBUG_RETURN(RECHEADER_READ_ERROR);
    6723               0 :     DBUG_PRINT("info", ("Groups: %u", (uint) grp_no));
    6724               0 :     src+= (2 + 2);
    6725               0 :     page_rest= (uint16) (TRANSLOG_PAGE_SIZE - (src - page));
    6726               0 :     curr= 0;
    6727               0 :     header_to_skip= src - (page + page_offset);
    6728               0 :     buff->chunk0_pages= 0;
    6729                 : 
    6730                 :     for (;;)
    6731                 :     {
    6732               0 :       uint i, read_length= grp_no;
    6733                 : 
    6734               0 :       buff->chunk0_pages++;
    6735               0 :       if (page_rest < grp_no * (7 + 1))
    6736               0 :         read_length= page_rest / (7 + 1);
    6737               0 :       DBUG_PRINT("info", ("Read chunk0 page#%u  read: %u  left: %u  "
    6738                 :                           "start from: %u",
    6739                 :                           buff->chunk0_pages, read_length, grp_no, curr));
    6740               0 :       for (i= 0; i < read_length; i++, curr++)
    6741                 :       {
    6742               0 :         DBUG_ASSERT(curr < buff->groups_no);
    6743               0 :         buff->groups[curr].addr= lsn_korr(src + i * (7 + 1));
    6744               0 :         buff->groups[curr].num= src[i * (7 + 1) + 7];
    6745               0 :         DBUG_PRINT("info", ("group #%u (%lu,0x%lx)  chunks: %u",
    6746                 :                             curr,
    6747                 :                             LSN_IN_PARTS(buff->groups[curr].addr),
    6748                 :                             (uint) buff->groups[curr].num));
    6749                 :       }
    6750               0 :       grp_no-= read_length;
    6751               0 :       if (grp_no == 0)
    6752                 :       {
    6753               0 :         if (scanner)
    6754                 :         {
    6755               0 :           buff->chunk0_data_addr= scanner->page_addr;
    6756                 :           /* offset increased */
    6757               0 :           buff->chunk0_data_addr+= (page_offset + header_to_skip +
    6758                 :                                     read_length * (7 + 1));
    6759                 :         }
    6760                 :         else
    6761                 :         {
    6762               0 :           buff->chunk0_data_addr= buff->lsn;
    6763                 :           /* offset increased */
    6764               0 :           buff->chunk0_data_addr+= (header_to_skip + read_length * (7 + 1));
    6765                 :         }
    6766               0 :         buff->chunk0_data_len= chunk_len - 2 - read_length * (7 + 1);
    6767               0 :         DBUG_PRINT("info", ("Data address: (%lu,0x%lx)  len: %u",
    6768                 :                             LSN_IN_PARTS(buff->chunk0_data_addr),
    6769                 :                             buff->chunk0_data_len));
    6770                 :         break;
    6771                 :       }
    6772               0 :       if (scanner == NULL)
    6773                 :       {
    6774               0 :         DBUG_PRINT("info", ("use internal scanner for header reading"));
    6775               0 :         scanner= &internal_scanner;
    6776               0 :         if (translog_scanner_init(buff->lsn, 1, scanner, 0))
    6777                 :         {
    6778               0 :           rc= RECHEADER_READ_ERROR;
    6779               0 :           goto exit_and_free;
    6780                 :         }
    6781                 :       }
    6782               0 :       if (translog_get_next_chunk(scanner))
    6783                 :       {
    6784               0 :         if (scanner == &internal_scanner)
    6785               0 :           translog_destroy_scanner(scanner);
    6786               0 :         rc= RECHEADER_READ_ERROR;
    6787               0 :         goto exit_and_free;
    6788                 :       }
    6789               0 :       if (scanner->page == END_OF_LOG)
    6790                 :       {
    6791               0 :         if (scanner == &internal_scanner)
    6792               0 :           translog_destroy_scanner(scanner);
    6793               0 :         rc= RECHEADER_READ_EOF;
    6794               0 :         goto exit_and_free;
    6795                 :       }
    6796               0 :       page= scanner->page;
    6797               0 :       page_offset= scanner->page_offset;
    6798               0 :       src= page + page_offset + header_to_skip;
    6799               0 :       chunk_len= uint2korr(src - 2 - 2);
    6800               0 :       DBUG_PRINT("info", ("Chunk len: %u", (uint) chunk_len));
    6801               0 :       page_rest= (uint16) (TRANSLOG_PAGE_SIZE - (src - page));
    6802               0 :     }
    6803                 : 
    6804               0 :     if (scanner == NULL)
    6805                 :     {
    6806               0 :       DBUG_PRINT("info", ("use internal scanner"));
    6807               0 :       scanner= &internal_scanner;
    6808                 :     }
    6809                 :     else
    6810                 :     {
    6811               0 :       translog_destroy_scanner(scanner);
    6812                 :     }
    6813               0 :     base_lsn= buff->groups[0].addr;
    6814               0 :     translog_scanner_init(base_lsn, 1, scanner, scanner == &internal_scanner);
    6815                 :     /* first group chunk is always chunk type 2 */
    6816               0 :     page= scanner->page;
    6817               0 :     page_offset= scanner->page_offset;
    6818               0 :     src= page + page_offset + 1;
    6819               0 :     page_rest= (uint16) (TRANSLOG_PAGE_SIZE - (src - page));
    6820               0 :     body_len= page_rest;
    6821               0 :     if (scanner == &internal_scanner)
    6822               0 :       translog_destroy_scanner(scanner);
    6823                 :   }
    6824               0 :   if (lsns)
    6825                 :   {
    6826               0 :     uchar *start= src;
    6827               0 :     src= translog_relative_LSN_decode(base_lsn, src, dst, lsns);
    6828               0 :     lsns*= LSN_STORE_SIZE;
    6829               0 :     dst+= lsns;
    6830               0 :     length-= lsns;
    6831               0 :     buff->record_length+= (buff->compressed_LSN_economy=
    6832                 :                            (int) (lsns - (src - start)));
    6833               0 :     DBUG_PRINT("info", ("lsns: %u  length: %u  economy: %d  new length: %lu",
    6834                 :                         lsns / LSN_STORE_SIZE, (uint) length,
    6835                 :                         (int) buff->compressed_LSN_economy,
    6836                 :                         (ulong) buff->record_length));
    6837               0 :     body_len-= (uint16) (src - start);
    6838                 :   }
    6839                 :   else
    6840               0 :     buff->compressed_LSN_economy= 0;
    6841                 : 
    6842               0 :   DBUG_ASSERT(body_len >= length);
    6843               0 :   body_len-= length;
    6844               0 :   memcpy(dst, src, length);
    6845               0 :   buff->non_header_data_start_offset= (uint16) (src + length - page);
    6846               0 :   buff->non_header_data_len= body_len;
    6847               0 :   DBUG_PRINT("info", ("non_header_data_start_offset: %u  len: %u  buffer: %u",
    6848                 :                       buff->non_header_data_start_offset,
    6849                 :                       buff->non_header_data_len, buffer_length));
    6850               0 :   DBUG_RETURN(buffer_length);
    6851                 : 
    6852               0 : exit_and_free:
    6853               0 :   my_free(buff->groups, MYF(0));
    6854               0 :   buff->groups_no= 0; /* prevent try to use of buff->groups */
    6855               0 :   DBUG_RETURN(rc);
    6856                 : }
    6857                 : 
    6858                 : 
    6859                 : /**
    6860                 :    @brief Read record header from the given buffer
    6861                 : 
    6862                 :    @param page            page content buffer
    6863                 :    @param page_offset     offset of the chunk in the page
    6864                 :    @param buff            destination buffer
    6865                 :    @param scanner         If this is set the scanner will be moved to the
    6866                 :                           record header page (differ from LSN page in case of
    6867                 :                           multi-group records)
    6868                 : 
    6869                 :    @return Length of header or operation status
    6870                 :      @retval RECHEADER_READ_ERROR  error
    6871                 :      @retval #                     number of bytes in
    6872                 :                                    TRANSLOG_HEADER_BUFFER::header where
    6873                 :                                    stored decoded part of the header
    6874                 : */
    6875                 : 
    6876                 : int translog_read_record_header_from_buffer(uchar *page,
    6877                 :                                             uint16 page_offset,
    6878                 :                                             TRANSLOG_HEADER_BUFFER *buff,
    6879                 :                                             TRANSLOG_SCANNER_DATA *scanner)
    6880               0 : {
    6881                 :   translog_size_t res;
    6882               0 :   DBUG_ENTER("translog_read_record_header_from_buffer");
    6883               0 :   DBUG_ASSERT(translog_is_LSN_chunk(page[page_offset]));
    6884               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    6885                 :               translog_status == TRANSLOG_READONLY);
    6886               0 :   DBUG_PRINT("info", ("page byte: 0x%x  offset: %u",
    6887                 :                       (uint) page[page_offset], (uint) page_offset));
    6888               0 :   buff->type= (page[page_offset] & TRANSLOG_REC_TYPE);
    6889               0 :   buff->short_trid= uint2korr(page + page_offset + 1);
    6890               0 :   DBUG_PRINT("info", ("Type %u, Short TrID %u, LSN (%lu,0x%lx)",
    6891                 :                       (uint) buff->type, (uint)buff->short_trid,
    6892                 :                       LSN_IN_PARTS(buff->lsn)));
    6893                 :   /* Read required bytes from the header and call hook */
    6894               0 :   switch (log_record_type_descriptor[buff->type].rclass) {
    6895                 :   case LOGRECTYPE_VARIABLE_LENGTH:
    6896               0 :     res= translog_variable_length_header(page, page_offset, buff,
    6897                 :                                          scanner);
    6898               0 :     break;
    6899                 :   case LOGRECTYPE_PSEUDOFIXEDLENGTH:
    6900                 :   case LOGRECTYPE_FIXEDLENGTH:
    6901               0 :     res= translog_fixed_length_header(page, page_offset, buff);
    6902               0 :     break;
    6903                 :   default:
    6904               0 :     DBUG_ASSERT(0); /* we read some junk (got no LSN) */
    6905                 :     res= RECHEADER_READ_ERROR;
    6906                 :   }
    6907               0 :   DBUG_RETURN(res);
    6908                 : }
    6909                 : 
    6910                 : 
    6911                 : /**
    6912                 :    @brief Read record header and some fixed part of a record (the part depend
    6913                 :    on record type).
    6914                 : 
    6915                 :    @param lsn             log record serial number (address of the record)
    6916                 :    @param buff            log record header buffer
    6917                 : 
    6918                 :    @note Some type of record can be read completely by this call
    6919                 :    @note "Decoded" header stored in TRANSLOG_HEADER_BUFFER::header (relative
    6920                 :    LSN can be translated to absolute one), some fields can be added (like
    6921                 :    actual header length in the record if the header has variable length)
    6922                 : 
    6923                 :    @return Length of header or operation status
    6924                 :      @retval RECHEADER_READ_ERROR  error
    6925                 :      @retval #                     number of bytes in
    6926                 :                                    TRANSLOG_HEADER_BUFFER::header where
    6927                 :                                    stored decoded part of the header
    6928                 : */
    6929                 : 
    6930                 : int translog_read_record_header(LSN lsn, TRANSLOG_HEADER_BUFFER *buff)
    6931               0 : {
    6932                 :   TRANSLOG_PAGE_SIZE_BUFF psize_buff;
    6933                 :   uchar *page;
    6934               0 :   translog_size_t res, page_offset= LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE;
    6935                 :   PAGECACHE_BLOCK_LINK *direct_link;
    6936                 :   TRANSLOG_ADDRESS addr;
    6937                 :   TRANSLOG_VALIDATOR_DATA data;
    6938               0 :   DBUG_ENTER("translog_read_record_header");
    6939               0 :   DBUG_PRINT("enter", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
    6940               0 :   DBUG_ASSERT(LSN_OFFSET(lsn) % TRANSLOG_PAGE_SIZE != 0);
    6941               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    6942                 :               translog_status == TRANSLOG_READONLY);
    6943                 : 
    6944               0 :   buff->lsn= lsn;
    6945               0 :   buff->groups_no= 0;
    6946               0 :   data.addr= &addr;
    6947               0 :   data.was_recovered= 0;
    6948               0 :   addr= lsn;
    6949               0 :   addr-= page_offset; /* offset decreasing */
    6950               0 :   res= (!(page= translog_get_page(&data, psize_buff.buffer, &direct_link))) ?
    6951                 :     RECHEADER_READ_ERROR :
    6952                 :     translog_read_record_header_from_buffer(page, page_offset, buff, 0);
    6953               0 :   translog_free_link(direct_link);
    6954               0 :   DBUG_RETURN(res);
    6955                 : }
    6956                 : 
    6957                 : 
    6958                 : /**
    6959                 :    @brief Read record header and some fixed part of a record (the part depend
    6960                 :    on record type).
    6961                 : 
    6962                 :    @param scan            scanner position to read
    6963                 :    @param buff            log record header buffer
    6964                 :    @param move_scanner    request to move scanner to the header position
    6965                 : 
    6966                 :    @note Some type of record can be read completely by this call
    6967                 :    @note "Decoded" header stored in TRANSLOG_HEADER_BUFFER::header (relative
    6968                 :    LSN can be translated to absolute one), some fields can be added (like
    6969                 :    actual header length in the record if the header has variable length)
    6970                 : 
    6971                 :    @return Length of header or operation status
    6972                 :      @retval RECHEADER_READ_ERROR  error
    6973                 :      @retval #                     number of bytes in
    6974                 :                                    TRANSLOG_HEADER_BUFFER::header where stored
    6975                 :                                    decoded part of the header
    6976                 : */
    6977                 : 
    6978                 : int translog_read_record_header_scan(TRANSLOG_SCANNER_DATA *scanner,
    6979                 :                                      TRANSLOG_HEADER_BUFFER *buff,
    6980                 :                                      my_bool move_scanner)
    6981               0 : {
    6982                 :   translog_size_t res;
    6983               0 :   DBUG_ENTER("translog_read_record_header_scan");
    6984               0 :   DBUG_PRINT("enter", ("Scanner: Cur: (%lu,0x%lx)  Hrz: (%lu,0x%lx)  "
    6985                 :                        "Lst: (%lu,0x%lx)  Offset: %u(%x)  fixed %d",
    6986                 :                        LSN_IN_PARTS(scanner->page_addr),
    6987                 :                        LSN_IN_PARTS(scanner->horizon),
    6988                 :                        LSN_IN_PARTS(scanner->last_file_page),
    6989                 :                        (uint) scanner->page_offset,
    6990                 :                        (uint) scanner->page_offset, scanner->fixed_horizon));
    6991               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    6992                 :               translog_status == TRANSLOG_READONLY);
    6993               0 :   buff->groups_no= 0;
    6994               0 :   buff->lsn= scanner->page_addr;
    6995               0 :   buff->lsn+= scanner->page_offset; /* offset increasing */
    6996               0 :   res= translog_read_record_header_from_buffer(scanner->page,
    6997                 :                                                scanner->page_offset,
    6998                 :                                                buff,
    6999                 :                                                (move_scanner ?
    7000                 :                                                 scanner : 0));
    7001               0 :   DBUG_RETURN(res);
    7002                 : }
    7003                 : 
    7004                 : 
    7005                 : /**
    7006                 :    @brief Read record header and some fixed part of the next record (the part
    7007                 :    depend on record type).
    7008                 : 
    7009                 :    @param scanner         data for scanning if lsn is NULL scanner data
    7010                 :                           will be used for continue scanning.
    7011                 :                           The scanner can be NULL.
    7012                 : 
    7013                 :    @param buff            log record header buffer
    7014                 : 
    7015                 :    @return Length of header or operation status
    7016                 :      @retval RECHEADER_READ_ERROR  error
    7017                 :      @retval RECHEADER_READ_EOF    EOF
    7018                 :      @retval #                     number of bytes in
    7019                 :                                    TRANSLOG_HEADER_BUFFER::header where
    7020                 :                                    stored decoded part of the header
    7021                 : */
    7022                 : 
    7023                 : int translog_read_next_record_header(TRANSLOG_SCANNER_DATA *scanner,
    7024                 :                                      TRANSLOG_HEADER_BUFFER *buff)
    7025               0 : {
    7026                 :   translog_size_t res;
    7027                 : 
    7028               0 :   DBUG_ENTER("translog_read_next_record_header");
    7029               0 :   buff->groups_no= 0;        /* to be sure that we will free it right */
    7030               0 :   DBUG_PRINT("enter", ("scanner: 0x%lx", (ulong) scanner));
    7031               0 :   DBUG_PRINT("info", ("Scanner: Cur: (%lu,0x%lx)  Hrz: (%lu,0x%lx)  "
    7032                 :                       "Lst: (%lu,0x%lx)  Offset: %u(%x)  fixed: %d",
    7033                 :                       LSN_IN_PARTS(scanner->page_addr),
    7034                 :                       LSN_IN_PARTS(scanner->horizon),
    7035                 :                       LSN_IN_PARTS(scanner->last_file_page),
    7036                 :                       (uint) scanner->page_offset,
    7037                 :                       (uint) scanner->page_offset, scanner->fixed_horizon));
    7038               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    7039                 :               translog_status == TRANSLOG_READONLY);
    7040                 : 
    7041                 :   do
    7042                 :   {
    7043               0 :     if (translog_get_next_chunk(scanner))
    7044               0 :       DBUG_RETURN(RECHEADER_READ_ERROR);
    7045               0 :     if (scanner->page == END_OF_LOG)
    7046                 :     {
    7047               0 :        DBUG_PRINT("info", ("End of file from the scanner"));
    7048                 :        /* Last record was read */
    7049               0 :        buff->lsn= LSN_IMPOSSIBLE;
    7050               0 :        DBUG_RETURN(RECHEADER_READ_EOF);
    7051                 :     }
    7052               0 :     DBUG_PRINT("info", ("Page: (%lu,0x%lx)  offset: %lu  byte: %x",
    7053                 :                         LSN_IN_PARTS(scanner->page_addr),
    7054                 :                         (ulong) scanner->page_offset,
    7055                 :                         (uint) scanner->page[scanner->page_offset]));
    7056                 :   } while (!translog_is_LSN_chunk(scanner->page[scanner->page_offset]) &&
    7057               0 :            scanner->page[scanner->page_offset] != TRANSLOG_FILLER);
    7058                 : 
    7059               0 :   if (scanner->page[scanner->page_offset] == TRANSLOG_FILLER)
    7060                 :   {
    7061               0 :     DBUG_PRINT("info", ("End of file"));
    7062                 :     /* Last record was read */
    7063               0 :     buff->lsn= LSN_IMPOSSIBLE;
    7064                 :     /* Return 'end of log' marker */
    7065               0 :     res= RECHEADER_READ_EOF;
    7066                 :   }
    7067                 :   else
    7068               0 :     res= translog_read_record_header_scan(scanner, buff, 0);
    7069               0 :   DBUG_RETURN(res);
    7070                 : }
    7071                 : 
    7072                 : 
    7073                 : /*
    7074                 :   Moves record data reader to the next chunk and fill the data reader
    7075                 :   information about that chunk.
    7076                 : 
    7077                 :   SYNOPSIS
    7078                 :     translog_record_read_next_chunk()
    7079                 :     data                 data cursor
    7080                 : 
    7081                 :   RETURN
    7082                 :     0  OK
    7083                 :     1  Error
    7084                 : */
    7085                 : 
    7086                 : static my_bool translog_record_read_next_chunk(TRANSLOG_READER_DATA *data)
    7087               0 : {
    7088               0 :   translog_size_t new_current_offset= data->current_offset + data->chunk_size;
    7089                 :   uint16 chunk_header_len, chunk_len;
    7090                 :   uint8 type;
    7091               0 :   DBUG_ENTER("translog_record_read_next_chunk");
    7092                 : 
    7093               0 :   if (data->eor)
    7094                 :   {
    7095               0 :     DBUG_PRINT("info", ("end of the record flag set"));
    7096               0 :     DBUG_RETURN(1);
    7097                 :   }
    7098                 : 
    7099               0 :   if (data->header.groups_no &&
    7100                 :       data->header.groups_no - 1 != data->current_group &&
    7101                 :       data->header.groups[data->current_group].num == data->current_chunk)
    7102                 :   {
    7103                 :     /* Goto next group */
    7104               0 :     data->current_group++;
    7105               0 :     data->current_chunk= 0;
    7106               0 :     DBUG_PRINT("info", ("skip to group: #%u", data->current_group));
    7107               0 :     translog_destroy_scanner(&data->scanner);
    7108               0 :     translog_scanner_init(data->header.groups[data->current_group].addr,
    7109                 :                           1, &data->scanner, 1);
    7110                 :   }
    7111                 :   else
    7112                 :   {
    7113               0 :     data->current_chunk++;
    7114               0 :     if (translog_get_next_chunk(&data->scanner))
    7115               0 :       DBUG_RETURN(1);
    7116               0 :      if (data->scanner.page == END_OF_LOG)
    7117                 :      {
    7118                 :        /*
    7119                 :          Actually it should not happened, but we want to quit nicely in case
    7120                 :          of a truncated log
    7121                 :        */
    7122               0 :        DBUG_RETURN(1);
    7123                 :      }
    7124                 :   }
    7125               0 :   type= data->scanner.page[data->scanner.page_offset] & TRANSLOG_CHUNK_TYPE;
    7126                 : 
    7127               0 :   if (type == TRANSLOG_CHUNK_LSN && data->header.groups_no)
    7128                 :   {
    7129               0 :     DBUG_PRINT("info",
    7130                 :                ("Last chunk: data len: %u  offset: %u  group: %u of %u",
    7131                 :                 data->header.chunk0_data_len, data->scanner.page_offset,
    7132                 :                 data->current_group, data->header.groups_no - 1));
    7133               0 :     DBUG_ASSERT(data->header.groups_no - 1 == data->current_group);
    7134               0 :     DBUG_ASSERT(data->header.lsn ==
    7135                 :                 data->scanner.page_addr + data->scanner.page_offset);
    7136               0 :     translog_destroy_scanner(&data->scanner);
    7137               0 :     translog_scanner_init(data->header.chunk0_data_addr, 1, &data->scanner, 1);
    7138               0 :     data->chunk_size= data->header.chunk0_data_len;
    7139               0 :     data->body_offset= data->scanner.page_offset;
    7140               0 :     data->current_offset= new_current_offset;
    7141               0 :     data->eor= 1;
    7142               0 :     DBUG_RETURN(0);
    7143                 :   }
    7144                 : 
    7145               0 :   if (type == TRANSLOG_CHUNK_LSN || type == TRANSLOG_CHUNK_FIXED)
    7146                 :   {
    7147               0 :     data->eor= 1;
    7148               0 :     DBUG_RETURN(1);                             /* End of record */
    7149                 :   }
    7150                 : 
    7151               0 :   chunk_header_len=
    7152                 :     translog_get_chunk_header_length(data->scanner.page +
    7153                 :                                      data->scanner.page_offset);
    7154               0 :   chunk_len= translog_get_total_chunk_length(data->scanner.page,
    7155                 :                                              data->scanner.page_offset);
    7156               0 :   data->chunk_size= chunk_len - chunk_header_len;
    7157               0 :   data->body_offset= data->scanner.page_offset + chunk_header_len;
    7158               0 :   data->current_offset= new_current_offset;
    7159               0 :   DBUG_PRINT("info", ("grp: %u  chunk: %u  body_offset: %u  chunk_size: %u  "
    7160                 :                       "current_offset: %lu",
    7161                 :                       (uint) data->current_group,
    7162                 :                       (uint) data->current_chunk,
    7163                 :                       (uint) data->body_offset,
    7164                 :                       (uint) data->chunk_size, (ulong) data->current_offset));
    7165               0 :   DBUG_RETURN(0);
    7166                 : }
    7167                 : 
    7168                 : 
    7169                 : /*
    7170                 :   Initialize record reader data from LSN
    7171                 : 
    7172                 :   SYNOPSIS
    7173                 :     translog_init_reader_data()
    7174                 :     lsn                  reference to LSN we should start from
    7175                 :     data                 reader data to initialize
    7176                 : 
    7177                 :   RETURN
    7178                 :     0  OK
    7179                 :     1  Error
    7180                 : */
    7181                 : 
    7182                 : static my_bool translog_init_reader_data(LSN lsn,
    7183                 :                                          TRANSLOG_READER_DATA *data)
    7184               0 : {
    7185                 :   int read_header;
    7186               0 :   DBUG_ENTER("translog_init_reader_data");
    7187               0 :   if (translog_scanner_init(lsn, 1, &data->scanner, 1) ||
    7188                 :       ((read_header=
    7189                 :         translog_read_record_header_scan(&data->scanner, &data->header, 1))
    7190                 :        == RECHEADER_READ_ERROR))
    7191               0 :     DBUG_RETURN(1);
    7192               0 :   data->read_header= read_header;
    7193               0 :   data->body_offset= data->header.non_header_data_start_offset;
    7194               0 :   data->chunk_size= data->header.non_header_data_len;
    7195               0 :   data->current_offset= data->read_header;
    7196               0 :   data->current_group= 0;
    7197               0 :   data->current_chunk= 0;
    7198               0 :   data->eor= 0;
    7199               0 :   DBUG_PRINT("info", ("read_header: %u  "
    7200                 :                       "body_offset: %u  chunk_size: %u  current_offset: %lu",
    7201                 :                       (uint) data->read_header,
    7202                 :                       (uint) data->body_offset,
    7203                 :                       (uint) data->chunk_size, (ulong) data->current_offset));
    7204               0 :   DBUG_RETURN(0);
    7205                 : }
    7206                 : 
    7207                 : 
    7208                 : /**
    7209                 :   @brief Destroy reader data object
    7210                 : */
    7211                 : 
    7212                 : static void translog_destroy_reader_data(TRANSLOG_READER_DATA *data)
    7213               0 : {
    7214               0 :   translog_destroy_scanner(&data->scanner);
    7215               0 :   translog_free_record_header(&data->header);
    7216                 : }
    7217                 : 
    7218                 : 
    7219                 : /*
    7220                 :   Read a part of the record.
    7221                 : 
    7222                 :   SYNOPSIS
    7223                 :     translog_read_record_header()
    7224                 :     lsn                  log record serial number (address of the record)
    7225                 :     offset               From the beginning of the record beginning (read
    7226                 :                          by translog_read_record_header).
    7227                 :     length               Length of record part which have to be read.
    7228                 :     buffer               Buffer where to read the record part (have to be at
    7229                 :                          least 'length' bytes length)
    7230                 : 
    7231                 :   RETURN
    7232                 :     length of data actually read
    7233                 : */
    7234                 : 
    7235                 : translog_size_t translog_read_record(LSN lsn,
    7236                 :                                      translog_size_t offset,
    7237                 :                                      translog_size_t length,
    7238                 :                                      uchar *buffer,
    7239                 :                                      TRANSLOG_READER_DATA *data)
    7240               0 : {
    7241               0 :   translog_size_t requested_length= length;
    7242               0 :   translog_size_t end= offset + length;
    7243                 :   TRANSLOG_READER_DATA internal_data;
    7244               0 :   DBUG_ENTER("translog_read_record");
    7245               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    7246                 :               translog_status == TRANSLOG_READONLY);
    7247                 : 
    7248               0 :   if (data == NULL)
    7249                 :   {
    7250               0 :     DBUG_ASSERT(lsn != LSN_IMPOSSIBLE);
    7251               0 :     data= &internal_data;
    7252                 :   }
    7253               0 :   if (lsn ||
    7254                 :       (offset < data->current_offset &&
    7255                 :        !(offset < data->read_header && offset + length < data->read_header)))
    7256                 :   {
    7257               0 :     if (translog_init_reader_data(lsn, data))
    7258               0 :       DBUG_RETURN(0);
    7259                 :   }
    7260               0 :   DBUG_PRINT("info", ("Offset: %lu  length: %lu  "
    7261                 :                       "Scanner: Cur: (%lu,0x%lx)  Hrz: (%lu,0x%lx)  "
    7262                 :                       "Lst: (%lu,0x%lx)  Offset: %u(%x)  fixed: %d",
    7263                 :                       (ulong) offset, (ulong) length,
    7264                 :                       LSN_IN_PARTS(data->scanner.page_addr),
    7265                 :                       LSN_IN_PARTS(data->scanner.horizon),
    7266                 :                       LSN_IN_PARTS(data->scanner.last_file_page),
    7267                 :                       (uint) data->scanner.page_offset,
    7268                 :                       (uint) data->scanner.page_offset,
    7269                 :                       data->scanner.fixed_horizon));
    7270               0 :   if (offset < data->read_header)
    7271                 :   {
    7272               0 :     uint16 len= min(data->read_header, end) - offset;
    7273               0 :     DBUG_PRINT("info",
    7274                 :                ("enter header offset: %lu  length: %lu",
    7275                 :                 (ulong) offset, (ulong) length));
    7276               0 :     memcpy(buffer, data->header.header + offset, len);
    7277               0 :     length-= len;
    7278               0 :     if (length == 0)
    7279                 :     {
    7280               0 :       translog_destroy_reader_data(data);
    7281               0 :       DBUG_RETURN(requested_length);
    7282                 :     }
    7283               0 :     offset+= len;
    7284               0 :     buffer+= len;
    7285               0 :     DBUG_PRINT("info",
    7286                 :                ("len: %u  offset: %lu   curr: %lu  length: %lu",
    7287                 :                 len, (ulong) offset, (ulong) data->current_offset,
    7288                 :                 (ulong) length));
    7289                 :   }
    7290                 :   /* TODO: find first page which we should read by offset */
    7291                 : 
    7292                 :   /* read the record chunk by chunk */
    7293                 :   for(;;)
    7294                 :   {
    7295               0 :     uint page_end= data->current_offset + data->chunk_size;
    7296               0 :     DBUG_PRINT("info",
    7297                 :                ("enter body offset: %lu  curr: %lu  "
    7298                 :                 "length: %lu  page_end: %lu",
    7299                 :                 (ulong) offset, (ulong) data->current_offset, (ulong) length,
    7300                 :                 (ulong) page_end));
    7301               0 :     if (offset < page_end)
    7302                 :     {
    7303               0 :       uint len= page_end - offset;
    7304               0 :       set_if_smaller(len, length); /* in case we read beyond record's end */
    7305               0 :       DBUG_ASSERT(offset >= data->current_offset);
    7306               0 :       memcpy(buffer,
    7307                 :               data->scanner.page + data->body_offset +
    7308                 :               (offset - data->current_offset), len);
    7309               0 :       length-= len;
    7310               0 :       if (length == 0)
    7311                 :       {
    7312               0 :         translog_destroy_reader_data(data);
    7313               0 :         DBUG_RETURN(requested_length);
    7314                 :       }
    7315               0 :       offset+= len;
    7316               0 :       buffer+= len;
    7317               0 :       DBUG_PRINT("info",
    7318                 :                  ("len: %u  offset: %lu  curr: %lu  length: %lu",
    7319                 :                   len, (ulong) offset, (ulong) data->current_offset,
    7320                 :                   (ulong) length));
    7321                 :     }
    7322               0 :     if (translog_record_read_next_chunk(data))
    7323                 :     {
    7324               0 :       translog_destroy_reader_data(data);
    7325               0 :       DBUG_RETURN(requested_length - length);
    7326                 :     }
    7327                 :   }
    7328                 : }
    7329                 : 
    7330                 : 
    7331                 : /*
    7332                 :   @brief Force skipping to the next buffer
    7333                 : 
    7334                 :   @todo Do not copy old page content if all page protections are switched off
    7335                 :   (because we do not need calculate something or change old parts of the page)
    7336                 : */
    7337                 : 
    7338                 : static void translog_force_current_buffer_to_finish()
    7339               4 : {
    7340                 :   TRANSLOG_ADDRESS new_buff_beginning;
    7341               4 :   uint16 old_buffer_no= log_descriptor.bc.buffer_no;
    7342               4 :   uint16 new_buffer_no= (old_buffer_no + 1) % TRANSLOG_BUFFERS_NO;
    7343                 :   struct st_translog_buffer *new_buffer= (log_descriptor.buffers +
    7344               4 :                                           new_buffer_no);
    7345               4 :   struct st_translog_buffer *old_buffer= log_descriptor.bc.buffer;
    7346               4 :   uchar *data= log_descriptor.bc.ptr - log_descriptor.bc.current_page_fill;
    7347               4 :   uint16 left= TRANSLOG_PAGE_SIZE - log_descriptor.bc.current_page_fill;
    7348                 :   uint16 current_page_fill, write_counter, previous_offset;
    7349               4 :   DBUG_ENTER("translog_force_current_buffer_to_finish");
    7350               4 :   DBUG_PRINT("enter", ("Buffer #%u 0x%lx  "
    7351                 :                        "Buffer addr: (%lu,0x%lx)  "
    7352                 :                        "Page addr: (%lu,0x%lx)  "
    7353                 :                        "size: %lu (%lu)  Pg: %u  left: %u  in progress %u",
    7354                 :                        (uint) log_descriptor.bc.buffer_no,
    7355                 :                        (ulong) log_descriptor.bc.buffer,
    7356                 :                        LSN_IN_PARTS(log_descriptor.bc.buffer->offset),
    7357                 :                        (ulong) LSN_FILE_NO(log_descriptor.horizon),
    7358                 :                        (ulong) (LSN_OFFSET(log_descriptor.horizon) -
    7359                 :                                 log_descriptor.bc.current_page_fill),
    7360                 :                        (ulong) log_descriptor.bc.buffer->size,
    7361                 :                        (ulong) (log_descriptor.bc.ptr -log_descriptor.bc.
    7362                 :                                 buffer->buffer),
    7363                 :                        (uint) log_descriptor.bc.current_page_fill,
    7364                 :                        (uint) left,
    7365                 :                        (uint) log_descriptor.bc.buffer->
    7366                 :                        copy_to_buffer_in_progress));
    7367               4 :   translog_lock_assert_owner();
    7368               4 :   LINT_INIT(current_page_fill);
    7369               4 :   new_buff_beginning= log_descriptor.bc.buffer->offset;
    7370               4 :   new_buff_beginning+= log_descriptor.bc.buffer->size; /* increase offset */
    7371                 : 
    7372               4 :   DBUG_ASSERT(log_descriptor.bc.ptr !=NULL);
    7373               4 :   DBUG_ASSERT(LSN_FILE_NO(log_descriptor.horizon) ==
    7374                 :               LSN_FILE_NO(log_descriptor.bc.buffer->offset));
    7375               4 :   translog_check_cursor(&log_descriptor.bc);
    7376               4 :   DBUG_ASSERT(left < TRANSLOG_PAGE_SIZE);
    7377               4 :   if (left)
    7378                 :   {
    7379                 :     /*
    7380                 :        TODO: if 'left' is so small that can't hold any other record
    7381                 :        then do not move the page
    7382                 :     */
    7383               4 :     DBUG_PRINT("info", ("left: %u", (uint) left));
    7384                 : 
    7385                 :     /* decrease offset */
    7386               4 :     new_buff_beginning-= log_descriptor.bc.current_page_fill;
    7387               4 :     current_page_fill= log_descriptor.bc.current_page_fill;
    7388                 : 
    7389               4 :     memset(log_descriptor.bc.ptr, TRANSLOG_FILLER, left);
    7390               4 :     log_descriptor.bc.buffer->size+= left;
    7391               4 :     DBUG_PRINT("info", ("Finish Page buffer #%u: 0x%lx  "
    7392                 :                         "Size: %lu",
    7393                 :                         (uint) log_descriptor.bc.buffer->buffer_no,
    7394                 :                         (ulong) log_descriptor.bc.buffer,
    7395                 :                         (ulong) log_descriptor.bc.buffer->size));
    7396               4 :     DBUG_ASSERT(log_descriptor.bc.buffer->buffer_no ==
    7397                 :                 log_descriptor.bc.buffer_no);
    7398                 :   }
    7399                 :   else
    7400                 :   {
    7401               0 :     log_descriptor.bc.current_page_fill= 0;
    7402                 :   }
    7403                 : 
    7404               4 :   translog_buffer_lock(new_buffer);
    7405                 : #ifndef DBUG_OFF
    7406                 :   {
    7407               4 :     TRANSLOG_ADDRESS offset= new_buffer->offset;
    7408               4 :     TRANSLOG_FILE *file= new_buffer->file;
    7409               4 :     uint8 ver= new_buffer->ver;
    7410               4 :     translog_lock_assert_owner();
    7411                 : #endif
    7412               4 :     translog_wait_for_buffer_free(new_buffer);
    7413                 : #ifndef DBUG_OFF
    7414                 :     /* We keep the handler locked so nobody can start this new buffer */
    7415               4 :     DBUG_ASSERT(offset == new_buffer->offset && new_buffer->file == NULL &&
    7416                 :                 (file == NULL ? ver : (uint8)(ver + 1)) == new_buffer->ver);
    7417                 :   }
    7418                 : #endif
    7419                 : 
    7420               4 :   write_counter= log_descriptor.bc.write_counter;
    7421               4 :   previous_offset= log_descriptor.bc.previous_offset;
    7422               4 :   translog_start_buffer(new_buffer, &log_descriptor.bc, new_buffer_no);
    7423                 :   /* Fix buffer offset (which was incorrectly set to horizon) */
    7424               4 :   log_descriptor.bc.buffer->offset= new_buff_beginning;
    7425               4 :   log_descriptor.bc.write_counter= write_counter;
    7426               4 :   log_descriptor.bc.previous_offset= previous_offset;
    7427               4 :   new_buffer->prev_last_lsn= BUFFER_MAX_LSN(old_buffer);
    7428               4 :   DBUG_PRINT("info", ("prev_last_lsn set to (%lu,0x%lx)  buffer: 0x%lx",
    7429                 :                       LSN_IN_PARTS(new_buffer->prev_last_lsn),
    7430                 :                       (ulong) new_buffer));
    7431                 : 
    7432                 :   /*
    7433                 :     Advances this log pointer, increases writers and let other threads to
    7434                 :     write to the log while we process old page content
    7435                 :   */
    7436               4 :   if (left)
    7437                 :   {
    7438               4 :     log_descriptor.bc.ptr+= current_page_fill;
    7439               4 :     log_descriptor.bc.buffer->size= log_descriptor.bc.current_page_fill=
    7440                 :       current_page_fill;
    7441               4 :     new_buffer->overlay= 1;
    7442                 :   }
    7443                 :   else
    7444               0 :     translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
    7445               4 :   translog_buffer_increase_writers(new_buffer);
    7446               4 :   translog_buffer_unlock(new_buffer);
    7447                 : 
    7448                 :   /*
    7449                 :     We have to wait until all writers finish before start changing the
    7450                 :     pages by applying protection and copying the page content in the
    7451                 :     new buffer.
    7452                 :   */
    7453                 : #ifndef DBUG_OFF
    7454                 :   {
    7455               4 :     TRANSLOG_ADDRESS offset= old_buffer->offset;
    7456               4 :     TRANSLOG_FILE *file= old_buffer->file;
    7457               4 :     uint8 ver= old_buffer->ver;
    7458                 : #endif
    7459                 :     /*
    7460                 :       Now only one thread can flush log (buffer can flush many threads but
    7461                 :       log flush log flush where this function is used can do only one thread)
    7462                 :       so no other thread can set is_closing_buffer.
    7463                 :     */
    7464               4 :     DBUG_ASSERT(!old_buffer->is_closing_buffer);
    7465               4 :     old_buffer->is_closing_buffer= 1; /* Other flushes will wait */
    7466               4 :     DBUG_PRINT("enter", ("Buffer #%u 0x%lx  is_closing_buffer set",
    7467                 :                          (uint) old_buffer->buffer_no, (ulong) old_buffer));
    7468               4 :     translog_wait_for_writers(old_buffer);
    7469                 : #ifndef DBUG_OFF
    7470                 :     /* We blocked flushing this buffer so the buffer should not changed */
    7471               4 :     DBUG_ASSERT(offset == old_buffer->offset && file == old_buffer->file &&
    7472                 :                 ver == old_buffer->ver);
    7473                 :   }
    7474                 : #endif
    7475                 : 
    7476               4 :   if (log_descriptor.flags & TRANSLOG_SECTOR_PROTECTION)
    7477                 :   {
    7478               0 :     translog_put_sector_protection(data, &log_descriptor.bc);
    7479               0 :     if (left)
    7480                 :     {
    7481               0 :       log_descriptor.bc.write_counter++;
    7482               0 :       log_descriptor.bc.previous_offset= current_page_fill;
    7483                 :     }
    7484                 :     else
    7485                 :     {
    7486               0 :       DBUG_PRINT("info", ("drop write_counter"));
    7487               0 :       log_descriptor.bc.write_counter= 0;
    7488               0 :       log_descriptor.bc.previous_offset= 0;
    7489                 :     }
    7490                 :   }
    7491                 : 
    7492               4 :   if (log_descriptor.flags & TRANSLOG_PAGE_CRC)
    7493                 :   {
    7494                 :     uint32 crc= translog_crc(data + log_descriptor.page_overhead,
    7495                 :                              TRANSLOG_PAGE_SIZE -
    7496               0 :                              log_descriptor.page_overhead);
    7497               0 :     DBUG_PRINT("info", ("CRC: 0x%lx", (ulong) crc));
    7498               0 :     int4store(data + 3 + 3 + 1, crc);
    7499                 :   }
    7500               4 :   old_buffer->is_closing_buffer= 0;
    7501               4 :   DBUG_PRINT("enter", ("Buffer #%u 0x%lx  is_closing_buffer cleared",
    7502                 :                        (uint) old_buffer->buffer_no, (ulong) old_buffer));
    7503               4 :   pthread_cond_broadcast(&old_buffer->waiting_filling_buffer);
    7504                 : 
    7505               4 :   if (left)
    7506                 :   {
    7507                 :     /*
    7508                 :       TODO: do not copy beginning of the page if we have no CRC or sector
    7509                 :       checks on
    7510                 :     */
    7511               4 :     memcpy(new_buffer->buffer, data, current_page_fill);
    7512                 :   }
    7513               4 :   old_buffer->next_buffer_offset= new_buffer->offset;
    7514               4 :   translog_buffer_lock(new_buffer);
    7515               4 :   new_buffer->prev_buffer_offset= old_buffer->offset;
    7516               4 :   translog_buffer_decrease_writers(new_buffer);
    7517               4 :   translog_buffer_unlock(new_buffer);
    7518                 : 
    7519               4 :   DBUG_VOID_RETURN;
    7520                 : }
    7521                 : 
    7522                 : 
    7523                 : /**
    7524                 :   @brief Waits while given lsn will be flushed
    7525                 : 
    7526                 :   @param  lsn            log record serial number up to which (inclusive)
    7527                 :                          the log has to be flushed
    7528                 : */
    7529                 : 
    7530                 : void  translog_flush_wait_for_end(LSN lsn)
    7531               0 : {
    7532               0 :   DBUG_ENTER("translog_flush_wait_for_end");
    7533               0 :   DBUG_PRINT("enter", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
    7534               0 :   safe_mutex_assert_owner(&log_descriptor.log_flush_lock);
    7535               0 :   while (cmp_translog_addr(log_descriptor.flushed, lsn) < 0)
    7536               0 :     pthread_cond_wait(&log_descriptor.log_flush_cond,
    7537                 :                       &log_descriptor.log_flush_lock);
    7538               0 :   DBUG_VOID_RETURN;
    7539                 : }
    7540                 : 
    7541                 : 
    7542                 : /**
    7543                 :   @brief Sets goal for the next flush pass and waits for this pass end.
    7544                 : 
    7545                 :   @param  lsn            log record serial number up to which (inclusive)
    7546                 :                          the log has to be flushed
    7547                 : */
    7548                 : 
    7549                 : void translog_flush_set_new_goal_and_wait(TRANSLOG_ADDRESS lsn)
    7550               0 : {
    7551               0 :   DBUG_ENTER("translog_flush_set_new_goal_and_wait");
    7552               0 :   DBUG_PRINT("enter", ("LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
    7553               0 :   safe_mutex_assert_owner(&log_descriptor.log_flush_lock);
    7554               0 :   if (cmp_translog_addr(lsn, log_descriptor.next_pass_max_lsn) > 0)
    7555                 :   {
    7556               0 :     log_descriptor.next_pass_max_lsn= lsn;
    7557               0 :     log_descriptor.max_lsn_requester= pthread_self();
    7558                 :   }
    7559               0 :   while (log_descriptor.flush_in_progress)
    7560                 :   {
    7561               0 :     pthread_cond_wait(&log_descriptor.log_flush_cond,
    7562                 :                       &log_descriptor.log_flush_lock);
    7563                 :   }
    7564               0 :   DBUG_VOID_RETURN;
    7565                 : }
    7566                 : 
    7567                 : 
    7568                 : /**
    7569                 :   @brief Flush the log up to given LSN (included)
    7570                 : 
    7571                 :   @param  lsn            log record serial number up to which (inclusive)
    7572                 :                          the log has to be flushed
    7573                 : 
    7574                 :   @return Operation status
    7575                 :     @retval 0      OK
    7576                 :     @retval 1      Error
    7577                 : 
    7578                 : */
    7579                 : 
    7580                 : my_bool translog_flush(TRANSLOG_ADDRESS lsn)
    7581               4 : {
    7582               4 :   LSN sent_to_disk= LSN_IMPOSSIBLE;
    7583                 :   TRANSLOG_ADDRESS flush_horizon;
    7584                 :   uint fn, i;
    7585                 :   dirty_buffer_mask_t dirty_buffer_mask;
    7586                 :   uint8 last_buffer_no, start_buffer_no;
    7587               4 :   my_bool rc= 0;
    7588               4 :   DBUG_ENTER("translog_flush");
    7589               4 :   DBUG_PRINT("enter", ("Flush up to LSN: (%lu,0x%lx)", LSN_IN_PARTS(lsn)));
    7590               4 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    7591                 :               translog_status == TRANSLOG_READONLY);
    7592               4 :   LINT_INIT(sent_to_disk);
    7593                 : 
    7594               4 :   pthread_mutex_lock(&log_descriptor.log_flush_lock);
    7595               4 :   DBUG_PRINT("info", ("Everything is flushed up to (%lu,0x%lx)",
    7596                 :                       LSN_IN_PARTS(log_descriptor.flushed)));
    7597               4 :   if (cmp_translog_addr(log_descriptor.flushed, lsn) >= 0)
    7598                 :   {
    7599               0 :     pthread_mutex_unlock(&log_descriptor.log_flush_lock);
    7600               0 :     DBUG_RETURN(0);
    7601                 :   }
    7602               4 :   if (log_descriptor.flush_in_progress)
    7603                 :   {
    7604               0 :     translog_flush_set_new_goal_and_wait(lsn);
    7605               0 :     if (!pthread_equal(log_descriptor.max_lsn_requester, pthread_self()))
    7606                 :     {
    7607                 :       /* fix lsn if it was horizon */
    7608               0 :       if (cmp_translog_addr(lsn, log_descriptor.bc.buffer->last_lsn) > 0)
    7609               0 :           lsn= BUFFER_MAX_LSN(log_descriptor.bc.buffer);
    7610               0 :       translog_flush_wait_for_end(lsn);
    7611               0 :       pthread_mutex_unlock(&log_descriptor.log_flush_lock);
    7612               0 :       DBUG_RETURN(0);
    7613                 :     }
    7614               0 :     log_descriptor.next_pass_max_lsn= LSN_IMPOSSIBLE;
    7615                 :   }
    7616               4 :   log_descriptor.flush_in_progress= 1;
    7617               4 :   flush_horizon= log_descriptor.previous_flush_horizon;
    7618               4 :   DBUG_PRINT("info", ("flush_in_progress is set"));
    7619               4 :   pthread_mutex_unlock(&log_descriptor.log_flush_lock);
    7620                 : 
    7621               4 :   translog_lock();
    7622               4 :   if (log_descriptor.is_everything_flushed)
    7623                 :   {
    7624               0 :     DBUG_PRINT("info", ("everything is flushed"));
    7625               0 :     rc= (translog_status == TRANSLOG_READONLY);
    7626               0 :     translog_unlock();
    7627               0 :     goto out;
    7628                 :   }
    7629                 : 
    7630                 :   /*
    7631                 :     We will recheck information when will lock buffers one by
    7632                 :     one so we can use unprotected read here (this is just for
    7633                 :     speed up buffers processing)
    7634                 :   */
    7635               4 :   dirty_buffer_mask= log_descriptor.dirty_buffer_mask;
    7636               4 :   DBUG_PRINT("info", ("Dirty buffer mask: %lx  current buffer: %u",
    7637                 :                       (ulong) dirty_buffer_mask,
    7638                 :                       (uint) log_descriptor.bc.buffer_no));
    7639               4 :   for (i= (log_descriptor.bc.buffer_no + 1) % TRANSLOG_BUFFERS_NO;
    7640              36 :        i != log_descriptor.bc.buffer_no && !(dirty_buffer_mask & (1 << i));
    7641              28 :        i= (i + 1) % TRANSLOG_BUFFERS_NO) {}
    7642               4 :   start_buffer_no= i;
    7643                 : 
    7644               4 :   DBUG_PRINT("info",
    7645                 :              ("start from: %u  current: %u  prev last lsn: (%lu,0x%lx)",
    7646                 :               (uint) start_buffer_no, (uint) log_descriptor.bc.buffer_no,
    7647                 :               LSN_IN_PARTS(log_descriptor.bc.buffer->prev_last_lsn)));
    7648                 : 
    7649                 : 
    7650                 :   /*
    7651                 :     if LSN up to which we have to flush bigger then maximum LSN of previous
    7652                 :     buffer and at least one LSN was saved in the current buffer (last_lsn !=
    7653                 :     LSN_IMPOSSIBLE) then we better finish the current buffer.
    7654                 :   */
    7655               8 :   if (cmp_translog_addr(lsn, log_descriptor.bc.buffer->prev_last_lsn) > 0 &&
    7656                 :       log_descriptor.bc.buffer->last_lsn != LSN_IMPOSSIBLE)
    7657                 :   {
    7658               4 :     struct st_translog_buffer *buffer= log_descriptor.bc.buffer;
    7659               4 :     lsn= log_descriptor.bc.buffer->last_lsn; /* fix lsn if it was horizon */
    7660               4 :     DBUG_PRINT("info", ("LSN to flush fixed to last lsn: (%lu,0x%lx)",
    7661                 :                LSN_IN_PARTS(log_descriptor.bc.buffer->last_lsn)));
    7662               4 :     last_buffer_no= log_descriptor.bc.buffer_no;
    7663               4 :     log_descriptor.is_everything_flushed= 1;
    7664               4 :     translog_force_current_buffer_to_finish();
    7665               4 :     translog_buffer_unlock(buffer);
    7666                 :   }
    7667                 :   else
    7668                 :   {
    7669               0 :     last_buffer_no= ((log_descriptor.bc.buffer_no + TRANSLOG_BUFFERS_NO -1) %
    7670                 :                      TRANSLOG_BUFFERS_NO);
    7671               0 :     translog_unlock();
    7672                 :   }
    7673               4 :   sent_to_disk= translog_get_sent_to_disk();
    7674               4 :   if (cmp_translog_addr(lsn, sent_to_disk) > 0)
    7675                 :   {
    7676                 : 
    7677               4 :     DBUG_PRINT("info", ("Start buffer #: %u  last buffer #: %u",
    7678                 :                         (uint) start_buffer_no, (uint) last_buffer_no));
    7679               4 :     last_buffer_no= (last_buffer_no + 1) % TRANSLOG_BUFFERS_NO;
    7680               4 :     i= start_buffer_no;
    7681                 :     do
    7682                 :     {
    7683               4 :       struct st_translog_buffer *buffer= log_descriptor.buffers + i;
    7684               4 :       translog_buffer_lock(buffer);
    7685               4 :       DBUG_PRINT("info", ("Check buffer: 0x%lx  #: %u  "
    7686                 :                           "prev last LSN: (%lu,0x%lx)  "
    7687                 :                           "last LSN: (%lu,0x%lx)  status: %s",
    7688                 :                           (ulong)(buffer),
    7689                 :                           (uint) i,
    7690                 :                           LSN_IN_PARTS(buffer->prev_last_lsn),
    7691                 :                           LSN_IN_PARTS(buffer->last_lsn),
    7692                 :                           (buffer->file ?
    7693                 :                            "dirty" : "closed")));
    7694               4 :       if (buffer->prev_last_lsn <= lsn &&
    7695                 :           buffer->file != NULL)
    7696                 :       {
    7697               4 :         DBUG_ASSERT(flush_horizon <= buffer->offset + buffer->size);
    7698               4 :         flush_horizon= buffer->offset + buffer->size;
    7699               4 :         translog_buffer_flush(buffer);
    7700                 :       }
    7701               4 :       translog_buffer_unlock(buffer);
    7702               4 :       i= (i + 1) % TRANSLOG_BUFFERS_NO;
    7703               4 :     } while (i != last_buffer_no);
    7704               4 :     sent_to_disk= translog_get_sent_to_disk();
    7705                 :   }
    7706                 : 
    7707                 :   /* sync files from previous flush till current one */
    7708               8 :   for (fn= LSN_FILE_NO(log_descriptor.flushed); fn <= LSN_FILE_NO(lsn); fn++)
    7709                 :   {
    7710               4 :     TRANSLOG_FILE *file= get_logfile_by_number(fn);
    7711               4 :     DBUG_ASSERT(file != NULL);
    7712               4 :     if (!file->is_sync)
    7713                 :     {
    7714               4 :       if (my_sync(file->handler.file, MYF(MY_WME)))
    7715                 :       {
    7716               0 :         rc= 1;
    7717               0 :         translog_stop_writing();
    7718               0 :         sent_to_disk= LSN_IMPOSSIBLE;
    7719               0 :         goto out;
    7720                 :       }
    7721               4 :       file->is_sync= 1;
    7722                 :     }
    7723                 :   }
    7724                 : 
    7725               4 :   if (sync_log_dir >= TRANSLOG_SYNC_DIR_ALWAYS &&
    7726                 :       (LSN_FILE_NO(log_descriptor.previous_flush_horizon) !=
    7727                 :        LSN_FILE_NO(flush_horizon) ||
    7728                 :        ((LSN_OFFSET(log_descriptor.previous_flush_horizon) - 1) /
    7729                 :         TRANSLOG_PAGE_SIZE) !=
    7730                 :        ((LSN_OFFSET(flush_horizon) - 1) / TRANSLOG_PAGE_SIZE)))
    7731               0 :     rc|= sync_dir(log_descriptor.directory_fd, MYF(MY_WME | MY_IGNORE_BADFD));
    7732               4 :   log_descriptor.previous_flush_horizon= flush_horizon;
    7733               4 : out:
    7734               4 :   pthread_mutex_lock(&log_descriptor.log_flush_lock);
    7735               4 :   if (sent_to_disk != LSN_IMPOSSIBLE)
    7736               4 :     log_descriptor.flushed= sent_to_disk;
    7737               4 :   log_descriptor.flush_in_progress= 0;
    7738               4 :   DBUG_PRINT("info", ("flush_in_progress is dropped"));
    7739               4 :   pthread_mutex_unlock(&log_descriptor.log_flush_lock);\
    7740                 :   pthread_cond_broadcast(&log_descriptor.log_flush_cond);
    7741               4 :   DBUG_RETURN(rc);
    7742                 : }
    7743                 : 
    7744                 : 
    7745                 : /**
    7746                 :    @brief Gives a 2-byte-id to MARIA_SHARE and logs this fact
    7747                 : 
    7748                 :    If a MARIA_SHARE does not yet have a 2-byte-id (unique over all currently
    7749                 :    open MARIA_SHAREs), give it one and record this assignment in the log
    7750                 :    (LOGREC_FILE_ID log record).
    7751                 : 
    7752                 :    @param  tbl_info        table
    7753                 :    @param  trn             calling transaction
    7754                 : 
    7755                 :    @return Operation status
    7756                 :      @retval 0      OK
    7757                 :      @retval 1      Error
    7758                 : 
    7759                 :    @note Can be called even if share already has an id (then will do nothing)
    7760                 : */
    7761                 : 
    7762                 : int translog_assign_id_to_share(MARIA_HA *tbl_info, TRN *trn)
    7763               0 : {
    7764               0 :   MARIA_SHARE *share= tbl_info->s;
    7765                 :   /*
    7766                 :     If you give an id to a non-BLOCK_RECORD table, you also need to release
    7767                 :     this id somewhere. Then you can change the assertion.
    7768                 :   */
    7769               0 :   DBUG_ASSERT(share->data_file_type == BLOCK_RECORD);
    7770                 :   /* re-check under mutex to avoid having 2 ids for the same share */
    7771               0 :   pthread_mutex_lock(&share->intern_lock);
    7772               0 :   if (unlikely(share->id == 0))
    7773                 :   {
    7774                 :     LSN lsn;
    7775                 :     LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
    7776                 :     uchar log_data[FILEID_STORE_SIZE];
    7777                 :     /* Inspired by set_short_trid() of trnman.c */
    7778               0 :     uint i= share->kfile.file % SHARE_ID_MAX + 1;
    7779                 :     do
    7780                 :     {
    7781                 :       my_atomic_rwlock_wrlock(&LOCK_id_to_share);
    7782               0 :       for ( ; i <= SHARE_ID_MAX ; i++) /* the range is [1..SHARE_ID_MAX] */
    7783                 :       {
    7784               0 :         void *tmp= NULL;
    7785               0 :         if (id_to_share[i] == NULL &&
    7786                 :             my_atomic_casptr((void **)&id_to_share[i], &tmp, share))
    7787                 :         {
    7788               0 :           share->id= (uint16)i;
    7789               0 :           break;
    7790                 :         }
    7791                 :       }
    7792                 :       my_atomic_rwlock_wrunlock(&LOCK_id_to_share);
    7793               0 :       i= 1; /* scan the whole array */
    7794               0 :     } while (share->id == 0);
    7795               0 :     DBUG_PRINT("info", ("id_to_share: 0x%lx -> %u", (ulong)share, share->id));
    7796               0 :     log_array[TRANSLOG_INTERNAL_PARTS + 0].str=    log_data;
    7797               0 :     log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data);
    7798                 :     /*
    7799                 :       open_file_name is an unresolved name (symlinks are not resolved, datadir
    7800                 :       is not realpath-ed, etc) which is good: the log can be moved to another
    7801                 :       directory and continue working.
    7802                 :     */
    7803               0 :     log_array[TRANSLOG_INTERNAL_PARTS + 1].str=
    7804                 :       (uchar *)share->open_file_name.str;
    7805               0 :     log_array[TRANSLOG_INTERNAL_PARTS + 1].length=
    7806                 :       share->open_file_name.length + 1;
    7807                 :     /*
    7808                 :       We can't unlock share->intern_lock before the log entry is written to
    7809                 :       ensure no one uses the id before it's logged.
    7810                 :     */
    7811               0 :     if (unlikely(translog_write_record(&lsn, LOGREC_FILE_ID, trn, tbl_info,
    7812                 :                                        (translog_size_t)
    7813                 :                                        (sizeof(log_data) +
    7814                 :                                         log_array[TRANSLOG_INTERNAL_PARTS +
    7815                 :                                                   1].length),
    7816                 :                                        sizeof(log_array)/sizeof(log_array[0]),
    7817                 :                                        log_array, log_data, NULL)))
    7818                 :     {
    7819               0 :       pthread_mutex_unlock(&share->intern_lock);
    7820               0 :       return 1;
    7821                 :     }
    7822                 :   }
    7823               0 :   pthread_mutex_unlock(&share->intern_lock);
    7824               0 :   return 0;
    7825                 : }
    7826                 : 
    7827                 : 
    7828                 : /**
    7829                 :    @brief Recycles a MARIA_SHARE's short id.
    7830                 : 
    7831                 :    @param  share           table
    7832                 : 
    7833                 :    @note Must be called only if share has an id (i.e. id != 0)
    7834                 : */
    7835                 : 
    7836                 : void translog_deassign_id_from_share(MARIA_SHARE *share)
    7837               0 : {
    7838               0 :   DBUG_PRINT("info", ("id_to_share: 0x%lx id %u -> 0",
    7839                 :                       (ulong)share, share->id));
    7840                 :   /*
    7841                 :     We don't need any mutex as we are called only when closing the last
    7842                 :     instance of the table or at the end of REPAIR: no writes can be
    7843                 :     happening. But a Checkpoint may be reading share->id, so we require this
    7844                 :     mutex:
    7845                 :   */
    7846               0 :   safe_mutex_assert_owner(&share->intern_lock);
    7847                 :   my_atomic_rwlock_rdlock(&LOCK_id_to_share);
    7848               0 :   my_atomic_storeptr((void **)&id_to_share[share->id], 0);
    7849                 :   my_atomic_rwlock_rdunlock(&LOCK_id_to_share);
    7850               0 :   share->id= 0;
    7851                 :   /* useless but safety: */
    7852               0 :   share->lsn_of_file_id= LSN_IMPOSSIBLE;
    7853                 : }
    7854                 : 
    7855                 : 
    7856                 : void translog_assign_id_to_share_from_recovery(MARIA_SHARE *share,
    7857                 :                                                uint16 id)
    7858               0 : {
    7859               0 :   DBUG_ASSERT(maria_in_recovery && !maria_multi_threaded);
    7860               0 :   DBUG_ASSERT(share->data_file_type == BLOCK_RECORD);
    7861               0 :   DBUG_ASSERT(share->id == 0);
    7862               0 :   DBUG_ASSERT(id_to_share[id] == NULL);
    7863               0 :   id_to_share[share->id= id]= share;
    7864                 : }
    7865                 : 
    7866                 : 
    7867                 : /**
    7868                 :    @brief check if such log file exists
    7869                 : 
    7870                 :    @param file_no number of the file to test
    7871                 : 
    7872                 :    @retval 0 no such file
    7873                 :    @retval 1 there is file with such number
    7874                 : */
    7875                 : 
    7876                 : my_bool translog_is_file(uint file_no)
    7877               4 : {
    7878                 :   MY_STAT stat_buff;
    7879                 :   char path[FN_REFLEN];
    7880               4 :   return (test(my_stat(translog_filename_by_fileno(file_no, path),
    7881                 :                        &stat_buff, MYF(0))));
    7882                 : }
    7883                 : 
    7884                 : 
    7885                 : /**
    7886                 :   @brief returns minimum log file number
    7887                 : 
    7888                 :   @param horizon         the end of the log
    7889                 :   @param is_protected    true if it is under purge_log protection
    7890                 : 
    7891                 :   @retval minimum file number
    7892                 :   @retval 0 no files found
    7893                 : */
    7894                 : 
    7895                 : static uint32 translog_first_file(TRANSLOG_ADDRESS horizon, int is_protected)
    7896               9 : {
    7897               9 :   uint min_file= 0, max_file;
    7898               9 :   DBUG_ENTER("translog_first_file");
    7899               9 :   if (!is_protected)
    7900               5 :     pthread_mutex_lock(&log_descriptor.purger_lock);
    7901               9 :   if (log_descriptor.min_file_number &&
    7902                 :       translog_is_file(log_descriptor.min_file_number))
    7903                 :   {
    7904               4 :     DBUG_PRINT("info", ("cached %lu",
    7905                 :                         (ulong) log_descriptor.min_file_number));
    7906               4 :     if (!is_protected)
    7907               0 :       pthread_mutex_unlock(&log_descriptor.purger_lock);
    7908               4 :     DBUG_RETURN(log_descriptor.min_file_number);
    7909                 :   }
    7910                 : 
    7911               5 :   max_file= LSN_FILE_NO(horizon);
    7912                 : 
    7913                 :   /* binary search for last file */
    7914              10 :   while (min_file != max_file && min_file != (max_file - 1))
    7915                 :   {
    7916               0 :     uint test= (min_file + max_file) / 2;
    7917               0 :     DBUG_PRINT("info", ("min_file: %u  test: %u  max_file: %u",
    7918                 :                         min_file, test, max_file));
    7919               0 :     if (test == max_file)
    7920               0 :       test--;
    7921               0 :     if (translog_is_file(test))
    7922               0 :       max_file= test;
    7923                 :     else
    7924               0 :       min_file= test;
    7925                 :   }
    7926               5 :   log_descriptor.min_file_number= max_file;
    7927               5 :   if (!is_protected)
    7928               5 :     pthread_mutex_unlock(&log_descriptor.purger_lock);
    7929               5 :   DBUG_PRINT("info", ("first file :%lu", (ulong) max_file));
    7930               5 :   DBUG_ASSERT(max_file >= 1);
    7931               5 :   DBUG_RETURN(max_file);
    7932                 : }
    7933                 : 
    7934                 : 
    7935                 : /**
    7936                 :   @brief returns the most close LSN higher the given chunk address
    7937                 : 
    7938                 :   @param addr the chunk address to start from
    7939                 :   @param horizon the horizon if it is known or LSN_IMPOSSIBLE
    7940                 : 
    7941                 :   @retval LSN_ERROR Error
    7942                 :   @retval LSN_IMPOSSIBLE no LSNs after the address
    7943                 :   @retval # LSN of the most close LSN higher the given chunk address
    7944                 : */
    7945                 : 
    7946                 : LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon)
    7947               5 : {
    7948                 :   TRANSLOG_SCANNER_DATA scanner;
    7949                 :   LSN result;
    7950               5 :   DBUG_ENTER("translog_next_LSN");
    7951                 : 
    7952               5 :   if (horizon == LSN_IMPOSSIBLE)
    7953               0 :     horizon= translog_get_horizon();
    7954                 : 
    7955               5 :   if (addr == horizon)
    7956               5 :     DBUG_RETURN(LSN_IMPOSSIBLE);
    7957                 : 
    7958               0 :   translog_scanner_init(addr, 0, &scanner, 1);
    7959                 :   /*
    7960                 :     addr can point not to a chunk beginning but page end so next
    7961                 :     page beginning.
    7962                 :   */
    7963               0 :   if (addr % TRANSLOG_PAGE_SIZE == 0)
    7964                 :   {
    7965                 :     /*
    7966                 :       We are emulating the page end which cased such horizon value to
    7967                 :       trigger translog_scanner_eop().
    7968                 : 
    7969                 :       We can't just increase addr on page header overhead because it
    7970                 :       can be file end so we allow translog_get_next_chunk() to skip
    7971                 :       to the next page in correct way
    7972                 :     */
    7973               0 :     scanner.page_addr-= TRANSLOG_PAGE_SIZE;
    7974               0 :     scanner.page_offset= TRANSLOG_PAGE_SIZE;
    7975                 : #ifndef DBUG_OFF
    7976               0 :     scanner.page= NULL; /* prevent using incorrect page content */
    7977                 : #endif
    7978                 :   }
    7979                 :   /* addr can point not to a chunk beginning but to a page end */
    7980               0 :   if (translog_scanner_eop(&scanner))
    7981                 :   {
    7982               0 :     if (translog_get_next_chunk(&scanner))
    7983                 :     {
    7984               0 :       result= LSN_ERROR;
    7985               0 :       goto out;
    7986                 :     }
    7987               0 :     if (scanner.page == END_OF_LOG)
    7988                 :     {
    7989               0 :       result= LSN_IMPOSSIBLE;
    7990               0 :       goto out;
    7991                 :     }
    7992                 :   }
    7993                 : 
    7994               0 :   while (!translog_is_LSN_chunk(scanner.page[scanner.page_offset]) &&
    7995                 :          scanner.page[scanner.page_offset] != TRANSLOG_FILLER)
    7996                 :   {
    7997               0 :     if (translog_get_next_chunk(&scanner))
    7998                 :     {
    7999               0 :       result= LSN_ERROR;
    8000               0 :       goto out;
    8001                 :     }
    8002               0 :     if (scanner.page == END_OF_LOG)
    8003                 :     {
    8004               0 :       result= LSN_IMPOSSIBLE;
    8005               0 :       goto out;
    8006                 :     }
    8007                 :   }
    8008                 : 
    8009               0 :   if (scanner.page[scanner.page_offset] == TRANSLOG_FILLER)
    8010               0 :     result= LSN_IMPOSSIBLE; /* reached page filler */
    8011                 :   else
    8012               0 :     result= scanner.page_addr + scanner.page_offset;
    8013               0 : out:
    8014               0 :   translog_destroy_scanner(&scanner);
    8015               0 :   DBUG_RETURN(result);
    8016                 : }
    8017                 : 
    8018                 : 
    8019                 : /**
    8020                 :    @brief returns the LSN of the first record starting in this log
    8021                 : 
    8022                 :    @retval LSN_ERROR Error
    8023                 :    @retval LSN_IMPOSSIBLE no log or the log is empty
    8024                 :    @retval # LSN of the first record
    8025                 : */
    8026                 : 
    8027                 : LSN translog_first_lsn_in_log()
    8028               5 : {
    8029               5 :   TRANSLOG_ADDRESS addr, horizon= translog_get_horizon();
    8030                 :   TRANSLOG_VALIDATOR_DATA data;
    8031                 :   uint file;
    8032                 :   uint16 chunk_offset;
    8033                 :   uchar *page;
    8034               5 :   DBUG_ENTER("translog_first_lsn_in_log");
    8035               5 :   DBUG_PRINT("info", ("Horizon: (%lu,0x%lx)", LSN_IN_PARTS(horizon)));
    8036               5 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    8037                 :               translog_status == TRANSLOG_READONLY);
    8038                 : 
    8039               5 :   if (!(file= translog_first_file(horizon, 0)))
    8040                 :   {
    8041                 :     /* log has no records yet */
    8042               0 :     DBUG_RETURN(LSN_IMPOSSIBLE);
    8043                 :   }
    8044                 : 
    8045               5 :   addr= MAKE_LSN(file, TRANSLOG_PAGE_SIZE); /* the first page of the file */
    8046               5 :   data.addr= &addr;
    8047                 :   {
    8048                 :     TRANSLOG_PAGE_SIZE_BUFF psize_buff;
    8049               5 :     if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL ||
    8050                 :         (chunk_offset= translog_get_first_chunk_offset(page)) == 0)
    8051               0 :       DBUG_RETURN(LSN_ERROR);
    8052                 :   }
    8053               5 :   addr+= chunk_offset;
    8054                 : 
    8055               5 :   DBUG_RETURN(translog_next_LSN(addr, horizon));
    8056                 : }
    8057                 : 
    8058                 : 
    8059                 : /**
    8060                 :    @brief Returns theoretical first LSN if first log is present
    8061                 : 
    8062                 :    @retval LSN_ERROR Error
    8063                 :    @retval LSN_IMPOSSIBLE no log
    8064                 :    @retval # LSN of the first record
    8065                 : */
    8066                 : 
    8067                 : LSN translog_first_theoretical_lsn()
    8068               0 : {
    8069               0 :   TRANSLOG_ADDRESS addr= translog_get_horizon();
    8070                 :   TRANSLOG_PAGE_SIZE_BUFF psize_buff;
    8071                 :   uchar *page;
    8072                 :   TRANSLOG_VALIDATOR_DATA data;
    8073               0 :   DBUG_ENTER("translog_first_theoretical_lsn");
    8074               0 :   DBUG_PRINT("info", ("Horizon: (%lu,0x%lx)", LSN_IN_PARTS(addr)));
    8075               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    8076                 :               translog_status == TRANSLOG_READONLY);
    8077                 : 
    8078               0 :   if (!translog_is_file(1))
    8079               0 :     DBUG_RETURN(LSN_IMPOSSIBLE);
    8080               0 :   if (addr == MAKE_LSN(1, TRANSLOG_PAGE_SIZE))
    8081                 :   {
    8082                 :     /* log has no records yet */
    8083               0 :     DBUG_RETURN(MAKE_LSN(1, TRANSLOG_PAGE_SIZE +
    8084                 :                          log_descriptor.page_overhead));
    8085                 :   }
    8086                 : 
    8087               0 :   addr= MAKE_LSN(1, TRANSLOG_PAGE_SIZE); /* the first page of the file */
    8088               0 :   data.addr= &addr;
    8089               0 :   if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL)
    8090               0 :     DBUG_RETURN(LSN_ERROR);
    8091                 : 
    8092               0 :   DBUG_RETURN(MAKE_LSN(1, TRANSLOG_PAGE_SIZE +
    8093                 :                        page_overhead[page[TRANSLOG_PAGE_FLAGS]]));
    8094                 : }
    8095                 : 
    8096                 : 
    8097                 : /**
    8098                 :   @brief Checks given low water mark and purge files if it is need
    8099                 : 
    8100                 :   @param low the last (minimum) address which is need
    8101                 : 
    8102                 :   @retval 0 OK
    8103                 :   @retval 1 Error
    8104                 : */
    8105                 : 
    8106                 : my_bool translog_purge(TRANSLOG_ADDRESS low)
    8107               4 : {
    8108               4 :   uint32 last_need_file= LSN_FILE_NO(low);
    8109               4 :   TRANSLOG_ADDRESS horizon= translog_get_horizon();
    8110               4 :   int rc= 0;
    8111               4 :   DBUG_ENTER("translog_purge");
    8112               4 :   DBUG_PRINT("enter", ("low: (%lu,0x%lx)", LSN_IN_PARTS(low)));
    8113               4 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    8114                 :               translog_status == TRANSLOG_READONLY);
    8115                 : 
    8116               4 :   pthread_mutex_lock(&log_descriptor.purger_lock);
    8117               4 :   if (LSN_FILE_NO(log_descriptor.last_lsn_checked) < last_need_file)
    8118                 :   {
    8119                 :     uint32 i;
    8120               4 :     uint32 min_file= translog_first_file(horizon, 1);
    8121               4 :     DBUG_ASSERT(min_file != 0); /* log is already started */
    8122               4 :     for(i= min_file; i < last_need_file && rc == 0; i++)
    8123                 :     {
    8124               0 :       LSN lsn= translog_get_file_max_lsn_stored(i);
    8125               0 :       if (lsn == LSN_IMPOSSIBLE)
    8126               0 :         break;   /* files are still in writing */
    8127               0 :       if (lsn == LSN_ERROR)
    8128                 :       {
    8129               0 :         rc= 1;
    8130               0 :         break;
    8131                 :       }
    8132               0 :       if (cmp_translog_addr(lsn, low) >= 0)
    8133               0 :         break;
    8134                 : 
    8135               0 :       DBUG_PRINT("info", ("purge file %lu", (ulong) i));
    8136                 : 
    8137                 :       /* remove file descriptor from the cache */
    8138                 :       /*
    8139                 :         log_descriptor.min_file can be changed only here during execution
    8140                 :         and the function is serialized, so we can access it without problems
    8141                 :       */
    8142               0 :       if (i >= log_descriptor.min_file)
    8143                 :       {
    8144                 :         TRANSLOG_FILE *file;
    8145               0 :         rw_wrlock(&log_descriptor.open_files_lock);
    8146               0 :         DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
    8147                 :                     log_descriptor.open_files.elements);
    8148               0 :         DBUG_ASSERT(log_descriptor.min_file == i);
    8149               0 :         file= *((TRANSLOG_FILE **)pop_dynamic(&log_descriptor.open_files));
    8150               0 :         DBUG_PRINT("info", ("Files : %d", log_descriptor.open_files.elements));
    8151               0 :         DBUG_ASSERT(i == file->number);
    8152               0 :         log_descriptor.min_file++;
    8153               0 :         DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
    8154                 :                     log_descriptor.open_files.elements);
    8155               0 :         rw_unlock(&log_descriptor.open_files_lock);
    8156               0 :         translog_close_log_file(file);
    8157                 :       }
    8158               0 :       if (log_purge_type == TRANSLOG_PURGE_IMMIDIATE)
    8159                 :       {
    8160                 :         char path[FN_REFLEN], *file_name;
    8161               0 :         file_name= translog_filename_by_fileno(i, path);
    8162               0 :         rc= test(my_delete(file_name, MYF(MY_WME)));
    8163                 :       }
    8164                 :     }
    8165               4 :     if (unlikely(rc == 1))
    8166               0 :       log_descriptor.min_need_file= 0; /* impossible value */
    8167                 :     else
    8168               4 :       log_descriptor.min_need_file= i;
    8169                 :   }
    8170                 : 
    8171               4 :   pthread_mutex_unlock(&log_descriptor.purger_lock);
    8172               4 :   DBUG_RETURN(rc);
    8173                 : }
    8174                 : 
    8175                 : 
    8176                 : /**
    8177                 :   @brief Purges files by stored min need file in case of
    8178                 :     "ondemend" purge type
    8179                 : 
    8180                 :   @note This function do real work only if it is "ondemend" purge type
    8181                 :     and translog_purge() was called at least once and last time without
    8182                 :     errors
    8183                 : 
    8184                 :   @retval 0 OK
    8185                 :   @retval 1 Error
    8186                 : */
    8187                 : 
    8188                 : my_bool translog_purge_at_flush()
    8189               0 : {
    8190                 :   uint32 i, min_file;
    8191               0 :   int rc= 0;
    8192               0 :   DBUG_ENTER("translog_purge_at_flush");
    8193               0 :   DBUG_ASSERT(translog_status == TRANSLOG_OK ||
    8194                 :               translog_status == TRANSLOG_READONLY);
    8195                 : 
    8196               0 :   if (unlikely(translog_status == TRANSLOG_READONLY))
    8197                 :   {
    8198               0 :     DBUG_PRINT("info", ("The log is read only => exit"));
    8199               0 :     DBUG_RETURN(0);
    8200                 :   }
    8201                 : 
    8202               0 :   if (log_purge_type != TRANSLOG_PURGE_ONDEMAND)
    8203                 :   {
    8204               0 :     DBUG_PRINT("info", ("It is not \"at_flush\" => exit"));
    8205               0 :     DBUG_RETURN(0);
    8206                 :   }
    8207                 : 
    8208               0 :   pthread_mutex_lock(&log_descriptor.purger_lock);
    8209                 : 
    8210               0 :   if (unlikely(log_descriptor.min_need_file == 0))
    8211                 :   {
    8212               0 :     DBUG_PRINT("info", ("No info about min need file => exit"));
    8213               0 :     pthread_mutex_unlock(&log_descriptor.purger_lock);
    8214               0 :     DBUG_RETURN(0);
    8215                 :   }
    8216                 : 
    8217               0 :   min_file= translog_first_file(translog_get_horizon(), 1);
    8218               0 :   DBUG_ASSERT(min_file != 0); /* log is already started */
    8219               0 :   for(i= min_file; i < log_descriptor.min_need_file && rc == 0; i++)
    8220                 :   {
    8221                 :     char path[FN_REFLEN], *file_name;
    8222               0 :     DBUG_PRINT("info", ("purge file %lu\n", (ulong) i));
    8223               0 :     file_name= translog_filename_by_fileno(i, path);
    8224               0 :     rc= test(my_delete(file_name, MYF(MY_WME)));
    8225                 :   }
    8226                 : 
    8227               0 :   pthread_mutex_unlock(&log_descriptor.purger_lock);
    8228               0 :   DBUG_RETURN(rc);
    8229                 : }
    8230                 : 
    8231                 : 
    8232                 : /**
    8233                 :   @brief Gets min file number
    8234                 : 
    8235                 :   @param horizon         the end of the log
    8236                 : 
    8237                 :   @retval minimum file number
    8238                 :   @retval 0 no files found
    8239                 : */
    8240                 : 
    8241                 : uint32 translog_get_first_file(TRANSLOG_ADDRESS horizon)
    8242               0 : {
    8243               0 :   return translog_first_file(horizon, 0);
    8244                 : }
    8245                 : 
    8246                 : 
    8247                 : /**
    8248                 :   @brief Gets min file number which is needed
    8249                 : 
    8250                 :   @retval minimum file number
    8251                 :   @retval 0 unknown
    8252                 : */
    8253                 : 
    8254                 : uint32 translog_get_first_needed_file()
    8255               0 : {
    8256                 :   uint32 file_no;
    8257               0 :   pthread_mutex_lock(&log_descriptor.purger_lock);
    8258               0 :   file_no= log_descriptor.min_need_file;
    8259               0 :   pthread_mutex_unlock(&log_descriptor.purger_lock);
    8260               0 :   return file_no;
    8261                 : }
    8262                 : 
    8263                 : 
    8264                 : /**
    8265                 :   @brief Gets transaction log file size
    8266                 : 
    8267                 :   @return transaction log file size
    8268                 : */
    8269                 : 
    8270                 : uint32 translog_get_file_size()
    8271               0 : {
    8272                 :   uint32 res;
    8273               0 :   translog_lock();
    8274               0 :   res= log_descriptor.log_file_max_size;
    8275               0 :   translog_unlock();
    8276               0 :   return (res);
    8277                 : }
    8278                 : 
    8279                 : 
    8280                 : /**
    8281                 :   @brief Sets transaction log file size
    8282                 : 
    8283                 :   @return Returns actually set transaction log size
    8284                 : */
    8285                 : 
    8286                 : void translog_set_file_size(uint32 size)
    8287               0 : {
    8288               0 :   struct st_translog_buffer *old_buffer= NULL;
    8289               0 :   DBUG_ENTER("translog_set_file_size");
    8290               0 :   translog_lock();
    8291               0 :   DBUG_PRINT("enter", ("Size: %lu", (ulong) size));
    8292               0 :   DBUG_ASSERT(size % TRANSLOG_PAGE_SIZE == 0 &&
    8293                 :               size >= TRANSLOG_MIN_FILE_SIZE);
    8294               0 :   log_descriptor.log_file_max_size= size;
    8295                 :   /* if current file longer then finish it*/
    8296               0 :   if (LSN_OFFSET(log_descriptor.horizon) >=  log_descriptor.log_file_max_size)
    8297                 :   {
    8298               0 :     old_buffer= log_descriptor.bc.buffer;
    8299               0 :     translog_buffer_next(&log_descriptor.horizon, &log_descriptor.bc, 1);
    8300               0 :     translog_buffer_unlock(old_buffer);
    8301                 :   }
    8302               0 :   translog_unlock();
    8303               0 :   if (old_buffer)
    8304                 :   {
    8305               0 :     translog_buffer_lock(old_buffer);
    8306               0 :     translog_buffer_flush(old_buffer);
    8307               0 :     translog_buffer_unlock(old_buffer);
    8308                 :   }
    8309               0 :   DBUG_VOID_RETURN;
    8310                 : }
    8311                 : 
    8312                 : 
    8313                 : /**
    8314                 :    Write debug information to log if we EXTRA_DEBUG is enabled
    8315                 : */
    8316                 : 
    8317                 : my_bool translog_log_debug_info(TRN *trn __attribute__((unused)),
    8318                 :                                 enum translog_debug_info_type type
    8319                 :                                 __attribute__((unused)),
    8320                 :                                 uchar *info __attribute__((unused)),
    8321                 :                                 size_t length __attribute__((unused)))
    8322               9 : {
    8323                 : #ifdef EXTRA_DEBUG
    8324                 :   LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
    8325                 :   uchar debug_type;
    8326                 :   LSN lsn;
    8327                 : 
    8328               9 :   if (!trn)
    8329                 :   {
    8330                 :     /*
    8331                 :       We can't log the current transaction because we don't have
    8332                 :       an active transaction. Use a temporary transaction object instead
    8333                 :     */
    8334               9 :     trn= &dummy_transaction_object;
    8335                 :   }
    8336               9 :   debug_type= (uchar) type;
    8337               9 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].str= &debug_type;
    8338               9 :   log_array[TRANSLOG_INTERNAL_PARTS + 0].length= 1;
    8339               9 :   log_array[TRANSLOG_INTERNAL_PARTS + 1].str= info;
    8340               9 :   log_array[TRANSLOG_INTERNAL_PARTS + 1].length= length;
    8341               9 :   return translog_write_record(&lsn, LOGREC_DEBUG_INFO,
    8342                 :                                trn, NULL,
    8343                 :                                (translog_size_t) (1+ length),
    8344                 :                                sizeof(log_array)/sizeof(log_array[0]),
    8345                 :                                log_array, NULL, NULL);
    8346                 : #else
    8347                 :   return 0;
    8348                 : #endif
    8349                 : }
    8350                 : 
    8351                 : 
    8352                 : #ifdef MARIA_DUMP_LOG
    8353                 : #include <my_getopt.h>
    8354                 : extern void translog_example_table_init();
    8355                 : static const char *load_default_groups[]= { "maria_dump_log",0 };
    8356                 : static void get_options(int *argc,char * * *argv);
    8357                 : #ifndef DBUG_OFF
    8358                 : #if defined(__WIN__)
    8359                 : const char *default_dbug_option= "d:t:i:O,\\maria_dump_log.trace";
    8360                 : #else
    8361                 : const char *default_dbug_option= "d:t:i:o,/tmp/maria_dump_log.trace";
    8362                 : #endif
    8363                 : #endif
    8364                 : static ulonglong opt_offset;
    8365                 : static ulong opt_pages;
    8366                 : static const char *opt_file= NULL;
    8367                 : static File handler= -1;
    8368                 : static my_bool opt_unit= 0;
    8369                 : static struct my_option my_long_options[] =
    8370                 : {
    8371                 : #ifdef IMPLTMENTED
    8372                 :   {"body", 'b',
    8373                 :    "Print chunk body dump",
    8374                 :    (uchar **) &opt_body, (uchar **) &opt_body, 0,
    8375                 :    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
    8376                 : #endif
    8377                 : #ifndef DBUG_OFF
    8378                 :   {"debug", '#', "Output debug log. Often the argument is 'd:t:o,filename'.",
    8379                 :    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
    8380                 : #endif
    8381                 :   {"file", 'f', "Path to file which will be read",
    8382                 :     (uchar**) &opt_file, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
    8383                 :   {"help", '?', "Display this help and exit.",
    8384                 :    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
    8385                 :   { "offset", 'o', "Start reading log from this offset",
    8386                 :     (uchar**) &opt_offset, (uchar**) &opt_offset,
    8387                 :     0, GET_ULL, REQUIRED_ARG, 0, 0, ~(longlong) 0, 0, 0, 0 },
    8388                 :   { "pages", 'n', "Number of pages to read",
    8389                 :     (uchar**) &opt_pages, (uchar**) &opt_pages, 0,
    8390                 :     GET_ULONG, REQUIRED_ARG, (long) ~(ulong) 0,
    8391                 :     (long) 1, (long) ~(ulong) 0, (long) 0,
    8392                 :     (long) 1, 0},
    8393                 :   {"unit-test", 'U',
    8394                 :    "Use unit test record table (for logs created by unittests",
    8395                 :    (uchar **) &opt_unit, (uchar **) &opt_unit, 0,
    8396                 :    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
    8397                 :   {"version", 'V', "Print version and exit.",
    8398                 :    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
    8399                 :   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
    8400                 : };
    8401                 : 
    8402                 : 
    8403                 : static void print_version(void)
    8404                 : {
    8405                 :   VOID(printf("%s Ver 1.0 for %s on %s\n",
    8406                 :               my_progname_short, SYSTEM_TYPE, MACHINE_TYPE));
    8407                 :   NETWARE_SET_SCREEN_MODE(1);
    8408                 : }
    8409                 : 
    8410                 : 
    8411                 : static void usage(void)
    8412                 : {
    8413                 :   print_version();
    8414                 :   puts("Copyright (C) 2008 MySQL AB");
    8415                 :   puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
    8416                 :   puts("and you are welcome to modify and redistribute it under the GPL license\n");
    8417                 : 
    8418                 :   puts("Dump content of maria log pages.");
    8419                 :   VOID(printf("\nUsage: %s -f file OPTIONS\n", my_progname_short));
    8420                 :   my_print_help(my_long_options);
    8421                 :   print_defaults("my", load_default_groups);
    8422                 :   my_print_variables(my_long_options);
    8423                 : }
    8424                 : 
    8425                 : 
    8426                 : static my_bool
    8427                 : get_one_option(int optid __attribute__((unused)),
    8428                 :                const struct my_option *opt __attribute__((unused)),
    8429                 :                char *argument __attribute__((unused)))
    8430                 : {
    8431                 :   switch (optid) {
    8432                 :   case '?':
    8433                 :     usage();
    8434                 :     exit(0);
    8435                 :   case 'V':
    8436                 :     print_version();
    8437                 :     exit(0);
    8438                 : #ifndef DBUG_OFF
    8439                 :   case '#':
    8440                 :     DBUG_SET_INITIAL(argument ? argument : default_dbug_option);
    8441                 :     break;
    8442                 : #endif
    8443                 :   }
    8444                 :   return 0;
    8445                 : }
    8446                 : 
    8447                 : 
    8448                 : static void get_options(int *argc,char ***argv)
    8449                 : {
    8450                 :   int ho_error;
    8451                 : 
    8452                 :   if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option)))
    8453                 :     exit(ho_error);
    8454                 : 
    8455                 :   if (opt_file == NULL)
    8456                 :   {
    8457                 :     usage();
    8458                 :     exit(1);
    8459                 :   }
    8460                 : }
    8461                 : 
    8462                 : 
    8463                 : /**
    8464                 :   @brief Dump information about file header page.
    8465                 : */
    8466                 : 
    8467                 : static void dump_header_page(uchar *buff)
    8468                 : {
    8469                 :   LOGHANDLER_FILE_INFO desc;
    8470                 :   char strbuff[21];
    8471                 :   translog_interpret_file_header(&desc, buff);
    8472                 :   printf("  This can be header page:\n"
    8473                 :          "    Timestamp: %s\n"
    8474                 :          "    Maria log version: %lu\n"
    8475                 :          "    Server version: %lu\n"
    8476                 :          "    Server id %lu\n"
    8477                 :          "    Page size %lu\n",
    8478                 :          llstr(desc.timestamp, strbuff),
    8479                 :          desc.maria_version,
    8480                 :          desc.mysql_version,
    8481                 :          desc.server_id,
    8482                 :          desc.page_size);
    8483                 :   if (desc.page_size != TRANSLOG_PAGE_SIZE)
    8484                 :     printf("      WARNING: page size is not equal compiled in one %lu!!!\n",
    8485                 :            (ulong) TRANSLOG_PAGE_SIZE);
    8486                 :   printf("    File number %lu\n"
    8487                 :          "    Max lsn: (%lu,0x%lx)\n",
    8488                 :          desc.file_number,
    8489                 :          LSN_IN_PARTS(desc.max_lsn));
    8490                 : }
    8491                 : 
    8492                 : static const char *record_class_string[]=
    8493                 : {
    8494                 :   "LOGRECTYPE_NOT_ALLOWED",
    8495                 :   "LOGRECTYPE_VARIABLE_LENGTH",
    8496                 :   "LOGRECTYPE_PSEUDOFIXEDLENGTH",
    8497                 :   "LOGRECTYPE_FIXEDLENGTH"
    8498                 : };
    8499                 : 
    8500                 : 
    8501                 : /**
    8502                 :   @brief dump information about transaction log chunk
    8503                 : 
    8504                 :   @param buffer          reference to the whole page
    8505                 :   @param ptr             pointer to the chunk
    8506                 : 
    8507                 :   @reval # reference to the next chunk
    8508                 :   @retval NULL can't interpret data
    8509                 : */
    8510                 : 
    8511                 : static uchar *dump_chunk(uchar *buffer, uchar *ptr)
    8512                 : {
    8513                 :   uint length;
    8514                 :   if (*ptr == TRANSLOG_FILLER)
    8515                 :   {
    8516                 :     printf("  Filler till the page end\n");
    8517                 :     for (; ptr < buffer + TRANSLOG_PAGE_SIZE; ptr++)
    8518                 :     {
    8519                 :       if (*ptr != TRANSLOG_FILLER)
    8520                 :       {
    8521                 :         printf("    WARNING: non filler character met before page end "
    8522                 :                "(page + 0x%04x: 0x%02x) (stop interpretation)!!!",
    8523                 :                (uint) (ptr - buffer), (uint) ptr[0]);
    8524                 :         return NULL;
    8525                 :       }
    8526                 :     }
    8527                 :     return ptr;
    8528                 :   }
    8529                 :   if (*ptr == 0 || *ptr == 0xFF)
    8530                 :   {
    8531                 :     printf("    WARNING: chunk can't start from 0x0 "
    8532                 :            "(stop interpretation)!!!\n");
    8533                 :     return NULL;
    8534                 :   }
    8535                 :   switch (ptr[0] & TRANSLOG_CHUNK_TYPE) {
    8536                 :   case TRANSLOG_CHUNK_LSN:
    8537                 :     printf("    LSN chunk type 0 (variable length)\n");
    8538                 :     if (likely((ptr[0] & TRANSLOG_REC_TYPE) != TRANSLOG_CHUNK_0_CONT))
    8539                 :     {
    8540                 :       printf("      Record type %u: %s  record class %s compressed LSNs: %u\n",
    8541                 :              ptr[0] & TRANSLOG_REC_TYPE,
    8542                 :              (log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].name ?
    8543                 :               log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].name :
    8544                 :               "NULL"),
    8545                 :              record_class_string[log_record_type_descriptor[ptr[0] &
    8546                 :                                                             TRANSLOG_REC_TYPE].
    8547                 :                                                             rclass],
    8548                 :              log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].
    8549                 :              compressed_LSN);
    8550                 :       if (log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].rclass !=
    8551                 :           LOGRECTYPE_VARIABLE_LENGTH)
    8552                 :       {
    8553                 :         printf("        WARNING: this record class here can't be used "
    8554                 :                "(stop interpretation)!!!\n");
    8555                 :         break;
    8556                 :       }
    8557                 :     }
    8558                 :     else
    8559                 :       printf("      Continuation of previous chunk 0 header \n");
    8560                 :     printf("      Short transaction id: %u\n", (uint) uint2korr(ptr + 1));
    8561                 :     {
    8562                 :       uchar *hdr_ptr= ptr + 1 + 2; /* chunk type and short trid */
    8563                 :       uint16 chunk_len;
    8564                 :       printf ("      Record length: %lu\n",
    8565                 :               (ulong) translog_variable_record_1group_decode_len(&hdr_ptr));
    8566                 :       chunk_len= uint2korr(hdr_ptr);
    8567                 :       if (chunk_len == 0)
    8568                 :         printf ("      It is 1 group record (chunk length == 0)\n");
    8569                 :       else
    8570                 :       {
    8571                 :         uint16 groups, i;
    8572                 : 
    8573                 :         printf ("      Chunk length %u\n", (uint) chunk_len);
    8574                 :         groups= uint2korr(hdr_ptr + 2);
    8575                 :         hdr_ptr+= 4;
    8576                 :         printf ("      Number of groups left to the end %u:\n", (uint) groups);
    8577                 :         for(i= 0;
    8578                 :             i < groups && hdr_ptr < buffer + TRANSLOG_PAGE_SIZE;
    8579                 :             i++, hdr_ptr+= LSN_STORE_SIZE + 1)
    8580                 :         {
    8581                 :           TRANSLOG_ADDRESS gpr_addr= lsn_korr(hdr_ptr);
    8582                 :           uint pages= hdr_ptr[LSN_STORE_SIZE];
    8583                 :           printf ("        Group +#%u: (%lu,0x%lx)  pages: %u\n",
    8584                 :                   (uint) i, LSN_IN_PARTS(gpr_addr), pages);
    8585                 :         }
    8586                 :       }
    8587                 :     }
    8588                 :     break;
    8589                 :   case TRANSLOG_CHUNK_FIXED:
    8590                 :     printf("    LSN chunk type 1 (fixed size)\n");
    8591                 :     printf("      Record type %u: %s  record class %s compressed LSNs: %u\n",
    8592                 :            ptr[0] & TRANSLOG_REC_TYPE,
    8593                 :            (log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].name ?
    8594                 :             log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].name :
    8595                 :             "NULL"),
    8596                 :            record_class_string[log_record_type_descriptor[ptr[0] &
    8597                 :                                                           TRANSLOG_REC_TYPE].
    8598                 :                                                           rclass],
    8599                 :            log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].
    8600                 :            compressed_LSN);
    8601                 :     if (log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].rclass !=
    8602                 :         LOGRECTYPE_PSEUDOFIXEDLENGTH &&
    8603                 :         log_record_type_descriptor[ptr[0] & TRANSLOG_REC_TYPE].rclass !=
    8604                 :         LOGRECTYPE_FIXEDLENGTH)
    8605                 :     {
    8606                 :       printf("        WARNING: this record class here can't be used "
    8607                 :              "(stop interpretation)!!!\n");
    8608                 :     }
    8609                 :     printf("      Short transaction id: %u\n", (uint) uint2korr(ptr + 1));
    8610                 :     break;
    8611                 :   case TRANSLOG_CHUNK_NOHDR:
    8612                 :     printf("    No header chunk type 2(till the end of the page)\n");
    8613                 :     if (ptr[0] & TRANSLOG_REC_TYPE)
    8614                 :     {
    8615                 :       printf("      WARNING: chunk header content record type: 0x%02x "
    8616                 :              "(dtop interpretation)!!!",
    8617                 :              (uint) ptr[0]);
    8618                 :       return NULL;
    8619                 :     }
    8620                 :     break;
    8621                 :   case TRANSLOG_CHUNK_LNGTH:
    8622                 :     printf("    Chunk with length type 3\n");
    8623                 :     if (ptr[0] & TRANSLOG_REC_TYPE)
    8624                 :     {
    8625                 :       printf("      WARNING: chunk header content record type: 0x%02x "
    8626                 :              "(dtop interpretation)!!!",
    8627                 :              (uint) ptr[0]);
    8628                 :       return NULL;
    8629                 :     }
    8630                 :     break;
    8631                 :   }
    8632                 :   {
    8633                 :     intptr offset= ptr - buffer;
    8634                 :     DBUG_ASSERT(offset >= 0 && offset <= UINT_MAX16);
    8635                 :     length= translog_get_total_chunk_length(buffer, (uint16)offset);
    8636                 :   }
    8637                 :   printf("      Length %u\n", length);
    8638                 :   ptr+= length;
    8639                 :   return ptr;
    8640                 : }
    8641                 : 
    8642                 : 
    8643                 : /**
    8644                 :   @brief Dump information about page with data.
    8645                 : */
    8646                 : 
    8647                 : static void dump_datapage(uchar *buffer)
    8648                 : {
    8649                 :   uchar *ptr;
    8650                 :   ulong offset;
    8651                 :   uint32 page, file;
    8652                 :   uint header_len;
    8653                 :   printf("  Page: %ld  File number: %ld\n",
    8654                 :          (ulong) (page= uint3korr(buffer)),
    8655                 :          (ulong) (file= uint3korr(buffer + 3)));
    8656                 :   if (page == 0)
    8657                 :     printf("    WARNING: page == 0!!!\n");
    8658                 :   if (file == 0)
    8659                 :     printf("    WARNING: file == 0!!!\n");
    8660                 :   offset= page * TRANSLOG_PAGE_SIZE;
    8661                 :   printf("  Flags (0x%x):\n", (uint) buffer[TRANSLOG_PAGE_FLAGS]);
    8662                 :   if (buffer[TRANSLOG_PAGE_FLAGS])
    8663                 :   {
    8664                 :     if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_PAGE_CRC)
    8665                 :       printf("    Page CRC\n");
    8666                 :     if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION)
    8667                 :       printf("    Sector protection\n");
    8668                 :     if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_RECORD_CRC)
    8669                 :       printf("    Record CRC (WARNING: not yet implemented!!!)\n");
    8670                 :     if (buffer[TRANSLOG_PAGE_FLAGS] & ~(TRANSLOG_PAGE_CRC |
    8671                 :                                         TRANSLOG_SECTOR_PROTECTION |
    8672                 :                                         TRANSLOG_RECORD_CRC))
    8673                 :     {
    8674                 :       printf("    WARNING: unknown flags (stop interpretation)!!!\n");
    8675                 :       return;
    8676                 :     }
    8677                 :   }
    8678                 :   else
    8679                 :     printf("    No flags\n");
    8680                 :   printf("  Page header length: %u\n",
    8681                 :          (header_len= page_overhead[buffer[TRANSLOG_PAGE_FLAGS]]));
    8682                 :   if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_RECORD_CRC)
    8683                 :   {
    8684                 :     uint32 crc= uint4korr(buffer + TRANSLOG_PAGE_FLAGS + 1);
    8685                 :     uint32 ccrc;
    8686                 :     printf ("  Page CRC 0x%04lx\n", (ulong) crc);
    8687                 :     ccrc= translog_crc(buffer + header_len, TRANSLOG_PAGE_SIZE - header_len);
    8688                 :     if (crc != ccrc)
    8689                 :       printf("    WARNING: calculated CRC: 0x%04lx!!!\n", (ulong) ccrc);
    8690                 :   }
    8691                 :   if (buffer[TRANSLOG_PAGE_FLAGS] & TRANSLOG_SECTOR_PROTECTION)
    8692                 :   {
    8693                 :     TRANSLOG_FILE tfile;
    8694                 :     {
    8695                 :       uchar *table= buffer + header_len -
    8696                 :         TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE;
    8697                 :       uint i;
    8698                 :       printf("    Sector protection current value: 0x%02x\n", (uint) table[0]);
    8699                 :       for (i= 1; i < TRANSLOG_PAGE_SIZE / DISK_DRIVE_SECTOR_SIZE; i++)
    8700                 :       {
    8701                 :          printf("    Sector protection in sector: 0x%02x  saved value 0x%02x\n",
    8702                 :                 (uint)buffer[i * DISK_DRIVE_SECTOR_SIZE],
    8703                 :                 (uint)table[i]);
    8704                 :       }
    8705                 :     }
    8706                 :     tfile.number= file;
    8707                 :     tfile.handler.file= handler;
    8708                 :     pagecache_file_init(tfile.handler, NULL, NULL, NULL, NULL, NULL);
    8709                 :     tfile.was_recovered= 0;
    8710                 :     tfile.is_sync= 1;
    8711                 :     if (translog_check_sector_protection(buffer, &tfile))
    8712                 :       printf("    WARNING: sector protection found problems!!!\n");
    8713                 :   }
    8714                 :   ptr= buffer + header_len;
    8715                 :   while (ptr && ptr < buffer + TRANSLOG_PAGE_SIZE)
    8716                 :   {
    8717                 :     printf("  Chunk (%lu,0x%lx):\n",
    8718                 :            (ulong)file, (ulong) offset + (ptr - buffer));
    8719                 :     ptr= dump_chunk(buffer, ptr);
    8720                 :   }
    8721                 : }
    8722                 : 
    8723                 : 
    8724                 : /**
    8725                 :   @brief Dump information about page.
    8726                 : */
    8727                 : 
    8728                 : static void dump_page(uchar *buffer)
    8729                 : {
    8730                 :   printf("Page by offset %llu (0x%llx)\n", opt_offset, opt_offset);
    8731                 :   if (strncmp((char*)maria_trans_file_magic, (char*)buffer,
    8732                 :               sizeof(maria_trans_file_magic)) == 0)
    8733                 :   {
    8734                 :     dump_header_page(buffer);
    8735                 :   }
    8736                 :   dump_datapage(buffer);
    8737                 : }
    8738                 : 
    8739                 : 
    8740                 : /**
    8741                 :   @brief maria_dump_log main function.
    8742                 : */
    8743                 : 
    8744                 : int main(int argc, char **argv)
    8745                 : {
    8746                 :   char **default_argv;
    8747                 :   uchar buffer[TRANSLOG_PAGE_SIZE];
    8748                 :   MY_INIT(argv[0]);
    8749                 : 
    8750                 :   load_defaults("my", load_default_groups, &argc, &argv);
    8751                 :   default_argv= argv;
    8752                 :   get_options(&argc, &argv);
    8753                 : 
    8754                 :   if (opt_unit)
    8755                 :     translog_example_table_init();
    8756                 :   else
    8757                 :     translog_table_init();
    8758                 :   translog_fill_overhead_table();
    8759                 : 
    8760                 :   maria_data_root= (char *)".";
    8761                 : 
    8762                 :   if ((handler= my_open(opt_file, O_RDONLY, MYF(MY_WME))) < 0)
    8763                 :   {
    8764                 :     fprintf(stderr, "Can't open file: '%s'  errno: %d\n",
    8765                 :             opt_file, my_errno);
    8766                 :     goto err;
    8767                 :   }
    8768                 :   if (my_seek(handler, opt_offset, SEEK_SET, MYF(MY_WME)) !=
    8769                 :       opt_offset)
    8770                 :   {
    8771                 :      fprintf(stderr, "Can't set position %lld  file: '%s'  errno: %d\n",
    8772                 :              opt_offset, opt_file, my_errno);
    8773                 :      goto err;
    8774                 :   }
    8775                 :   for (;
    8776                 :        opt_pages;
    8777                 :        opt_offset+= TRANSLOG_PAGE_SIZE, opt_pages--)
    8778                 :   {
    8779                 :     if (my_pread(handler, buffer, TRANSLOG_PAGE_SIZE, opt_offset,
    8780                 :                  MYF(MY_NABP)))
    8781                 :     {
    8782                 :       if (my_errno == HA_ERR_FILE_TOO_SHORT)
    8783                 :         goto end;
    8784                 :       fprintf(stderr, "Can't read page at position %lld  file: '%s'  "
    8785                 :               "errno: %d\n", opt_offset, opt_file, my_errno);
    8786                 :       goto err;
    8787                 :     }
    8788                 :     dump_page(buffer);
    8789                 :   }
    8790                 : 
    8791                 : end:
    8792                 :   my_close(handler, MYF(0));
    8793                 :   free_defaults(default_argv);
    8794                 :   exit(0);
    8795                 :   return 0;                             /* No compiler warning */
    8796                 : 
    8797                 : err:
    8798                 :   my_close(handler, MYF(0));
    8799                 :   fprintf(stderr, "%s: FAILED\n", my_progname_short);
    8800                 :   free_defaults(default_argv);
    8801                 :   exit(1);
    8802                 : }
    8803                 : #endif

Generated by: LTP GCOV extension version 1.4