Drizzled Public API Documentation

log0log.cc
00001 /*****************************************************************************
00002 
00003 Copyright (C) 1995, 2010, Innobase Oy. All Rights Reserved.
00004 Copyright (C) 2009 Google Inc.
00005 
00006 Portions of this file contain modifications contributed and copyrighted by
00007 Google, Inc. Those modifications are gratefully acknowledged and are described
00008 briefly in the InnoDB documentation. The contributions by Google are
00009 incorporated with their permission, and subject to the conditions contained in
00010 the file COPYING.Google.
00011 
00012 This program is free software; you can redistribute it and/or modify it under
00013 the terms of the GNU General Public License as published by the Free Software
00014 Foundation; version 2 of the License.
00015 
00016 This program is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00018 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License along with
00021 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
00022 St, Fifth Floor, Boston, MA 02110-1301 USA
00023 
00024 *****************************************************************************/
00025 
00026 /**************************************************/
00033 #include "log0log.h"
00034 
00035 #ifdef UNIV_NONINL
00036 #include "log0log.ic"
00037 #endif
00038 
00039 #ifndef UNIV_HOTBACKUP
00040 #include "mem0mem.h"
00041 #include "buf0buf.h"
00042 #include "buf0flu.h"
00043 #include "srv0srv.h"
00044 #include "log0recv.h"
00045 #include "fil0fil.h"
00046 #include "dict0boot.h"
00047 #include "srv0srv.h"
00048 #include "srv0start.h"
00049 #include "trx0sys.h"
00050 #include "trx0trx.h"
00051 #include "ha_prototypes.h"
00052 
00053 #include <drizzled/errmsg_print.h>
00054 
00055 /*
00056 General philosophy of InnoDB redo-logs:
00057 
00058 1) Every change to a contents of a data page must be done
00059 through mtr, which in mtr_commit() writes log records
00060 to the InnoDB redo log.
00061 
00062 2) Normally these changes are performed using a mlog_write_ulint()
00063 or similar function.
00064 
00065 3) In some page level operations only a code number of a
00066 c-function and its parameters are written to the log to
00067 reduce the size of the log.
00068 
00069   3a) You should not add parameters to these kind of functions
00070   (e.g. trx_undo_header_create(), trx_undo_insert_header_reuse())
00071 
00072   3b) You should not add such functionality which either change
00073   working when compared with the old or are dependent on data
00074   outside of the page. These kind of functions should implement
00075   self-contained page transformation and it should be unchanged
00076   if you don't have very essential reasons to change log
00077   semantics or format.
00078 
00079 */
00080 
00081 /* Current free limit of space 0; protected by the log sys mutex; 0 means
00082 uninitialized */
00083 UNIV_INTERN ulint log_fsp_current_free_limit    = 0;
00084 
00085 /* Global log system variable */
00086 UNIV_INTERN log_t*  log_sys = NULL;
00087 
00088 #ifdef UNIV_PFS_RWLOCK
00089 UNIV_INTERN mysql_pfs_key_t checkpoint_lock_key;
00090 # ifdef UNIV_LOG_ARCHIVE
00091 UNIV_INTERN mysql_pfs_key_t archive_lock_key;
00092 # endif
00093 #endif /* UNIV_PFS_RWLOCK */
00094 
00095 #ifdef UNIV_PFS_MUTEX
00096 UNIV_INTERN mysql_pfs_key_t log_sys_mutex_key;
00097 UNIV_INTERN mysql_pfs_key_t log_flush_order_mutex_key;
00098 #endif /* UNIV_PFS_MUTEX */
00099 
00100 #ifdef UNIV_DEBUG
00101 UNIV_INTERN ibool log_do_write = TRUE;
00102 #endif /* UNIV_DEBUG */
00103 
00104 /* These control how often we print warnings if the last checkpoint is too
00105 old */
00106 UNIV_INTERN ibool log_has_printed_chkp_warning = FALSE;
00107 UNIV_INTERN time_t  log_last_warning_time;
00108 
00109 #ifdef UNIV_LOG_ARCHIVE
00110 /* Pointer to this variable is used as the i/o-message when we do i/o to an
00111 archive */
00112 UNIV_INTERN byte  log_archive_io;
00113 #endif /* UNIV_LOG_ARCHIVE */
00114 
00115 /* A margin for free space in the log buffer before a log entry is catenated */
00116 #define LOG_BUF_WRITE_MARGIN  (4 * OS_FILE_LOG_BLOCK_SIZE)
00117 
00118 /* Margins for free space in the log buffer after a log entry is catenated */
00119 #define LOG_BUF_FLUSH_RATIO 2
00120 #define LOG_BUF_FLUSH_MARGIN  (LOG_BUF_WRITE_MARGIN + 4 * UNIV_PAGE_SIZE)
00121 
00122 /* Margin for the free space in the smallest log group, before a new query
00123 step which modifies the database, is started */
00124 
00125 #define LOG_CHECKPOINT_FREE_PER_THREAD  (4 * UNIV_PAGE_SIZE)
00126 #define LOG_CHECKPOINT_EXTRA_FREE (8 * UNIV_PAGE_SIZE)
00127 
00128 /* This parameter controls asynchronous making of a new checkpoint; the value
00129 should be bigger than LOG_POOL_PREFLUSH_RATIO_SYNC */
00130 
00131 #define LOG_POOL_CHECKPOINT_RATIO_ASYNC 32
00132 
00133 /* This parameter controls synchronous preflushing of modified buffer pages */
00134 #define LOG_POOL_PREFLUSH_RATIO_SYNC  16
00135 
00136 /* The same ratio for asynchronous preflushing; this value should be less than
00137 the previous */
00138 #define LOG_POOL_PREFLUSH_RATIO_ASYNC 8
00139 
00140 /* Extra margin, in addition to one log file, used in archiving */
00141 #define LOG_ARCHIVE_EXTRA_MARGIN  (4 * UNIV_PAGE_SIZE)
00142 
00143 /* This parameter controls asynchronous writing to the archive */
00144 #define LOG_ARCHIVE_RATIO_ASYNC   16
00145 
00146 /* Codes used in unlocking flush latches */
00147 #define LOG_UNLOCK_NONE_FLUSHED_LOCK  1
00148 #define LOG_UNLOCK_FLUSH_LOCK   2
00149 
00150 /* States of an archiving operation */
00151 #define LOG_ARCHIVE_READ  1
00152 #define LOG_ARCHIVE_WRITE 2
00153 
00154 /******************************************************/
00156 static
00157 void
00158 log_io_complete_checkpoint(void);
00159 /*============================*/
00160 #ifdef UNIV_LOG_ARCHIVE
00161 /******************************************************/
00163 static
00164 void
00165 log_io_complete_archive(void);
00166 /*=========================*/
00167 #endif /* UNIV_LOG_ARCHIVE */
00168 
00169 /****************************************************************/
00173 UNIV_INTERN
00174 void
00175 log_fsp_current_free_limit_set_and_checkpoint(
00176 /*==========================================*/
00177   ulint limit)  
00178 {
00179   ibool success;
00180 
00181   mutex_enter(&(log_sys->mutex));
00182 
00183   log_fsp_current_free_limit = limit;
00184 
00185   mutex_exit(&(log_sys->mutex));
00186 
00187   /* Try to make a synchronous checkpoint */
00188 
00189   success = FALSE;
00190 
00191   while (!success) {
00192     success = log_checkpoint(TRUE, TRUE);
00193   }
00194 }
00195 
00196 /****************************************************************/
00200 static
00201 ib_uint64_t
00202 log_buf_pool_get_oldest_modification(void)
00203 /*======================================*/
00204 {
00205   ib_uint64_t lsn;
00206 
00207   ut_ad(mutex_own(&(log_sys->mutex)));
00208 
00209   lsn = buf_pool_get_oldest_modification();
00210 
00211   if (!lsn) {
00212 
00213     lsn = log_sys->lsn;
00214   }
00215 
00216   return(lsn);
00217 }
00218 
00219 /************************************************************/
00223 UNIV_INTERN
00224 ib_uint64_t
00225 log_reserve_and_open(
00226 /*=================*/
00227   ulint len)  
00228 {
00229   log_t*  log     = log_sys;
00230   ulint len_upper_limit;
00231 #ifdef UNIV_LOG_ARCHIVE
00232   ulint archived_lsn_age;
00233   ulint dummy;
00234 #endif /* UNIV_LOG_ARCHIVE */
00235 #ifdef UNIV_DEBUG
00236   ulint count     = 0;
00237 #endif /* UNIV_DEBUG */
00238 
00239   ut_a(len < log->buf_size / 2);
00240 loop:
00241   mutex_enter(&(log->mutex));
00242   ut_ad(!recv_no_log_write);
00243 
00244   /* Calculate an upper limit for the space the string may take in the
00245   log buffer */
00246 
00247   len_upper_limit = LOG_BUF_WRITE_MARGIN + (5 * len) / 4;
00248 
00249   if (log->buf_free + len_upper_limit > log->buf_size) {
00250 
00251     mutex_exit(&(log->mutex));
00252 
00253     /* Not enough free space, do a syncronous flush of the log
00254     buffer */
00255 
00256     log_buffer_flush_to_disk();
00257 
00258     srv_log_waits++;
00259 
00260     ut_ad(++count < 50);
00261 
00262     goto loop;
00263   }
00264 
00265 #ifdef UNIV_LOG_ARCHIVE
00266   if (log->archiving_state != LOG_ARCH_OFF) {
00267 
00268     archived_lsn_age = log->lsn - log->archived_lsn;
00269     if (archived_lsn_age + len_upper_limit
00270         > log->max_archived_lsn_age) {
00271       /* Not enough free archived space in log groups: do a
00272       synchronous archive write batch: */
00273 
00274       mutex_exit(&(log->mutex));
00275 
00276       ut_ad(len_upper_limit <= log->max_archived_lsn_age);
00277 
00278       log_archive_do(TRUE, &dummy);
00279 
00280       ut_ad(++count < 50);
00281 
00282       goto loop;
00283     }
00284   }
00285 #endif /* UNIV_LOG_ARCHIVE */
00286 
00287 #ifdef UNIV_LOG_DEBUG
00288   log->old_buf_free = log->buf_free;
00289   log->old_lsn = log->lsn;
00290 #endif
00291   return(log->lsn);
00292 }
00293 
00294 /************************************************************/
00297 UNIV_INTERN
00298 void
00299 log_write_low(
00300 /*==========*/
00301   byte* str,    
00302   ulint str_len)  
00303 {
00304   log_t*  log = log_sys;
00305   ulint len;
00306   ulint data_len;
00307   byte* log_block;
00308 
00309   ut_ad(mutex_own(&(log->mutex)));
00310 part_loop:
00311   ut_ad(!recv_no_log_write);
00312   /* Calculate a part length */
00313 
00314   data_len = (log->buf_free % OS_FILE_LOG_BLOCK_SIZE) + str_len;
00315 
00316   if (data_len <= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
00317 
00318     /* The string fits within the current log block */
00319 
00320     len = str_len;
00321   } else {
00322     data_len = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE;
00323 
00324     len = OS_FILE_LOG_BLOCK_SIZE
00325       - (log->buf_free % OS_FILE_LOG_BLOCK_SIZE)
00326       - LOG_BLOCK_TRL_SIZE;
00327   }
00328 
00329   ut_memcpy(log->buf + log->buf_free, str, len);
00330 
00331   str_len -= len;
00332   str = str + len;
00333 
00334   log_block = static_cast<unsigned char *>(ut_align_down(log->buf + log->buf_free,
00335         OS_FILE_LOG_BLOCK_SIZE));
00336   log_block_set_data_len(log_block, data_len);
00337 
00338   if (data_len == OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
00339     /* This block became full */
00340     log_block_set_data_len(log_block, OS_FILE_LOG_BLOCK_SIZE);
00341     log_block_set_checkpoint_no(log_block,
00342               log_sys->next_checkpoint_no);
00343     len += LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE;
00344 
00345     log->lsn += len;
00346 
00347     /* Initialize the next block header */
00348     log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, log->lsn);
00349   } else {
00350     log->lsn += len;
00351   }
00352 
00353   log->buf_free += len;
00354 
00355   ut_ad(log->buf_free <= log->buf_size);
00356 
00357   if (str_len > 0) {
00358     goto part_loop;
00359   }
00360 
00361   srv_log_write_requests++;
00362 }
00363 
00364 /************************************************************/
00366 UNIV_INLINE
00367 ulint
00368 log_max_modified_age_async()
00369 /*========================*/
00370 {
00371   if (srv_checkpoint_age_target) {
00372     return(ut_min(log_sys->max_modified_age_async,
00373       srv_checkpoint_age_target
00374       - srv_checkpoint_age_target / 8));
00375   } else {
00376     return(log_sys->max_modified_age_async);
00377   }
00378 }
00379 
00380 /************************************************************/
00382 UNIV_INLINE
00383 ulint
00384 log_max_checkpoint_age_async()
00385 /*==========================*/
00386 {
00387   if (srv_checkpoint_age_target) {
00388     return(ut_min(log_sys->max_checkpoint_age_async,
00389       srv_checkpoint_age_target));
00390   } else {
00391     return(log_sys->max_checkpoint_age_async);
00392   }
00393 }
00394 
00395 
00396 
00397 /************************************************************/
00400 UNIV_INTERN
00401 ib_uint64_t
00402 log_close(void)
00403 /*===========*/
00404 {
00405   byte*   log_block;
00406   ulint   first_rec_group;
00407   ib_uint64_t oldest_lsn;
00408   ib_uint64_t lsn;
00409   log_t*    log = log_sys;
00410   ib_uint64_t checkpoint_age;
00411 
00412   ut_ad(mutex_own(&(log->mutex)));
00413   ut_ad(!recv_no_log_write);
00414 
00415   lsn = log->lsn;
00416 
00417   log_block = static_cast<unsigned char *>(ut_align_down(log->buf + log->buf_free,
00418         OS_FILE_LOG_BLOCK_SIZE));
00419   first_rec_group = log_block_get_first_rec_group(log_block);
00420 
00421   if (first_rec_group == 0) {
00422     /* We initialized a new log block which was not written
00423     full by the current mtr: the next mtr log record group
00424     will start within this block at the offset data_len */
00425 
00426     log_block_set_first_rec_group(
00427       log_block, log_block_get_data_len(log_block));
00428   }
00429 
00430   if (log->buf_free > log->max_buf_free) {
00431 
00432     log->check_flush_or_checkpoint = TRUE;
00433   }
00434 
00435   checkpoint_age = lsn - log->last_checkpoint_lsn;
00436 
00437   if (checkpoint_age >= log->log_group_capacity) {
00438     /* TODO: split btr_store_big_rec_extern_fields() into small
00439     steps so that we can release all latches in the middle, and
00440     call log_free_check() to ensure we never write over log written
00441     after the latest checkpoint. In principle, we should split all
00442     big_rec operations, but other operations are smaller. */
00443 
00444     if (!log_has_printed_chkp_warning
00445         || difftime(time(NULL), log_last_warning_time) > 15) {
00446 
00447       log_has_printed_chkp_warning = TRUE;
00448       log_last_warning_time = time(NULL);
00449 
00450       ut_print_timestamp(stderr);
00451       fprintf(stderr,
00452         "  InnoDB: ERROR: the age of the last"
00453         " checkpoint is %lu,\n"
00454         "InnoDB: which exceeds the log group"
00455         " capacity %lu.\n"
00456         "InnoDB: If you are using big"
00457         " BLOB or TEXT rows, you must set the\n"
00458         "InnoDB: combined size of log files"
00459         " at least 10 times bigger than the\n"
00460         "InnoDB: largest such row.\n",
00461         (ulong) checkpoint_age,
00462         (ulong) log->log_group_capacity);
00463     }
00464   }
00465 
00466   if (checkpoint_age <= log_max_modified_age_async()) {
00467 
00468     goto function_exit;
00469   }
00470 
00471   oldest_lsn = buf_pool_get_oldest_modification();
00472 
00473   if (!oldest_lsn
00474       || lsn - oldest_lsn > log_max_modified_age_async()
00475       || checkpoint_age > log_max_checkpoint_age_async()) {
00476 
00477     log->check_flush_or_checkpoint = TRUE;
00478   }
00479 function_exit:
00480 
00481 #ifdef UNIV_LOG_DEBUG
00482   log_check_log_recs(log->buf + log->old_buf_free,
00483          log->buf_free - log->old_buf_free, log->old_lsn);
00484 #endif
00485 
00486   return(lsn);
00487 }
00488 
00489 #ifdef UNIV_LOG_ARCHIVE
00490 /******************************************************/
00493 static
00494 void
00495 log_pad_current_log_block(void)
00496 /*===========================*/
00497 {
00498   byte    b   = MLOG_DUMMY_RECORD;
00499   ulint   pad_length;
00500   ulint   i;
00501   ib_uint64_t lsn;
00502 
00503   /* We retrieve lsn only because otherwise gcc crashed on HP-UX */
00504   lsn = log_reserve_and_open(OS_FILE_LOG_BLOCK_SIZE);
00505 
00506   pad_length = OS_FILE_LOG_BLOCK_SIZE
00507     - (log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE)
00508     - LOG_BLOCK_TRL_SIZE;
00509 
00510   for (i = 0; i < pad_length; i++) {
00511     log_write_low(&b, 1);
00512   }
00513 
00514   lsn = log_sys->lsn;
00515 
00516   log_close();
00517   log_release();
00518 
00519   ut_a(lsn % OS_FILE_LOG_BLOCK_SIZE == LOG_BLOCK_HDR_SIZE);
00520 }
00521 #endif /* UNIV_LOG_ARCHIVE */
00522 
00523 /******************************************************/
00527 UNIV_INTERN
00528 ulint
00529 log_group_get_capacity(
00530 /*===================*/
00531   const log_group_t*  group)  
00532 {
00533   ut_ad(mutex_own(&(log_sys->mutex)));
00534 
00535   return((group->file_size - LOG_FILE_HDR_SIZE) * group->n_files);
00536 }
00537 
00538 /******************************************************/
00542 UNIV_INLINE
00543 ulint
00544 log_group_calc_size_offset(
00545 /*=======================*/
00546   ulint     offset, 
00548   const log_group_t*  group)  
00549 {
00550   ut_ad(mutex_own(&(log_sys->mutex)));
00551 
00552   return(offset - LOG_FILE_HDR_SIZE * (1 + offset / group->file_size));
00553 }
00554 
00555 /******************************************************/
00559 UNIV_INLINE
00560 ulint
00561 log_group_calc_real_offset(
00562 /*=======================*/
00563   ulint     offset, 
00565   const log_group_t*  group)  
00566 {
00567   ut_ad(mutex_own(&(log_sys->mutex)));
00568 
00569   return(offset + LOG_FILE_HDR_SIZE
00570          * (1 + offset / (group->file_size - LOG_FILE_HDR_SIZE)));
00571 }
00572 
00573 /******************************************************/
00576 static
00577 ulint
00578 log_group_calc_lsn_offset(
00579 /*======================*/
00580   ib_uint64_t   lsn,  
00582   const log_group_t*  group)  
00583 {
00584   ib_uint64_t gr_lsn;
00585   ib_int64_t  gr_lsn_size_offset;
00586   ib_int64_t  difference;
00587   ib_int64_t  group_size;
00588   ib_int64_t  offset;
00589 
00590   ut_ad(mutex_own(&(log_sys->mutex)));
00591 
00592   /* If total log file size is > 2 GB we can easily get overflows
00593   with 32-bit integers. Use 64-bit integers instead. */
00594 
00595   gr_lsn = group->lsn;
00596 
00597   gr_lsn_size_offset = (ib_int64_t)
00598     log_group_calc_size_offset(group->lsn_offset, group);
00599 
00600   group_size = (ib_int64_t) log_group_get_capacity(group);
00601 
00602   if (lsn >= gr_lsn) {
00603 
00604     difference = (ib_int64_t) (lsn - gr_lsn);
00605   } else {
00606     difference = (ib_int64_t) (gr_lsn - lsn);
00607 
00608     difference = difference % group_size;
00609 
00610     difference = group_size - difference;
00611   }
00612 
00613   offset = (gr_lsn_size_offset + difference) % group_size;
00614 
00615   /* Offset must be < 4 GB on 32 bit systems */
00616   ut_a((sizeof(ulint) == 4) || (offset < (((ib_int64_t) 1) << 32)));
00617 
00618   /* fprintf(stderr,
00619   "Offset is %lu gr_lsn_offset is %lu difference is %lu\n",
00620   (ulint)offset,(ulint)gr_lsn_size_offset, (ulint)difference);
00621   */
00622 
00623   return(log_group_calc_real_offset((ulint)offset, group));
00624 }
00625 #endif /* !UNIV_HOTBACKUP */
00626 
00627 #ifdef UNIV_DEBUG
00628 UNIV_INTERN ibool log_debug_writes = FALSE;
00629 #endif /* UNIV_DEBUG */
00630 
00631 /*******************************************************************/
00634 UNIV_INTERN
00635 ulint
00636 log_calc_where_lsn_is(
00637 /*==================*/
00638   ib_int64_t* log_file_offset,  
00640   ib_uint64_t first_header_lsn, 
00642   ib_uint64_t lsn,      
00644   ulint   n_log_files,    
00646   ib_int64_t  log_file_size)    
00648 {
00649   ib_int64_t  capacity  = log_file_size - LOG_FILE_HDR_SIZE;
00650   ulint   file_no;
00651   ib_int64_t  add_this_many;
00652 
00653   if (lsn < first_header_lsn) {
00654     add_this_many = 1 + (first_header_lsn - lsn)
00655       / (capacity * (ib_int64_t)n_log_files);
00656     lsn += add_this_many
00657       * capacity * (ib_int64_t)n_log_files;
00658   }
00659 
00660   ut_a(lsn >= first_header_lsn);
00661 
00662   file_no = ((ulint)((lsn - first_header_lsn) / capacity))
00663     % n_log_files;
00664   *log_file_offset = (lsn - first_header_lsn) % capacity;
00665 
00666   *log_file_offset = *log_file_offset + LOG_FILE_HDR_SIZE;
00667 
00668   return(file_no);
00669 }
00670 
00671 #ifndef UNIV_HOTBACKUP
00672 /********************************************************/
00676 UNIV_INTERN
00677 void
00678 log_group_set_fields(
00679 /*=================*/
00680   log_group_t*  group,  
00681   ib_uint64_t lsn)  
00683 {
00684   group->lsn_offset = log_group_calc_lsn_offset(lsn, group);
00685   group->lsn = lsn;
00686 }
00687 
00688 /*****************************************************************/
00693 static
00694 ibool
00695 log_calc_max_ages(void)
00696 /*===================*/
00697 {
00698   log_group_t*  group;
00699   ulint   margin;
00700   ulint   free;
00701   ibool   success   = TRUE;
00702   ulint   smallest_capacity;
00703   ulint   archive_margin;
00704   ulint   smallest_archive_margin;
00705 
00706   mutex_enter(&(log_sys->mutex));
00707 
00708   group = UT_LIST_GET_FIRST(log_sys->log_groups);
00709 
00710   ut_ad(group);
00711 
00712   smallest_capacity = ULINT_MAX;
00713   smallest_archive_margin = ULINT_MAX;
00714 
00715   while (group) {
00716     if (log_group_get_capacity(group) < smallest_capacity) {
00717 
00718       smallest_capacity = log_group_get_capacity(group);
00719     }
00720 
00721     archive_margin = log_group_get_capacity(group)
00722       - (group->file_size - LOG_FILE_HDR_SIZE)
00723       - LOG_ARCHIVE_EXTRA_MARGIN;
00724 
00725     if (archive_margin < smallest_archive_margin) {
00726 
00727       smallest_archive_margin = archive_margin;
00728     }
00729 
00730     group = UT_LIST_GET_NEXT(log_groups, group);
00731   }
00732 
00733   /* Add extra safety */
00734   smallest_capacity = smallest_capacity - smallest_capacity / 10;
00735 
00736   /* For each OS thread we must reserve so much free space in the
00737   smallest log group that it can accommodate the log entries produced
00738   by single query steps: running out of free log space is a serious
00739   system error which requires rebooting the database. */
00740 
00741   free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency)
00742     + LOG_CHECKPOINT_EXTRA_FREE;
00743   if (free >= smallest_capacity / 2) {
00744     success = FALSE;
00745 
00746     goto failure;
00747   } else {
00748     margin = smallest_capacity - free;
00749   }
00750 
00751   margin = ut_min(margin, log_sys->adm_checkpoint_interval);
00752 
00753   margin = margin - margin / 10;  /* Add still some extra safety */
00754 
00755   log_sys->log_group_capacity = smallest_capacity;
00756 
00757   log_sys->max_modified_age_async = margin
00758     - margin / LOG_POOL_PREFLUSH_RATIO_ASYNC;
00759   log_sys->max_modified_age_sync = margin
00760     - margin / LOG_POOL_PREFLUSH_RATIO_SYNC;
00761 
00762   log_sys->max_checkpoint_age_async = margin - margin
00763     / LOG_POOL_CHECKPOINT_RATIO_ASYNC;
00764   log_sys->max_checkpoint_age = margin;
00765 
00766 #ifdef UNIV_LOG_ARCHIVE
00767   log_sys->max_archived_lsn_age = smallest_archive_margin;
00768 
00769   log_sys->max_archived_lsn_age_async = smallest_archive_margin
00770     - smallest_archive_margin / LOG_ARCHIVE_RATIO_ASYNC;
00771 #endif /* UNIV_LOG_ARCHIVE */
00772 failure:
00773   mutex_exit(&(log_sys->mutex));
00774 
00775   if (!success) {
00776     fprintf(stderr,
00777       "InnoDB: Error: ib_logfiles are too small"
00778       " for innodb_thread_concurrency %lu.\n"
00779       "InnoDB: The combined size of ib_logfiles"
00780       " should be bigger than\n"
00781       "InnoDB: 200 kB * innodb_thread_concurrency.\n"
00782       "InnoDB: To get mysqld to start up, set"
00783       " innodb_thread_concurrency in my.cnf\n"
00784       "InnoDB: to a lower value, for example, to 8."
00785       " After an ERROR-FREE shutdown\n"
00786       "InnoDB: of mysqld you can adjust the size of"
00787       " ib_logfiles, as explained in\n"
00788       "InnoDB: " REFMAN "adding-and-removing.html\n"
00789       "InnoDB: Cannot continue operation."
00790       " Calling exit(1).\n",
00791       (ulong)srv_thread_concurrency);
00792 
00793     exit(1);
00794   }
00795 
00796   return(success);
00797 }
00798 
00799 /******************************************************/
00801 UNIV_INTERN
00802 void
00803 log_init(void)
00804 /*==========*/
00805 {
00806   log_sys = static_cast<log_t *>(mem_alloc(sizeof(log_t)));
00807 
00808   mutex_create(log_sys_mutex_key, &log_sys->mutex, SYNC_LOG);
00809 
00810   mutex_create(log_flush_order_mutex_key,
00811          &log_sys->log_flush_order_mutex,
00812          SYNC_LOG_FLUSH_ORDER);
00813 
00814   mutex_enter(&(log_sys->mutex));
00815 
00816   /* Start the lsn from one log block from zero: this way every
00817   log record has a start lsn != zero, a fact which we will use */
00818 
00819   log_sys->lsn = LOG_START_LSN;
00820 
00821   ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE);
00822   ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE);
00823 
00824   log_sys->buf_ptr = static_cast<unsigned char *>(mem_alloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE));
00825   log_sys->buf = static_cast<unsigned char *>(ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE));
00826 
00827   log_sys->buf_size = LOG_BUFFER_SIZE;
00828 
00829   memset(log_sys->buf, '\0', LOG_BUFFER_SIZE);
00830 
00831   log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO
00832     - LOG_BUF_FLUSH_MARGIN;
00833   log_sys->check_flush_or_checkpoint = TRUE;
00834   UT_LIST_INIT(log_sys->log_groups);
00835 
00836   log_sys->n_log_ios = 0;
00837 
00838   log_sys->n_log_ios_old = log_sys->n_log_ios;
00839   log_sys->last_printout_time = time(NULL);
00840   /*----------------------------*/
00841 
00842   log_sys->buf_next_to_write = 0;
00843 
00844   log_sys->write_lsn = 0;
00845   log_sys->current_flush_lsn = 0;
00846   log_sys->flushed_to_disk_lsn = 0;
00847 
00848   log_sys->written_to_some_lsn = log_sys->lsn;
00849   log_sys->written_to_all_lsn = log_sys->lsn;
00850 
00851   log_sys->n_pending_writes = 0;
00852 
00853   log_sys->no_flush_event = os_event_create(NULL);
00854 
00855   os_event_set(log_sys->no_flush_event);
00856 
00857   log_sys->one_flushed_event = os_event_create(NULL);
00858 
00859   os_event_set(log_sys->one_flushed_event);
00860 
00861   /*----------------------------*/
00862   log_sys->adm_checkpoint_interval = ULINT_MAX;
00863 
00864   log_sys->next_checkpoint_no = 0;
00865   log_sys->last_checkpoint_lsn = log_sys->lsn;
00866   log_sys->n_pending_checkpoint_writes = 0;
00867 
00868   rw_lock_create(checkpoint_lock_key, &log_sys->checkpoint_lock,
00869            SYNC_NO_ORDER_CHECK);
00870 
00871   log_sys->checkpoint_buf_ptr = static_cast<unsigned char *>(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE));
00872   log_sys->checkpoint_buf = static_cast<unsigned char *>(ut_align(log_sys->checkpoint_buf_ptr,
00873         OS_FILE_LOG_BLOCK_SIZE));
00874   memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
00875   /*----------------------------*/
00876 
00877 #ifdef UNIV_LOG_ARCHIVE
00878   /* Under MySQL, log archiving is always off */
00879   log_sys->archiving_state = LOG_ARCH_OFF;
00880   log_sys->archived_lsn = log_sys->lsn;
00881   log_sys->next_archived_lsn = 0;
00882 
00883   log_sys->n_pending_archive_ios = 0;
00884 
00885   rw_lock_create(archive_lock_key, &log_sys->archive_lock,
00886            SYNC_NO_ORDER_CHECK);
00887 
00888   log_sys->archive_buf = NULL;
00889 
00890   /* ut_align(
00891   ut_malloc(LOG_ARCHIVE_BUF_SIZE
00892   + OS_FILE_LOG_BLOCK_SIZE),
00893   OS_FILE_LOG_BLOCK_SIZE); */
00894   log_sys->archive_buf_size = 0;
00895 
00896   /* memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE); */
00897 
00898   log_sys->archiving_on = os_event_create(NULL);
00899 #endif /* UNIV_LOG_ARCHIVE */
00900 
00901   /*----------------------------*/
00902 
00903   log_block_init(log_sys->buf, log_sys->lsn);
00904   log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE);
00905 
00906   log_sys->buf_free = LOG_BLOCK_HDR_SIZE;
00907   log_sys->lsn = LOG_START_LSN + LOG_BLOCK_HDR_SIZE;
00908 
00909   mutex_exit(&(log_sys->mutex));
00910 
00911 #ifdef UNIV_LOG_DEBUG
00912   recv_sys_create();
00913   recv_sys_init(buf_pool_get_curr_size());
00914 
00915   recv_sys->parse_start_lsn = log_sys->lsn;
00916   recv_sys->scanned_lsn = log_sys->lsn;
00917   recv_sys->scanned_checkpoint_no = 0;
00918   recv_sys->recovered_lsn = log_sys->lsn;
00919   recv_sys->limit_lsn = IB_ULONGLONG_MAX;
00920 #endif
00921 }
00922 
00923 /******************************************************************/
00925 UNIV_INTERN
00926 void
00927 log_group_init(
00928 /*===========*/
00929   ulint id,     
00930   ulint n_files,    
00931   ulint file_size,    
00932   ulint space_id,   
00935   ulint /*archive_space_id __attribute__((unused))*/)
00941 {
00942   ulint i;
00943 
00944   log_group_t*  group;
00945 
00946   group = static_cast<log_group_t *>(mem_alloc(sizeof(log_group_t)));
00947 
00948   group->id = id;
00949   group->n_files = n_files;
00950   group->file_size = file_size;
00951   group->space_id = space_id;
00952   group->state = LOG_GROUP_OK;
00953   group->lsn = LOG_START_LSN;
00954   group->lsn_offset = LOG_FILE_HDR_SIZE;
00955   group->n_pending_writes = 0;
00956 
00957   group->file_header_bufs_ptr = static_cast<unsigned char **>(mem_alloc(sizeof(byte*) * n_files));
00958   group->file_header_bufs = static_cast<unsigned char **>(mem_alloc(sizeof(byte*) * n_files));
00959 #ifdef UNIV_LOG_ARCHIVE
00960   group->archive_file_header_bufs_ptr = mem_alloc(
00961     sizeof(byte*) * n_files);
00962   group->archive_file_header_bufs = mem_alloc(sizeof(byte*) * n_files);
00963 #endif /* UNIV_LOG_ARCHIVE */
00964 
00965   for (i = 0; i < n_files; i++) {
00966     group->file_header_bufs_ptr[i] = static_cast<unsigned char *>(mem_alloc(
00967       LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE));
00968 
00969     group->file_header_bufs[i] = static_cast<unsigned char *>(ut_align(
00970       group->file_header_bufs_ptr[i],
00971       OS_FILE_LOG_BLOCK_SIZE));
00972 
00973     memset(*(group->file_header_bufs + i), '\0',
00974            LOG_FILE_HDR_SIZE);
00975 
00976 #ifdef UNIV_LOG_ARCHIVE
00977     group->archive_file_header_bufs_ptr[i] = mem_alloc(
00978       LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
00979 
00980     group->archive_file_header_bufs[i] = ut_align(
00981       group->archive_file_header_bufs_ptr[i],
00982       OS_FILE_LOG_BLOCK_SIZE);
00983 
00984     memset(*(group->archive_file_header_bufs + i), '\0',
00985            LOG_FILE_HDR_SIZE);
00986 #endif /* UNIV_LOG_ARCHIVE */
00987   }
00988 
00989 #ifdef UNIV_LOG_ARCHIVE
00990   group->archive_space_id = archive_space_id;
00991 
00992   group->archived_file_no = 0;
00993   group->archived_offset = 0;
00994 #endif /* UNIV_LOG_ARCHIVE */
00995 
00996   group->checkpoint_buf_ptr = static_cast<unsigned char *>(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE));
00997   group->checkpoint_buf = static_cast<unsigned char*>(ut_align(group->checkpoint_buf_ptr,
00998            OS_FILE_LOG_BLOCK_SIZE));
00999 
01000   memset(group->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
01001 
01002   UT_LIST_ADD_LAST(log_groups, log_sys->log_groups, group);
01003 
01004   ut_a(log_calc_max_ages());
01005 }
01006 
01007 /******************************************************************/
01009 UNIV_INLINE
01010 void
01011 log_flush_do_unlocks(
01012 /*=================*/
01013   ulint code) 
01015 {
01016   ut_ad(mutex_own(&(log_sys->mutex)));
01017 
01018   /* NOTE that we must own the log mutex when doing the setting of the
01019   events: this is because transactions will wait for these events to
01020   be set, and at that moment the log flush they were waiting for must
01021   have ended. If the log mutex were not reserved here, the i/o-thread
01022   calling this function might be preempted for a while, and when it
01023   resumed execution, it might be that a new flush had been started, and
01024   this function would erroneously signal the NEW flush as completed.
01025   Thus, the changes in the state of these events are performed
01026   atomically in conjunction with the changes in the state of
01027   log_sys->n_pending_writes etc. */
01028 
01029   if (code & LOG_UNLOCK_NONE_FLUSHED_LOCK) {
01030     os_event_set(log_sys->one_flushed_event);
01031   }
01032 
01033   if (code & LOG_UNLOCK_FLUSH_LOCK) {
01034     os_event_set(log_sys->no_flush_event);
01035   }
01036 }
01037 
01038 /******************************************************************/
01042 UNIV_INLINE
01043 ulint
01044 log_group_check_flush_completion(
01045 /*=============================*/
01046   log_group_t*  group)  
01047 {
01048   ut_ad(mutex_own(&(log_sys->mutex)));
01049 
01050   if (!log_sys->one_flushed && group->n_pending_writes == 0) {
01051 #ifdef UNIV_DEBUG
01052     if (log_debug_writes) {
01053       fprintf(stderr,
01054         "Log flushed first to group %lu\n",
01055         (ulong) group->id);
01056     }
01057 #endif /* UNIV_DEBUG */
01058     log_sys->written_to_some_lsn = log_sys->write_lsn;
01059     log_sys->one_flushed = TRUE;
01060 
01061     return(LOG_UNLOCK_NONE_FLUSHED_LOCK);
01062   }
01063 
01064 #ifdef UNIV_DEBUG
01065   if (log_debug_writes && (group->n_pending_writes == 0)) {
01066 
01067     fprintf(stderr, "Log flushed to group %lu\n",
01068       (ulong) group->id);
01069   }
01070 #endif /* UNIV_DEBUG */
01071   return(0);
01072 }
01073 
01074 /******************************************************/
01077 static
01078 ulint
01079 log_sys_check_flush_completion(void)
01080 /*================================*/
01081 {
01082   ulint move_start;
01083   ulint move_end;
01084 
01085   ut_ad(mutex_own(&(log_sys->mutex)));
01086 
01087   if (log_sys->n_pending_writes == 0) {
01088 
01089     log_sys->written_to_all_lsn = log_sys->write_lsn;
01090     log_sys->buf_next_to_write = log_sys->write_end_offset;
01091 
01092     if (log_sys->write_end_offset > log_sys->max_buf_free / 2) {
01093       /* Move the log buffer content to the start of the
01094       buffer */
01095 
01096       move_start = ut_calc_align_down(
01097         log_sys->write_end_offset,
01098         OS_FILE_LOG_BLOCK_SIZE);
01099       move_end = ut_calc_align(log_sys->buf_free,
01100              OS_FILE_LOG_BLOCK_SIZE);
01101 
01102       ut_memmove(log_sys->buf, log_sys->buf + move_start,
01103            move_end - move_start);
01104       log_sys->buf_free -= move_start;
01105 
01106       log_sys->buf_next_to_write -= move_start;
01107     }
01108 
01109     return(LOG_UNLOCK_FLUSH_LOCK);
01110   }
01111 
01112   return(0);
01113 }
01114 
01115 /******************************************************/
01117 UNIV_INTERN
01118 void
01119 log_io_complete(
01120 /*============*/
01121   log_group_t*  group)  
01122 {
01123   ulint unlock;
01124 
01125 #ifdef UNIV_LOG_ARCHIVE
01126   if ((byte*)group == &log_archive_io) {
01127     /* It was an archive write */
01128 
01129     log_io_complete_archive();
01130 
01131     return;
01132   }
01133 #endif /* UNIV_LOG_ARCHIVE */
01134 
01135   if ((ulint)group & 0x1UL) {
01136     /* It was a checkpoint write */
01137     group = (log_group_t*)((ulint)group - 1);
01138 
01139     if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
01140         && srv_unix_file_flush_method != SRV_UNIX_ALL_O_DIRECT
01141         && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) {
01142 
01143       fil_flush(group->space_id);
01144     }
01145 
01146 #ifdef UNIV_DEBUG
01147     if (log_debug_writes) {
01148       fprintf(stderr,
01149         "Checkpoint info written to group %lu\n",
01150         group->id);
01151     }
01152 #endif /* UNIV_DEBUG */
01153     log_io_complete_checkpoint();
01154 
01155     return;
01156   }
01157 
01158   ut_error; 
01161   if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
01162       && srv_unix_file_flush_method != SRV_UNIX_ALL_O_DIRECT
01163       && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
01164       && srv_flush_log_at_trx_commit != 2) {
01165 
01166     fil_flush(group->space_id);
01167   }
01168 
01169   mutex_enter(&(log_sys->mutex));
01170   ut_ad(!recv_no_log_write);
01171 
01172   ut_a(group->n_pending_writes > 0);
01173   ut_a(log_sys->n_pending_writes > 0);
01174 
01175   group->n_pending_writes--;
01176   log_sys->n_pending_writes--;
01177 
01178   unlock = log_group_check_flush_completion(group);
01179   unlock = unlock | log_sys_check_flush_completion();
01180 
01181   log_flush_do_unlocks(unlock);
01182 
01183   mutex_exit(&(log_sys->mutex));
01184 }
01185 
01186 /******************************************************/
01188 static
01189 void
01190 log_group_file_header_flush(
01191 /*========================*/
01192   log_group_t*  group,    
01193   ulint   nth_file, 
01195   ib_uint64_t start_lsn)  
01197 {
01198   byte* buf;
01199   ulint dest_offset;
01200 
01201   ut_ad(mutex_own(&(log_sys->mutex)));
01202   ut_ad(!recv_no_log_write);
01203   ut_a(nth_file < group->n_files);
01204 
01205   buf = *(group->file_header_bufs + nth_file);
01206 
01207   mach_write_to_4(buf + LOG_GROUP_ID, group->id);
01208   mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn);
01209 
01210   /* Wipe over possible label of ibbackup --restore */
01211   memcpy(buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, "    ", 4);
01212 
01213   mach_write_to_4(buf + LOG_FILE_OS_FILE_LOG_BLOCK_SIZE,
01214       srv_log_block_size);
01215 
01216   dest_offset = nth_file * group->file_size;
01217 
01218 #ifdef UNIV_DEBUG
01219   if (log_debug_writes) {
01220     fprintf(stderr,
01221       "Writing log file header to group %lu file %lu\n",
01222       (ulong) group->id, (ulong) nth_file);
01223   }
01224 #endif /* UNIV_DEBUG */
01225   if (log_do_write) {
01226     log_sys->n_log_ios++;
01227 
01228     srv_os_log_pending_writes++;
01229 
01230     fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id, 0,
01231            dest_offset / UNIV_PAGE_SIZE,
01232            dest_offset % UNIV_PAGE_SIZE,
01233            OS_FILE_LOG_BLOCK_SIZE,
01234            buf, group);
01235 
01236     srv_os_log_pending_writes--;
01237   }
01238 }
01239 
01240 /******************************************************/
01244 static
01245 void
01246 log_block_store_checksum(
01247 /*=====================*/
01248   byte* block)  
01249 {
01250   log_block_set_checksum(block, log_block_calc_checksum(block));
01251 }
01252 
01253 /******************************************************/
01255 UNIV_INTERN
01256 void
01257 log_group_write_buf(
01258 /*================*/
01259   log_group_t*  group,    
01260   byte*   buf,    
01261   ulint   len,    
01263   ib_uint64_t start_lsn,  
01266   ulint   new_data_offset)
01270 {
01271   ulint write_len;
01272   ibool write_header;
01273   ulint next_offset;
01274   ulint i;
01275 
01276   ut_ad(mutex_own(&(log_sys->mutex)));
01277   ut_ad(!recv_no_log_write);
01278   ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0);
01279   ut_a(((ulint) start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
01280 
01281   if (new_data_offset == 0) {
01282     write_header = TRUE;
01283   } else {
01284     write_header = FALSE;
01285   }
01286 loop:
01287   if (len == 0) {
01288 
01289     return;
01290   }
01291 
01292   next_offset = log_group_calc_lsn_offset(start_lsn, group);
01293 
01294   if ((next_offset % group->file_size == LOG_FILE_HDR_SIZE)
01295       && write_header) {
01296     /* We start to write a new log file instance in the group */
01297 
01298     log_group_file_header_flush(group,
01299               next_offset / group->file_size,
01300               start_lsn);
01301     srv_os_log_written+= OS_FILE_LOG_BLOCK_SIZE;
01302     srv_log_writes++;
01303   }
01304 
01305   if ((next_offset % group->file_size) + len > group->file_size) {
01306 
01307     write_len = group->file_size
01308       - (next_offset % group->file_size);
01309   } else {
01310     write_len = len;
01311   }
01312 
01313 #ifdef UNIV_DEBUG
01314   if (log_debug_writes) {
01315 
01316     fprintf(stderr,
01317       "Writing log file segment to group %lu"
01318       " offset %lu len %lu\n"
01319       "start lsn %"PRIu64"\n"
01320       "First block n:o %lu last block n:o %lu\n",
01321       (ulong) group->id, (ulong) next_offset,
01322       (ulong) write_len,
01323       start_lsn,
01324       (ulong) log_block_get_hdr_no(buf),
01325       (ulong) log_block_get_hdr_no(
01326         buf + write_len - OS_FILE_LOG_BLOCK_SIZE));
01327     ut_a(log_block_get_hdr_no(buf)
01328          == log_block_convert_lsn_to_no(start_lsn));
01329 
01330     for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) {
01331 
01332       ut_a(log_block_get_hdr_no(buf) + i
01333            == log_block_get_hdr_no(
01334              buf + i * OS_FILE_LOG_BLOCK_SIZE));
01335     }
01336   }
01337 #endif /* UNIV_DEBUG */
01338   /* Calculate the checksums for each log block and write them to
01339   the trailer fields of the log blocks */
01340 
01341   for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) {
01342     log_block_store_checksum(buf + i * OS_FILE_LOG_BLOCK_SIZE);
01343   }
01344 
01345   if (log_do_write) {
01346     log_sys->n_log_ios++;
01347 
01348     srv_os_log_pending_writes++;
01349 
01350     fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id, 0,
01351            next_offset / UNIV_PAGE_SIZE,
01352            next_offset % UNIV_PAGE_SIZE, write_len, buf, group);
01353 
01354     srv_os_log_pending_writes--;
01355 
01356     srv_os_log_written+= write_len;
01357     srv_log_writes++;
01358   }
01359 
01360   if (write_len < len) {
01361     start_lsn += write_len;
01362     len -= write_len;
01363     buf += write_len;
01364 
01365     write_header = TRUE;
01366 
01367     goto loop;
01368   }
01369 }
01370 
01371 /******************************************************/
01376 UNIV_INTERN
01377 void
01378 log_write_up_to(
01379 /*============*/
01380   ib_uint64_t lsn,  
01383   ulint   wait, 
01385   ibool   flush_to_disk)
01388 {
01389   log_group_t*  group;
01390   ulint   start_offset;
01391   ulint   end_offset;
01392   ulint   area_start;
01393   ulint   area_end;
01394 #ifdef UNIV_DEBUG
01395   ulint   loop_count  = 0;
01396 #endif /* UNIV_DEBUG */
01397   ulint   unlock;
01398 
01399   if (recv_no_ibuf_operations || srv_fake_write) {
01400     /* Recovery is running and no operations on the log files are
01401     allowed yet (the variable name .._no_ibuf_.. is misleading) */
01402 
01403     return;
01404   }
01405 
01406 loop:
01407 #ifdef UNIV_DEBUG
01408   loop_count++;
01409 
01410   ut_ad(loop_count < 5);
01411 
01412 # if 0
01413   if (loop_count > 2) {
01414     fprintf(stderr, "Log loop count %lu\n", loop_count);
01415   }
01416 # endif
01417 #endif
01418 
01419   mutex_enter(&(log_sys->mutex));
01420   ut_ad(!recv_no_log_write);
01421 
01422   if (flush_to_disk
01423       && log_sys->flushed_to_disk_lsn >= lsn) {
01424 
01425     mutex_exit(&(log_sys->mutex));
01426 
01427     return;
01428   }
01429 
01430   if (!flush_to_disk
01431       && (log_sys->written_to_all_lsn >= lsn
01432     || (log_sys->written_to_some_lsn >= lsn
01433         && wait != LOG_WAIT_ALL_GROUPS))) {
01434 
01435     mutex_exit(&(log_sys->mutex));
01436 
01437     return;
01438   }
01439 
01440   if (log_sys->n_pending_writes > 0) {
01441     /* A write (+ possibly flush to disk) is running */
01442 
01443     if (flush_to_disk
01444         && log_sys->current_flush_lsn >= lsn) {
01445       /* The write + flush will write enough: wait for it to
01446       complete  */
01447 
01448       goto do_waits;
01449     }
01450 
01451     if (!flush_to_disk
01452         && log_sys->write_lsn >= lsn) {
01453       /* The write will write enough: wait for it to
01454       complete  */
01455 
01456       goto do_waits;
01457     }
01458 
01459     mutex_exit(&(log_sys->mutex));
01460 
01461     /* Wait for the write to complete and try to start a new
01462     write */
01463 
01464     os_event_wait(log_sys->no_flush_event);
01465 
01466     goto loop;
01467   }
01468 
01469   if (!flush_to_disk
01470       && log_sys->buf_free == log_sys->buf_next_to_write) {
01471     /* Nothing to write and no flush to disk requested */
01472 
01473     mutex_exit(&(log_sys->mutex));
01474 
01475     return;
01476   }
01477 
01478 #ifdef UNIV_DEBUG
01479   if (log_debug_writes) {
01480     fprintf(stderr,
01481       "Writing log from %"PRIu64" up to lsn %"PRIu64"\n",
01482       log_sys->written_to_all_lsn,
01483       log_sys->lsn);
01484   }
01485 #endif /* UNIV_DEBUG */
01486   log_sys->n_pending_writes++;
01487 
01488   group = UT_LIST_GET_FIRST(log_sys->log_groups);
01489   group->n_pending_writes++;  
01492   os_event_reset(log_sys->no_flush_event);
01493   os_event_reset(log_sys->one_flushed_event);
01494 
01495   start_offset = log_sys->buf_next_to_write;
01496   end_offset = log_sys->buf_free;
01497 
01498   area_start = ut_calc_align_down(start_offset, OS_FILE_LOG_BLOCK_SIZE);
01499   area_end = ut_calc_align(end_offset, OS_FILE_LOG_BLOCK_SIZE);
01500 
01501   ut_ad(area_end - area_start > 0);
01502 
01503   log_sys->write_lsn = log_sys->lsn;
01504 
01505   if (flush_to_disk) {
01506     log_sys->current_flush_lsn = log_sys->lsn;
01507   }
01508 
01509   log_sys->one_flushed = FALSE;
01510 
01511   log_block_set_flush_bit(log_sys->buf + area_start, TRUE);
01512   log_block_set_checkpoint_no(
01513     log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
01514     log_sys->next_checkpoint_no);
01515 
01516   /* Copy the last, incompletely written, log block a log block length
01517   up, so that when the flush operation writes from the log buffer, the
01518   segment to write will not be changed by writers to the log */
01519 
01520   ut_memcpy(log_sys->buf + area_end,
01521       log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
01522       OS_FILE_LOG_BLOCK_SIZE);
01523 
01524   log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE;
01525   log_sys->write_end_offset = log_sys->buf_free;
01526 
01527   group = UT_LIST_GET_FIRST(log_sys->log_groups);
01528 
01529   /* Do the write to the log files */
01530 
01531   while (group) {
01532     log_group_write_buf(
01533       group, log_sys->buf + area_start,
01534       area_end - area_start,
01535       ut_uint64_align_down(log_sys->written_to_all_lsn,
01536                OS_FILE_LOG_BLOCK_SIZE),
01537       start_offset - area_start);
01538 
01539     log_group_set_fields(group, log_sys->write_lsn);
01540 
01541     group = UT_LIST_GET_NEXT(log_groups, group);
01542   }
01543 
01544   mutex_exit(&(log_sys->mutex));
01545 
01546   if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC
01547       || srv_unix_file_flush_method == SRV_UNIX_ALL_O_DIRECT) {
01548     /* O_DSYNC means the OS did not buffer the log file at all:
01549     so we have also flushed to disk what we have written */
01550 
01551     log_sys->flushed_to_disk_lsn = log_sys->write_lsn;
01552 
01553   } else if (flush_to_disk) {
01554 
01555     group = UT_LIST_GET_FIRST(log_sys->log_groups);
01556 
01557     fil_flush(group->space_id);
01558     log_sys->flushed_to_disk_lsn = log_sys->write_lsn;
01559   }
01560 
01561   mutex_enter(&(log_sys->mutex));
01562 
01563   group = UT_LIST_GET_FIRST(log_sys->log_groups);
01564 
01565   ut_a(group->n_pending_writes == 1);
01566   ut_a(log_sys->n_pending_writes == 1);
01567 
01568   group->n_pending_writes--;
01569   log_sys->n_pending_writes--;
01570 
01571   unlock = log_group_check_flush_completion(group);
01572   unlock = unlock | log_sys_check_flush_completion();
01573 
01574   log_flush_do_unlocks(unlock);
01575 
01576   mutex_exit(&(log_sys->mutex));
01577 
01578   return;
01579 
01580 do_waits:
01581   mutex_exit(&(log_sys->mutex));
01582 
01583   switch (wait) {
01584   case LOG_WAIT_ONE_GROUP:
01585     os_event_wait(log_sys->one_flushed_event);
01586     break;
01587   case LOG_WAIT_ALL_GROUPS:
01588     os_event_wait(log_sys->no_flush_event);
01589     break;
01590 #ifdef UNIV_DEBUG
01591   case LOG_NO_WAIT:
01592     break;
01593   default:
01594     ut_error;
01595 #endif /* UNIV_DEBUG */
01596   }
01597 }
01598 
01599 /****************************************************************/
01601 UNIV_INTERN
01602 void
01603 log_buffer_flush_to_disk(void)
01604 /*==========================*/
01605 {
01606   ib_uint64_t lsn;
01607 
01608   mutex_enter(&(log_sys->mutex));
01609 
01610   lsn = log_sys->lsn;
01611 
01612   mutex_exit(&(log_sys->mutex));
01613 
01614   log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, TRUE);
01615 }
01616 
01617 /****************************************************************/
01622 UNIV_INTERN
01623 void
01624 log_buffer_sync_in_background(
01625 /*==========================*/
01626   ibool flush)  
01627 {
01628   ib_uint64_t lsn;
01629 
01630   mutex_enter(&(log_sys->mutex));
01631 
01632   lsn = log_sys->lsn;
01633 
01634   mutex_exit(&(log_sys->mutex));
01635 
01636   log_write_up_to(lsn, LOG_NO_WAIT, flush);
01637 }
01638 
01639 /********************************************************************
01640 
01641 Tries to establish a big enough margin of free space in the log buffer, such
01642 that a new log entry can be catenated without an immediate need for a flush. */
01643 static
01644 void
01645 log_flush_margin(void)
01646 /*==================*/
01647 {
01648   log_t*    log = log_sys;
01649   ib_uint64_t lsn = 0;
01650 
01651   mutex_enter(&(log->mutex));
01652 
01653   if (log->buf_free > log->max_buf_free) {
01654 
01655     if (log->n_pending_writes > 0) {
01656       /* A flush is running: hope that it will provide enough
01657       free space */
01658     } else {
01659       lsn = log->lsn;
01660     }
01661   }
01662 
01663   mutex_exit(&(log->mutex));
01664 
01665   if (lsn) {
01666     log_write_up_to(lsn, LOG_NO_WAIT, FALSE);
01667   }
01668 }
01669 
01670 /****************************************************************/
01676 UNIV_INTERN
01677 ibool
01678 log_preflush_pool_modified_pages(
01679 /*=============================*/
01680   ib_uint64_t new_oldest, 
01683   ibool   sync)   
01685 {
01686   ulint n_pages;
01687 
01688   if (recv_recovery_on) {
01689     /* If the recovery is running, we must first apply all
01690     log records to their respective file pages to get the
01691     right modify lsn values to these pages: otherwise, there
01692     might be pages on disk which are not yet recovered to the
01693     current lsn, and even after calling this function, we could
01694     not know how up-to-date the disk version of the database is,
01695     and we could not make a new checkpoint on the basis of the
01696     info on the buffer pool only. */
01697 
01698     recv_apply_hashed_log_recs(TRUE);
01699   }
01700 
01701   n_pages = buf_flush_list(ULINT_MAX, new_oldest);
01702 
01703   if (sync) {
01704     buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
01705   }
01706 
01707   if (n_pages == ULINT_UNDEFINED) {
01708 
01709     return(FALSE);
01710   }
01711 
01712   return(TRUE);
01713 }
01714 
01715 /******************************************************/
01717 static
01718 void
01719 log_complete_checkpoint(void)
01720 /*=========================*/
01721 {
01722   ut_ad(mutex_own(&(log_sys->mutex)));
01723   ut_ad(log_sys->n_pending_checkpoint_writes == 0);
01724 
01725   log_sys->next_checkpoint_no++;
01726 
01727   log_sys->last_checkpoint_lsn = log_sys->next_checkpoint_lsn;
01728 
01729   rw_lock_x_unlock_gen(&(log_sys->checkpoint_lock), LOG_CHECKPOINT);
01730 }
01731 
01732 /******************************************************/
01734 static
01735 void
01736 log_io_complete_checkpoint(void)
01737 /*============================*/
01738 {
01739   mutex_enter(&(log_sys->mutex));
01740 
01741   ut_ad(log_sys->n_pending_checkpoint_writes > 0);
01742 
01743   log_sys->n_pending_checkpoint_writes--;
01744 
01745   if (log_sys->n_pending_checkpoint_writes == 0) {
01746     log_complete_checkpoint();
01747   }
01748 
01749   mutex_exit(&(log_sys->mutex));
01750 }
01751 
01752 /*******************************************************************/
01754 static
01755 void
01756 log_checkpoint_set_nth_group_info(
01757 /*==============================*/
01758   byte* buf,  
01759   ulint n,  
01760   ulint file_no,
01761   ulint offset) 
01762 {
01763   ut_ad(n < LOG_MAX_N_GROUPS);
01764 
01765   mach_write_to_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
01766       + 8 * n + LOG_CHECKPOINT_ARCHIVED_FILE_NO, file_no);
01767   mach_write_to_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
01768       + 8 * n + LOG_CHECKPOINT_ARCHIVED_OFFSET, offset);
01769 }
01770 
01771 /*******************************************************************/
01773 UNIV_INTERN
01774 void
01775 log_checkpoint_get_nth_group_info(
01776 /*==============================*/
01777   const byte* buf,  
01778   ulint   n,  
01779   ulint*    file_no,
01780   ulint*    offset) 
01781 {
01782   ut_ad(n < LOG_MAX_N_GROUPS);
01783 
01784   *file_no = mach_read_from_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
01785             + 8 * n + LOG_CHECKPOINT_ARCHIVED_FILE_NO);
01786   *offset = mach_read_from_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
01787            + 8 * n + LOG_CHECKPOINT_ARCHIVED_OFFSET);
01788 }
01789 
01790 /******************************************************/
01792 static
01793 void
01794 log_group_checkpoint(
01795 /*=================*/
01796   log_group_t*  group)  
01797 {
01798   log_group_t*  group2;
01799 #ifdef UNIV_LOG_ARCHIVE
01800   ib_uint64_t archived_lsn;
01801   ib_uint64_t next_archived_lsn;
01802 #endif /* UNIV_LOG_ARCHIVE */
01803   ulint   write_offset;
01804   ulint   fold;
01805   byte*   buf;
01806   ulint   i;
01807 
01808   ut_ad(mutex_own(&(log_sys->mutex)));
01809   ut_a(LOG_CHECKPOINT_SIZE <= OS_FILE_LOG_BLOCK_SIZE);
01810 
01811   buf = group->checkpoint_buf;
01812 
01813   mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no);
01814   mach_write_to_8(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn);
01815 
01816   mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET,
01817       log_group_calc_lsn_offset(
01818         log_sys->next_checkpoint_lsn, group));
01819 
01820   mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, log_sys->buf_size);
01821 
01822 #ifdef UNIV_LOG_ARCHIVE
01823   if (log_sys->archiving_state == LOG_ARCH_OFF) {
01824     archived_lsn = IB_ULONGLONG_MAX;
01825   } else {
01826     archived_lsn = log_sys->archived_lsn;
01827 
01828     if (archived_lsn != log_sys->next_archived_lsn) {
01829       next_archived_lsn = log_sys->next_archived_lsn;
01830       /* For debugging only */
01831     }
01832   }
01833 
01834   mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, archived_lsn);
01835 #else /* UNIV_LOG_ARCHIVE */
01836   mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN,
01837       (ib_uint64_t)log_group_calc_lsn_offset(
01838         log_sys->next_checkpoint_lsn, group));
01839 
01840 #endif /* UNIV_LOG_ARCHIVE */
01841 
01842   for (i = 0; i < LOG_MAX_N_GROUPS; i++) {
01843     log_checkpoint_set_nth_group_info(buf, i, 0, 0);
01844   }
01845 
01846   group2 = UT_LIST_GET_FIRST(log_sys->log_groups);
01847 
01848   while (group2) {
01849     log_checkpoint_set_nth_group_info(buf, group2->id,
01850 #ifdef UNIV_LOG_ARCHIVE
01851               group2->archived_file_no,
01852               group2->archived_offset
01853 #else /* UNIV_LOG_ARCHIVE */
01854               0, 0
01855 #endif /* UNIV_LOG_ARCHIVE */
01856               );
01857 
01858     group2 = UT_LIST_GET_NEXT(log_groups, group2);
01859   }
01860 
01861   fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
01862   mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold);
01863 
01864   fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
01865             LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
01866   mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_2, fold);
01867 
01868   /* Starting from InnoDB-3.23.50, we also write info on allocated
01869   size in the tablespace */
01870 
01871   mach_write_to_4(buf + LOG_CHECKPOINT_FSP_FREE_LIMIT,
01872       log_fsp_current_free_limit);
01873 
01874   mach_write_to_4(buf + LOG_CHECKPOINT_FSP_MAGIC_N,
01875       LOG_CHECKPOINT_FSP_MAGIC_N_VAL);
01876 
01877   /* We alternate the physical place of the checkpoint info in the first
01878   log file */
01879 
01880   if ((log_sys->next_checkpoint_no & 1) == 0) {
01881     write_offset = LOG_CHECKPOINT_1;
01882   } else {
01883     write_offset = LOG_CHECKPOINT_2;
01884   }
01885 
01886   if (log_do_write) {
01887     if (log_sys->n_pending_checkpoint_writes == 0) {
01888 
01889       rw_lock_x_lock_gen(&(log_sys->checkpoint_lock),
01890              LOG_CHECKPOINT);
01891     }
01892 
01893     log_sys->n_pending_checkpoint_writes++;
01894 
01895     log_sys->n_log_ios++;
01896 
01897     /* We send as the last parameter the group machine address
01898     added with 1, as we want to distinguish between a normal log
01899     file write and a checkpoint field write */
01900 
01901     fil_io(OS_FILE_WRITE | OS_FILE_LOG, FALSE, group->space_id, 0,
01902            write_offset / UNIV_PAGE_SIZE,
01903            write_offset % UNIV_PAGE_SIZE,
01904            OS_FILE_LOG_BLOCK_SIZE,
01905            buf, ((byte*)group + 1));
01906 
01907     ut_ad(((ulint)group & 0x1UL) == 0);
01908   }
01909 }
01910 #endif /* !UNIV_HOTBACKUP */
01911 
01912 #ifdef UNIV_HOTBACKUP
01913 /******************************************************/
01916 UNIV_INTERN
01917 void
01918 log_reset_first_header_and_checkpoint(
01919 /*==================================*/
01920   byte*   hdr_buf,
01922   ib_uint64_t start)  
01925 {
01926   ulint   fold;
01927   byte*   buf;
01928   ib_uint64_t lsn;
01929 
01930   mach_write_to_4(hdr_buf + LOG_GROUP_ID, 0);
01931   mach_write_to_8(hdr_buf + LOG_FILE_START_LSN, start);
01932 
01933   lsn = start + LOG_BLOCK_HDR_SIZE;
01934 
01935   /* Write the label of ibbackup --restore */
01936   strcpy((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
01937          "ibbackup ");
01938   ut_sprintf_timestamp((char*) hdr_buf
01939            + (LOG_FILE_WAS_CREATED_BY_HOT_BACKUP
01940         + (sizeof "ibbackup ") - 1));
01941   buf = hdr_buf + LOG_CHECKPOINT_1;
01942 
01943   mach_write_to_8(buf + LOG_CHECKPOINT_NO, 0);
01944   mach_write_to_8(buf + LOG_CHECKPOINT_LSN, lsn);
01945 
01946   mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET,
01947       LOG_FILE_HDR_SIZE + LOG_BLOCK_HDR_SIZE);
01948 
01949   mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, 2 * 1024 * 1024);
01950 
01951   mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, IB_ULONGLONG_MAX);
01952 
01953   fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
01954   mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold);
01955 
01956   fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
01957             LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
01958   mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_2, fold);
01959 
01960   /* Starting from InnoDB-3.23.50, we should also write info on
01961   allocated size in the tablespace, but unfortunately we do not
01962   know it here */
01963 }
01964 #endif /* UNIV_HOTBACKUP */
01965 
01966 #ifndef UNIV_HOTBACKUP
01967 /******************************************************/
01969 UNIV_INTERN
01970 void
01971 log_group_read_checkpoint_info(
01972 /*===========================*/
01973   log_group_t*  group,  
01974   ulint   field)  
01975 {
01976   ut_ad(mutex_own(&(log_sys->mutex)));
01977 
01978   log_sys->n_log_ios++;
01979 
01980   fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, group->space_id, 0,
01981          field / UNIV_PAGE_SIZE, field % UNIV_PAGE_SIZE,
01982          OS_FILE_LOG_BLOCK_SIZE, log_sys->checkpoint_buf, NULL);
01983 }
01984 
01985 /******************************************************/
01987 UNIV_INTERN
01988 void
01989 log_groups_write_checkpoint_info(void)
01990 /*==================================*/
01991 {
01992   log_group_t*  group;
01993 
01994   ut_ad(mutex_own(&(log_sys->mutex)));
01995 
01996   group = UT_LIST_GET_FIRST(log_sys->log_groups);
01997 
01998   while (group) {
01999     log_group_checkpoint(group);
02000 
02001     group = UT_LIST_GET_NEXT(log_groups, group);
02002   }
02003 }
02004 
02005 /******************************************************/
02011 UNIV_INTERN
02012 ibool
02013 log_checkpoint(
02014 /*===========*/
02015   ibool sync,   
02017   ibool write_always) 
02023 {
02024   ib_uint64_t oldest_lsn;
02025 
02026   if (recv_recovery_is_on()) {
02027     recv_apply_hashed_log_recs(TRUE);
02028   }
02029 
02030   if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC) {
02031     fil_flush_file_spaces(FIL_TABLESPACE);
02032   }
02033 
02034   mutex_enter(&(log_sys->mutex));
02035 
02036   ut_ad(!recv_no_log_write);
02037   oldest_lsn = log_buf_pool_get_oldest_modification();
02038 
02039   mutex_exit(&(log_sys->mutex));
02040 
02041   /* Because log also contains headers and dummy log records,
02042   if the buffer pool contains no dirty buffers, oldest_lsn
02043   gets the value log_sys->lsn from the previous function,
02044   and we must make sure that the log is flushed up to that
02045   lsn. If there are dirty buffers in the buffer pool, then our
02046   write-ahead-logging algorithm ensures that the log has been flushed
02047   up to oldest_lsn. */
02048 
02049   log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
02050 
02051   mutex_enter(&(log_sys->mutex));
02052 
02053   if (!write_always
02054       && log_sys->last_checkpoint_lsn >= oldest_lsn) {
02055 
02056     mutex_exit(&(log_sys->mutex));
02057 
02058     return(TRUE);
02059   }
02060 
02061   ut_ad(log_sys->flushed_to_disk_lsn >= oldest_lsn);
02062 
02063   if (log_sys->n_pending_checkpoint_writes > 0) {
02064     /* A checkpoint write is running */
02065 
02066     mutex_exit(&(log_sys->mutex));
02067 
02068     if (sync) {
02069       /* Wait for the checkpoint write to complete */
02070       rw_lock_s_lock(&(log_sys->checkpoint_lock));
02071       rw_lock_s_unlock(&(log_sys->checkpoint_lock));
02072     }
02073 
02074     return(FALSE);
02075   }
02076 
02077   log_sys->next_checkpoint_lsn = oldest_lsn;
02078 
02079 #ifdef UNIV_DEBUG
02080   if (log_debug_writes) {
02081     fprintf(stderr, "Making checkpoint no %lu at lsn %"PRIu64"\n",
02082       (ulong) log_sys->next_checkpoint_no,
02083       oldest_lsn);
02084   }
02085 #endif /* UNIV_DEBUG */
02086 
02087   log_groups_write_checkpoint_info();
02088 
02089   mutex_exit(&(log_sys->mutex));
02090 
02091   if (sync) {
02092     /* Wait for the checkpoint write to complete */
02093     rw_lock_s_lock(&(log_sys->checkpoint_lock));
02094     rw_lock_s_unlock(&(log_sys->checkpoint_lock));
02095   }
02096 
02097   return(TRUE);
02098 }
02099 
02100 /****************************************************************/
02102 UNIV_INTERN
02103 void
02104 log_make_checkpoint_at(
02105 /*===================*/
02106   ib_uint64_t lsn,    
02109   ibool   write_always) 
02116 {
02117   /* Preflush pages synchronously */
02118 
02119   while (!log_preflush_pool_modified_pages(lsn, TRUE)) {}
02120 
02121   while (!log_checkpoint(TRUE, write_always)) {}
02122 }
02123 
02124 /****************************************************************/
02129 static
02130 void
02131 log_checkpoint_margin(void)
02132 /*=======================*/
02133 {
02134   log_t*    log   = log_sys;
02135   ib_uint64_t age;
02136   ib_uint64_t checkpoint_age;
02137   ib_uint64_t advance;
02138   ib_uint64_t oldest_lsn;
02139   ibool   sync;
02140   ibool   checkpoint_sync;
02141   ibool   do_checkpoint;
02142   ibool   success;
02143 loop:
02144   sync = FALSE;
02145   checkpoint_sync = FALSE;
02146   do_checkpoint = FALSE;
02147 
02148   mutex_enter(&(log->mutex));
02149   ut_ad(!recv_no_log_write);
02150 
02151   if (log->check_flush_or_checkpoint == FALSE) {
02152     mutex_exit(&(log->mutex));
02153 
02154     return;
02155   }
02156 
02157   oldest_lsn = log_buf_pool_get_oldest_modification();
02158 
02159   age = log->lsn - oldest_lsn;
02160 
02161   if (age > log->max_modified_age_sync) {
02162 
02163     /* A flush is urgent: we have to do a synchronous preflush */
02164 
02165     sync = TRUE;
02166     advance = 2 * (age - log->max_modified_age_sync);
02167   } else if (age > log_max_modified_age_async()) {
02168 
02169     /* A flush is not urgent: we do an asynchronous preflush */
02170     advance = age - log_max_modified_age_async();
02171   } else {
02172     advance = 0;
02173   }
02174 
02175   checkpoint_age = log->lsn - log->last_checkpoint_lsn;
02176 
02177   if (checkpoint_age > log->max_checkpoint_age) {
02178     /* A checkpoint is urgent: we do it synchronously */
02179 
02180     checkpoint_sync = TRUE;
02181 
02182     do_checkpoint = TRUE;
02183 
02184   } else if (checkpoint_age > log_max_checkpoint_age_async()) {
02185     /* A checkpoint is not urgent: do it asynchronously */
02186 
02187     do_checkpoint = TRUE;
02188 
02189     log->check_flush_or_checkpoint = FALSE;
02190   } else {
02191     log->check_flush_or_checkpoint = FALSE;
02192   }
02193 
02194   mutex_exit(&(log->mutex));
02195 
02196   if (advance) {
02197     ib_uint64_t new_oldest = oldest_lsn + advance;
02198 
02199     success = log_preflush_pool_modified_pages(new_oldest, sync);
02200 
02201     /* If the flush succeeded, this thread has done its part
02202     and can proceed. If it did not succeed, there was another
02203     thread doing a flush at the same time. If sync was FALSE,
02204     the flush was not urgent, and we let this thread proceed.
02205     Otherwise, we let it start from the beginning again. */
02206 
02207     if (sync && !success) {
02208       mutex_enter(&(log->mutex));
02209 
02210       log->check_flush_or_checkpoint = TRUE;
02211 
02212       mutex_exit(&(log->mutex));
02213       goto loop;
02214     }
02215   }
02216 
02217   if (do_checkpoint) {
02218     log_checkpoint(checkpoint_sync, FALSE);
02219 
02220     if (checkpoint_sync) {
02221 
02222       goto loop;
02223     }
02224   }
02225 }
02226 
02227 /******************************************************/
02229 UNIV_INTERN
02230 void
02231 log_group_read_log_seg(
02232 /*===================*/
02233   ulint   type,   
02234   byte*   buf,    
02235   log_group_t*  group,    
02236   ib_uint64_t start_lsn,  
02237   ib_uint64_t end_lsn)  
02238 {
02239   ulint len;
02240   ulint source_offset;
02241   ibool sync;
02242 
02243   ut_ad(mutex_own(&(log_sys->mutex)));
02244 
02245   sync = (type == LOG_RECOVER);
02246 loop:
02247   source_offset = log_group_calc_lsn_offset(start_lsn, group);
02248 
02249   len = (ulint) (end_lsn - start_lsn);
02250 
02251   ut_ad(len != 0);
02252 
02253   if ((source_offset % group->file_size) + len > group->file_size) {
02254 
02255     len = group->file_size - (source_offset % group->file_size);
02256   }
02257 
02258 #ifdef UNIV_LOG_ARCHIVE
02259   if (type == LOG_ARCHIVE) {
02260 
02261     log_sys->n_pending_archive_ios++;
02262   }
02263 #endif /* UNIV_LOG_ARCHIVE */
02264 
02265   log_sys->n_log_ios++;
02266 
02267   fil_io(OS_FILE_READ | OS_FILE_LOG, sync, group->space_id, 0,
02268          source_offset / UNIV_PAGE_SIZE, source_offset % UNIV_PAGE_SIZE,
02269          len, buf, NULL);
02270 
02271   start_lsn += len;
02272   buf += len;
02273 
02274   if (start_lsn != end_lsn) {
02275 
02276     goto loop;
02277   }
02278 }
02279 
02280 #ifdef UNIV_LOG_ARCHIVE
02281 /******************************************************/
02283 UNIV_INTERN
02284 void
02285 log_archived_file_name_gen(
02286 /*=======================*/
02287   char* buf,  
02288   ulint /*id __attribute__((unused))*/,
02291   ulint file_no)
02292 {
02293   sprintf(buf, "%sib_arch_log_%010lu", srv_arch_dir, (ulong) file_no);
02294 }
02295 
02296 /******************************************************/
02298 static
02299 void
02300 log_group_archive_file_header_write(
02301 /*================================*/
02302   log_group_t*  group,    
02303   ulint   nth_file, 
02305   ulint   file_no,  
02306   ib_uint64_t start_lsn)  
02308 {
02309   byte* buf;
02310   ulint dest_offset;
02311 
02312   ut_ad(mutex_own(&(log_sys->mutex)));
02313 
02314   ut_a(nth_file < group->n_files);
02315 
02316   buf = *(group->archive_file_header_bufs + nth_file);
02317 
02318   mach_write_to_4(buf + LOG_GROUP_ID, group->id);
02319   mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn);
02320   mach_write_to_4(buf + LOG_FILE_NO, file_no);
02321 
02322   mach_write_to_4(buf + LOG_FILE_ARCH_COMPLETED, FALSE);
02323 
02324   dest_offset = nth_file * group->file_size;
02325 
02326   log_sys->n_log_ios++;
02327 
02328   fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->archive_space_id,
02329          dest_offset / UNIV_PAGE_SIZE,
02330          dest_offset % UNIV_PAGE_SIZE,
02331          2 * OS_FILE_LOG_BLOCK_SIZE,
02332          buf, &log_archive_io);
02333 }
02334 
02335 /******************************************************/
02337 static
02338 void
02339 log_group_archive_completed_header_write(
02340 /*=====================================*/
02341   log_group_t*  group,    
02342   ulint   nth_file, 
02344   ib_uint64_t end_lsn)  
02345 {
02346   byte* buf;
02347   ulint dest_offset;
02348 
02349   ut_ad(mutex_own(&(log_sys->mutex)));
02350   ut_a(nth_file < group->n_files);
02351 
02352   buf = *(group->archive_file_header_bufs + nth_file);
02353 
02354   mach_write_to_4(buf + LOG_FILE_ARCH_COMPLETED, TRUE);
02355   mach_write_to_8(buf + LOG_FILE_END_LSN, end_lsn);
02356 
02357   dest_offset = nth_file * group->file_size + LOG_FILE_ARCH_COMPLETED;
02358 
02359   log_sys->n_log_ios++;
02360 
02361   fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->archive_space_id,
02362          dest_offset / UNIV_PAGE_SIZE,
02363          dest_offset % UNIV_PAGE_SIZE,
02364          OS_FILE_LOG_BLOCK_SIZE,
02365          buf + LOG_FILE_ARCH_COMPLETED,
02366          &log_archive_io);
02367 }
02368 
02369 /******************************************************/
02371 static
02372 void
02373 log_group_archive(
02374 /*==============*/
02375   log_group_t*  group)  
02376 {
02377   os_file_t  file_handle;
02378   ib_uint64_t start_lsn;
02379   ib_uint64_t end_lsn;
02380   char    name[1024];
02381   byte*   buf;
02382   ulint   len;
02383   ibool   ret;
02384   ulint   next_offset;
02385   ulint   n_files;
02386   ulint   open_mode;
02387 
02388   ut_ad(mutex_own(&(log_sys->mutex)));
02389 
02390   start_lsn = log_sys->archived_lsn;
02391 
02392   ut_a(start_lsn % OS_FILE_LOG_BLOCK_SIZE == 0);
02393 
02394   end_lsn = log_sys->next_archived_lsn;
02395 
02396   ut_a(end_lsn % OS_FILE_LOG_BLOCK_SIZE == 0);
02397 
02398   buf = log_sys->archive_buf;
02399 
02400   n_files = 0;
02401 
02402   next_offset = group->archived_offset;
02403 loop:
02404   if ((next_offset % group->file_size == 0)
02405       || (fil_space_get_size(group->archive_space_id) == 0)) {
02406 
02407     /* Add the file to the archive file space; create or open the
02408     file */
02409 
02410     if (next_offset % group->file_size == 0) {
02411       open_mode = OS_FILE_CREATE;
02412     } else {
02413       open_mode = OS_FILE_OPEN;
02414     }
02415 
02416     log_archived_file_name_gen(name, group->id,
02417              group->archived_file_no + n_files);
02418 
02419     file_handle = os_file_create(innodb_file_log_key,
02420                name, open_mode,
02421                OS_FILE_AIO,
02422                OS_DATA_FILE, &ret);
02423 
02424     if (!ret && (open_mode == OS_FILE_CREATE)) {
02425       file_handle = os_file_create(
02426         innodb_file_log_key, name, OS_FILE_OPEN,
02427         OS_FILE_AIO, OS_DATA_FILE, &ret);
02428     }
02429 
02430     if (!ret) {
02431       fprintf(stderr,
02432         "InnoDB: Cannot create or open"
02433         " archive log file %s.\n"
02434         "InnoDB: Cannot continue operation.\n"
02435         "InnoDB: Check that the log archive"
02436         " directory exists,\n"
02437         "InnoDB: you have access rights to it, and\n"
02438         "InnoDB: there is space available.\n", name);
02439       exit(1);
02440     }
02441 
02442 #ifdef UNIV_DEBUG
02443     if (log_debug_writes) {
02444       fprintf(stderr, "Created archive file %s\n", name);
02445     }
02446 #endif /* UNIV_DEBUG */
02447 
02448     ret = os_file_close(file_handle);
02449 
02450     ut_a(ret);
02451 
02452     /* Add the archive file as a node to the space */
02453 
02454     fil_node_create(name, group->file_size / UNIV_PAGE_SIZE,
02455         group->archive_space_id, FALSE);
02456 
02457     if (next_offset % group->file_size == 0) {
02458       log_group_archive_file_header_write(
02459         group, n_files,
02460         group->archived_file_no + n_files,
02461         start_lsn);
02462 
02463       next_offset += LOG_FILE_HDR_SIZE;
02464     }
02465   }
02466 
02467   len = end_lsn - start_lsn;
02468 
02469   if (group->file_size < (next_offset % group->file_size) + len) {
02470 
02471     len = group->file_size - (next_offset % group->file_size);
02472   }
02473 
02474 #ifdef UNIV_DEBUG
02475   if (log_debug_writes) {
02476     fprintf(stderr,
02477       "Archiving starting at lsn %"PRIu64", len %lu"
02478       " to group %lu\n",
02479       start_lsn,
02480       (ulong) len, (ulong) group->id);
02481   }
02482 #endif /* UNIV_DEBUG */
02483 
02484   log_sys->n_pending_archive_ios++;
02485 
02486   log_sys->n_log_ios++;
02487 
02488   fil_io(OS_FILE_WRITE | OS_FILE_LOG, FALSE, group->archive_space_id,
02489          next_offset / UNIV_PAGE_SIZE, next_offset % UNIV_PAGE_SIZE,
02490          ut_calc_align(len, OS_FILE_LOG_BLOCK_SIZE), buf,
02491          &log_archive_io);
02492 
02493   start_lsn += len;
02494   next_offset += len;
02495   buf += len;
02496 
02497   if (next_offset % group->file_size == 0) {
02498     n_files++;
02499   }
02500 
02501   if (end_lsn != start_lsn) {
02502 
02503     goto loop;
02504   }
02505 
02506   group->next_archived_file_no = group->archived_file_no + n_files;
02507   group->next_archived_offset = next_offset % group->file_size;
02508 
02509   ut_a(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
02510 }
02511 
02512 /*****************************************************/
02515 static
02516 void
02517 log_archive_groups(void)
02518 /*====================*/
02519 {
02520   log_group_t*  group;
02521 
02522   ut_ad(mutex_own(&(log_sys->mutex)));
02523 
02524   group = UT_LIST_GET_FIRST(log_sys->log_groups);
02525 
02526   log_group_archive(group);
02527 }
02528 
02529 /*****************************************************/
02532 static
02533 void
02534 log_archive_write_complete_groups(void)
02535 /*===================================*/
02536 {
02537   log_group_t*  group;
02538   ulint   end_offset;
02539   ulint   trunc_files;
02540   ulint   n_files;
02541   ib_uint64_t start_lsn;
02542   ib_uint64_t end_lsn;
02543   ulint   i;
02544 
02545   ut_ad(mutex_own(&(log_sys->mutex)));
02546 
02547   group = UT_LIST_GET_FIRST(log_sys->log_groups);
02548 
02549   group->archived_file_no = group->next_archived_file_no;
02550   group->archived_offset = group->next_archived_offset;
02551 
02552   /* Truncate from the archive file space all but the last
02553   file, or if it has been written full, all files */
02554 
02555   n_files = (UNIV_PAGE_SIZE
02556        * fil_space_get_size(group->archive_space_id))
02557     / group->file_size;
02558   ut_ad(n_files > 0);
02559 
02560   end_offset = group->archived_offset;
02561 
02562   if (end_offset % group->file_size == 0) {
02563 
02564     trunc_files = n_files;
02565   } else {
02566     trunc_files = n_files - 1;
02567   }
02568 
02569 #ifdef UNIV_DEBUG
02570   if (log_debug_writes && trunc_files) {
02571     fprintf(stderr,
02572       "Complete file(s) archived to group %lu\n",
02573       (ulong) group->id);
02574   }
02575 #endif /* UNIV_DEBUG */
02576 
02577   /* Calculate the archive file space start lsn */
02578   start_lsn = log_sys->next_archived_lsn
02579     - (end_offset - LOG_FILE_HDR_SIZE + trunc_files
02580        * (group->file_size - LOG_FILE_HDR_SIZE));
02581   end_lsn = start_lsn;
02582 
02583   for (i = 0; i < trunc_files; i++) {
02584 
02585     end_lsn += group->file_size - LOG_FILE_HDR_SIZE;
02586 
02587     /* Write a notice to the headers of archived log
02588     files that the file write has been completed */
02589 
02590     log_group_archive_completed_header_write(group, i, end_lsn);
02591   }
02592 
02593   fil_space_truncate_start(group->archive_space_id,
02594          trunc_files * group->file_size);
02595 
02596 #ifdef UNIV_DEBUG
02597   if (log_debug_writes) {
02598     fputs("Archiving writes completed\n", stderr);
02599   }
02600 #endif /* UNIV_DEBUG */
02601 }
02602 
02603 /******************************************************/
02605 static
02606 void
02607 log_archive_check_completion_low(void)
02608 /*==================================*/
02609 {
02610   ut_ad(mutex_own(&(log_sys->mutex)));
02611 
02612   if (log_sys->n_pending_archive_ios == 0
02613       && log_sys->archiving_phase == LOG_ARCHIVE_READ) {
02614 
02615 #ifdef UNIV_DEBUG
02616     if (log_debug_writes) {
02617       fputs("Archiving read completed\n", stderr);
02618     }
02619 #endif /* UNIV_DEBUG */
02620 
02621     /* Archive buffer has now been read in: start archive writes */
02622 
02623     log_sys->archiving_phase = LOG_ARCHIVE_WRITE;
02624 
02625     log_archive_groups();
02626   }
02627 
02628   if (log_sys->n_pending_archive_ios == 0
02629       && log_sys->archiving_phase == LOG_ARCHIVE_WRITE) {
02630 
02631     log_archive_write_complete_groups();
02632 
02633     log_sys->archived_lsn = log_sys->next_archived_lsn;
02634 
02635     rw_lock_x_unlock_gen(&(log_sys->archive_lock), LOG_ARCHIVE);
02636   }
02637 }
02638 
02639 /******************************************************/
02641 static
02642 void
02643 log_io_complete_archive(void)
02644 /*=========================*/
02645 {
02646   log_group_t*  group;
02647 
02648   mutex_enter(&(log_sys->mutex));
02649 
02650   group = UT_LIST_GET_FIRST(log_sys->log_groups);
02651 
02652   mutex_exit(&(log_sys->mutex));
02653 
02654   fil_flush(group->archive_space_id);
02655 
02656   mutex_enter(&(log_sys->mutex));
02657 
02658   ut_ad(log_sys->n_pending_archive_ios > 0);
02659 
02660   log_sys->n_pending_archive_ios--;
02661 
02662   log_archive_check_completion_low();
02663 
02664   mutex_exit(&(log_sys->mutex));
02665 }
02666 
02667 /********************************************************************/
02670 UNIV_INTERN
02671 ibool
02672 log_archive_do(
02673 /*===========*/
02674   ibool sync, 
02675   ulint*  n_bytes)
02677 {
02678   ibool   calc_new_limit;
02679   ib_uint64_t start_lsn;
02680   ib_uint64_t limit_lsn;
02681 
02682   calc_new_limit = TRUE;
02683 loop:
02684   mutex_enter(&(log_sys->mutex));
02685 
02686   switch (log_sys->archiving_state) {
02687   case LOG_ARCH_OFF:
02688 arch_none:
02689     mutex_exit(&(log_sys->mutex));
02690 
02691     *n_bytes = 0;
02692 
02693     return(TRUE);
02694   case LOG_ARCH_STOPPED:
02695   case LOG_ARCH_STOPPING2:
02696     mutex_exit(&(log_sys->mutex));
02697 
02698     os_event_wait(log_sys->archiving_on);
02699 
02700     goto loop;
02701   }
02702 
02703   start_lsn = log_sys->archived_lsn;
02704 
02705   if (calc_new_limit) {
02706     ut_a(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE == 0);
02707     limit_lsn = start_lsn + log_sys->archive_buf_size;
02708 
02709     *n_bytes = log_sys->archive_buf_size;
02710 
02711     if (limit_lsn >= log_sys->lsn) {
02712 
02713       limit_lsn = ut_uint64_align_down(
02714         log_sys->lsn, OS_FILE_LOG_BLOCK_SIZE);
02715     }
02716   }
02717 
02718   if (log_sys->archived_lsn >= limit_lsn) {
02719 
02720     goto arch_none;
02721   }
02722 
02723   if (log_sys->written_to_all_lsn < limit_lsn) {
02724 
02725     mutex_exit(&(log_sys->mutex));
02726 
02727     log_write_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
02728 
02729     calc_new_limit = FALSE;
02730 
02731     goto loop;
02732   }
02733 
02734   if (log_sys->n_pending_archive_ios > 0) {
02735     /* An archiving operation is running */
02736 
02737     mutex_exit(&(log_sys->mutex));
02738 
02739     if (sync) {
02740       rw_lock_s_lock(&(log_sys->archive_lock));
02741       rw_lock_s_unlock(&(log_sys->archive_lock));
02742     }
02743 
02744     *n_bytes = log_sys->archive_buf_size;
02745 
02746     return(FALSE);
02747   }
02748 
02749   rw_lock_x_lock_gen(&(log_sys->archive_lock), LOG_ARCHIVE);
02750 
02751   log_sys->archiving_phase = LOG_ARCHIVE_READ;
02752 
02753   log_sys->next_archived_lsn = limit_lsn;
02754 
02755 #ifdef UNIV_DEBUG
02756   if (log_debug_writes) {
02757     fprintf(stderr,
02758       "Archiving from lsn %"PRIu64" to lsn %"PRIu64"\n",
02759       log_sys->archived_lsn, limit_lsn);
02760   }
02761 #endif /* UNIV_DEBUG */
02762 
02763   /* Read the log segment to the archive buffer */
02764 
02765   log_group_read_log_seg(LOG_ARCHIVE, log_sys->archive_buf,
02766              UT_LIST_GET_FIRST(log_sys->log_groups),
02767              start_lsn, limit_lsn);
02768 
02769   mutex_exit(&(log_sys->mutex));
02770 
02771   if (sync) {
02772     rw_lock_s_lock(&(log_sys->archive_lock));
02773     rw_lock_s_unlock(&(log_sys->archive_lock));
02774   }
02775 
02776   *n_bytes = log_sys->archive_buf_size;
02777 
02778   return(TRUE);
02779 }
02780 
02781 /****************************************************************/
02784 static
02785 void
02786 log_archive_all(void)
02787 /*=================*/
02788 {
02789   ib_uint64_t present_lsn;
02790   ulint   dummy;
02791 
02792   mutex_enter(&(log_sys->mutex));
02793 
02794   if (log_sys->archiving_state == LOG_ARCH_OFF) {
02795     mutex_exit(&(log_sys->mutex));
02796 
02797     return;
02798   }
02799 
02800   present_lsn = log_sys->lsn;
02801 
02802   mutex_exit(&(log_sys->mutex));
02803 
02804   log_pad_current_log_block();
02805 
02806   for (;;) {
02807     mutex_enter(&(log_sys->mutex));
02808 
02809     if (present_lsn <= log_sys->archived_lsn) {
02810 
02811       mutex_exit(&(log_sys->mutex));
02812 
02813       return;
02814     }
02815 
02816     mutex_exit(&(log_sys->mutex));
02817 
02818     log_archive_do(TRUE, &dummy);
02819   }
02820 }
02821 
02822 /*****************************************************/
02825 static
02826 void
02827 log_archive_close_groups(
02828 /*=====================*/
02829   ibool increment_file_count) 
02831 {
02832   log_group_t*  group;
02833   ulint   trunc_len;
02834 
02835   ut_ad(mutex_own(&(log_sys->mutex)));
02836 
02837   if (log_sys->archiving_state == LOG_ARCH_OFF) {
02838 
02839     return;
02840   }
02841 
02842   group = UT_LIST_GET_FIRST(log_sys->log_groups);
02843 
02844   trunc_len = UNIV_PAGE_SIZE
02845     * fil_space_get_size(group->archive_space_id);
02846   if (trunc_len > 0) {
02847     ut_a(trunc_len == group->file_size);
02848 
02849     /* Write a notice to the headers of archived log
02850     files that the file write has been completed */
02851 
02852     log_group_archive_completed_header_write(
02853       group, 0, log_sys->archived_lsn);
02854 
02855     fil_space_truncate_start(group->archive_space_id,
02856            trunc_len);
02857     if (increment_file_count) {
02858       group->archived_offset = 0;
02859       group->archived_file_no += 2;
02860     }
02861 
02862 #ifdef UNIV_DEBUG
02863     if (log_debug_writes) {
02864       fprintf(stderr,
02865         "Incrementing arch file no to %lu"
02866         " in log group %lu\n",
02867         (ulong) group->archived_file_no + 2,
02868         (ulong) group->id);
02869     }
02870 #endif /* UNIV_DEBUG */
02871   }
02872 }
02873 
02874 /****************************************************************/
02880 UNIV_INTERN
02881 ulint
02882 log_archive_stop(void)
02883 /*==================*/
02884 {
02885   ibool success;
02886 
02887   mutex_enter(&(log_sys->mutex));
02888 
02889   if (log_sys->archiving_state != LOG_ARCH_ON) {
02890 
02891     mutex_exit(&(log_sys->mutex));
02892 
02893     return(DB_ERROR);
02894   }
02895 
02896   log_sys->archiving_state = LOG_ARCH_STOPPING;
02897 
02898   mutex_exit(&(log_sys->mutex));
02899 
02900   log_archive_all();
02901 
02902   mutex_enter(&(log_sys->mutex));
02903 
02904   log_sys->archiving_state = LOG_ARCH_STOPPING2;
02905   os_event_reset(log_sys->archiving_on);
02906 
02907   mutex_exit(&(log_sys->mutex));
02908 
02909   /* Wait for a possible archiving operation to end */
02910 
02911   rw_lock_s_lock(&(log_sys->archive_lock));
02912   rw_lock_s_unlock(&(log_sys->archive_lock));
02913 
02914   mutex_enter(&(log_sys->mutex));
02915 
02916   /* Close all archived log files, incrementing the file count by 2,
02917   if appropriate */
02918 
02919   log_archive_close_groups(TRUE);
02920 
02921   mutex_exit(&(log_sys->mutex));
02922 
02923   /* Make a checkpoint, so that if recovery is needed, the file numbers
02924   of new archived log files will start from the right value */
02925 
02926   success = FALSE;
02927 
02928   while (!success) {
02929     success = log_checkpoint(TRUE, TRUE);
02930   }
02931 
02932   mutex_enter(&(log_sys->mutex));
02933 
02934   log_sys->archiving_state = LOG_ARCH_STOPPED;
02935 
02936   mutex_exit(&(log_sys->mutex));
02937 
02938   return(DB_SUCCESS);
02939 }
02940 
02941 /****************************************************************/
02944 UNIV_INTERN
02945 ulint
02946 log_archive_start(void)
02947 /*===================*/
02948 {
02949   mutex_enter(&(log_sys->mutex));
02950 
02951   if (log_sys->archiving_state != LOG_ARCH_STOPPED) {
02952 
02953     mutex_exit(&(log_sys->mutex));
02954 
02955     return(DB_ERROR);
02956   }
02957 
02958   log_sys->archiving_state = LOG_ARCH_ON;
02959 
02960   os_event_set(log_sys->archiving_on);
02961 
02962   mutex_exit(&(log_sys->mutex));
02963 
02964   return(DB_SUCCESS);
02965 }
02966 
02967 /****************************************************************/
02970 UNIV_INTERN
02971 ulint
02972 log_archive_noarchivelog(void)
02973 /*==========================*/
02974 {
02975 loop:
02976   mutex_enter(&(log_sys->mutex));
02977 
02978   if (log_sys->archiving_state == LOG_ARCH_STOPPED
02979       || log_sys->archiving_state == LOG_ARCH_OFF) {
02980 
02981     log_sys->archiving_state = LOG_ARCH_OFF;
02982 
02983     os_event_set(log_sys->archiving_on);
02984 
02985     mutex_exit(&(log_sys->mutex));
02986 
02987     return(DB_SUCCESS);
02988   }
02989 
02990   mutex_exit(&(log_sys->mutex));
02991 
02992   log_archive_stop();
02993 
02994   os_thread_sleep(500000);
02995 
02996   goto loop;
02997 }
02998 
02999 /****************************************************************/
03002 UNIV_INTERN
03003 ulint
03004 log_archive_archivelog(void)
03005 /*========================*/
03006 {
03007   mutex_enter(&(log_sys->mutex));
03008 
03009   if (log_sys->archiving_state == LOG_ARCH_OFF) {
03010 
03011     log_sys->archiving_state = LOG_ARCH_ON;
03012 
03013     log_sys->archived_lsn
03014       = ut_uint64_align_down(log_sys->lsn,
03015                  OS_FILE_LOG_BLOCK_SIZE);
03016     mutex_exit(&(log_sys->mutex));
03017 
03018     return(DB_SUCCESS);
03019   }
03020 
03021   mutex_exit(&(log_sys->mutex));
03022 
03023   return(DB_ERROR);
03024 }
03025 
03026 /****************************************************************/
03030 static
03031 void
03032 log_archive_margin(void)
03033 /*====================*/
03034 {
03035   log_t*  log   = log_sys;
03036   ulint age;
03037   ibool sync;
03038   ulint dummy;
03039 loop:
03040   mutex_enter(&(log->mutex));
03041 
03042   if (log->archiving_state == LOG_ARCH_OFF) {
03043     mutex_exit(&(log->mutex));
03044 
03045     return;
03046   }
03047 
03048   age = log->lsn - log->archived_lsn;
03049 
03050   if (age > log->max_archived_lsn_age) {
03051 
03052     /* An archiving is urgent: we have to do synchronous i/o */
03053 
03054     sync = TRUE;
03055 
03056   } else if (age > log->max_archived_lsn_age_async) {
03057 
03058     /* An archiving is not urgent: we do asynchronous i/o */
03059 
03060     sync = FALSE;
03061   } else {
03062     /* No archiving required yet */
03063 
03064     mutex_exit(&(log->mutex));
03065 
03066     return;
03067   }
03068 
03069   mutex_exit(&(log->mutex));
03070 
03071   log_archive_do(sync, &dummy);
03072 
03073   if (sync == TRUE) {
03074     /* Check again that enough was written to the archive */
03075 
03076     goto loop;
03077   }
03078 }
03079 #endif /* UNIV_LOG_ARCHIVE */
03080 
03081 /********************************************************************/
03086 UNIV_INTERN
03087 void
03088 log_check_margins(void)
03089 /*===================*/
03090 {
03091 loop:
03092   log_flush_margin();
03093 
03094   log_checkpoint_margin();
03095 
03096 #ifdef UNIV_LOG_ARCHIVE
03097   log_archive_margin();
03098 #endif /* UNIV_LOG_ARCHIVE */
03099 
03100   mutex_enter(&(log_sys->mutex));
03101   ut_ad(!recv_no_log_write);
03102 
03103   if (log_sys->check_flush_or_checkpoint) {
03104 
03105     mutex_exit(&(log_sys->mutex));
03106 
03107     goto loop;
03108   }
03109 
03110   mutex_exit(&(log_sys->mutex));
03111 }
03112 
03113 /****************************************************************/
03118 UNIV_INTERN
03119 void
03120 logs_empty_and_mark_files_at_shutdown(void)
03121 /*=======================================*/
03122 {
03123   ib_uint64_t lsn;
03124   ulint   arch_log_no;
03125 
03126   if (srv_print_verbose_log) {
03127     ut_print_timestamp(stderr);
03128     fprintf(stderr, "  InnoDB: Starting shutdown...\n");
03129   }
03130   /* Wait until the master thread and all other operations are idle: our
03131   algorithm only works if the server is idle at shutdown */
03132 
03133   srv_shutdown_state = SRV_SHUTDOWN_CLEANUP;
03134 loop:
03135   os_thread_sleep(100000);
03136 
03137   mutex_enter(&kernel_mutex);
03138 
03139   /* We need the monitor threads to stop before we proceed with a
03140   normal shutdown. In case of very fast shutdown, however, we can
03141   proceed without waiting for monitor threads. */
03142 
03143   if (srv_fast_shutdown < 2
03144      && (srv_error_monitor_active
03145         || srv_lock_timeout_active
03146         || srv_monitor_active)) {
03147 
03148     mutex_exit(&kernel_mutex);
03149 
03150     os_event_set(srv_error_event);
03151     os_event_set(srv_monitor_event);
03152     os_event_set(srv_timeout_event);
03153 
03154     goto loop;
03155   }
03156 
03157   /* Check that there are no longer transactions. We need this wait even
03158   for the 'very fast' shutdown, because the InnoDB layer may have
03159   committed or prepared transactions and we don't want to lose them. */
03160 
03161         if (! srv_apply_log_only) {
03162   if (trx_n_mysql_transactions > 0
03163       || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
03164 
03165     mutex_exit(&kernel_mutex);
03166 
03167     goto loop;
03168   }
03169         }
03170 
03171   if (srv_fast_shutdown == 2) {
03172     /* In this fastest shutdown we do not flush the buffer pool:
03173     it is essentially a 'crash' of the InnoDB server. Make sure
03174     that the log is all flushed to disk, so that we can recover
03175     all committed transactions in a crash recovery. We must not
03176     write the lsn stamps to the data files, since at a startup
03177     InnoDB deduces from the stamps if the previous shutdown was
03178     clean. */
03179 
03180     log_buffer_flush_to_disk();
03181 
03182     mutex_exit(&kernel_mutex);
03183 
03184     return; /* We SKIP ALL THE REST !! */
03185   }
03186 
03187   mutex_exit(&kernel_mutex);
03188 
03189   /* Check that the background threads are suspended */
03190 
03191   if (srv_is_any_background_thread_active()) {
03192     goto loop;
03193   }
03194 
03195   mutex_enter(&(log_sys->mutex));
03196 
03197   if (log_sys->n_pending_checkpoint_writes
03198 #ifdef UNIV_LOG_ARCHIVE
03199       || log_sys->n_pending_archive_ios
03200 #endif /* UNIV_LOG_ARCHIVE */
03201       || log_sys->n_pending_writes) {
03202 
03203     mutex_exit(&(log_sys->mutex));
03204 
03205     goto loop;
03206   }
03207 
03208   mutex_exit(&(log_sys->mutex));
03209 
03210   if (!buf_pool_check_no_pending_io()) {
03211 
03212     goto loop;
03213   }
03214 
03215 #ifdef UNIV_LOG_ARCHIVE
03216   log_archive_all();
03217 #endif /* UNIV_LOG_ARCHIVE */
03218 
03219   log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
03220 
03221   mutex_enter(&(log_sys->mutex));
03222 
03223   lsn = log_sys->lsn;
03224 
03225   if (lsn != log_sys->last_checkpoint_lsn
03226 #ifdef UNIV_LOG_ARCHIVE
03227       || (srv_log_archive_on
03228     && lsn != log_sys->archived_lsn + LOG_BLOCK_HDR_SIZE)
03229 #endif /* UNIV_LOG_ARCHIVE */
03230       ) {
03231 
03232     mutex_exit(&(log_sys->mutex));
03233 
03234     goto loop;
03235   }
03236 
03237   arch_log_no = 0;
03238 
03239 #ifdef UNIV_LOG_ARCHIVE
03240   UT_LIST_GET_FIRST(log_sys->log_groups)->archived_file_no;
03241 
03242   if (0 == UT_LIST_GET_FIRST(log_sys->log_groups)->archived_offset) {
03243 
03244     arch_log_no--;
03245   }
03246 
03247   log_archive_close_groups(TRUE);
03248 #endif /* UNIV_LOG_ARCHIVE */
03249 
03250   mutex_exit(&(log_sys->mutex));
03251 
03252   /* Check that the background threads stay suspended */
03253   if (srv_is_any_background_thread_active()) {
03254     fprintf(stderr,
03255       "InnoDB: Warning: some background thread woke up"
03256       " during shutdown\n");
03257 
03258     goto loop;
03259   }
03260 
03261   fil_flush_file_spaces(FIL_TABLESPACE);
03262   fil_flush_file_spaces(FIL_LOG);
03263 
03264   /* The call fil_write_flushed_lsn_to_data_files() will pass the buffer
03265   pool: therefore it is essential that the buffer pool has been
03266   completely flushed to disk! (We do not call fil_write... if the
03267   'very fast' shutdown is enabled.) */
03268 
03269   if (!buf_all_freed()) {
03270 
03271     goto loop;
03272   }
03273 
03274   srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE;
03275 
03276   /* Make some checks that the server really is quiet */
03277   ut_a(!srv_is_any_background_thread_active());
03278 
03279   ut_a(buf_all_freed());
03280   ut_a(lsn == log_sys->lsn);
03281 
03282   if (lsn < srv_start_lsn) {
03283           drizzled::errmsg_printf(drizzled::error::ERROR,
03284                                   "InnoDB: Error: log sequence number at shutdown %"PRIu64" is lower than at startup %"PRIu64"!",
03285                                   lsn, srv_start_lsn);
03286   }
03287 
03288   srv_shutdown_lsn = lsn;
03289 
03290   fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
03291 
03292   fil_flush_file_spaces(FIL_TABLESPACE);
03293 
03294   fil_close_all_files();
03295 
03296   /* Make some checks that the server really is quiet */
03297   ut_a(!srv_is_any_background_thread_active());
03298 
03299   ut_a(buf_all_freed());
03300   ut_a(lsn == log_sys->lsn);
03301 }
03302 
03303 #ifdef UNIV_LOG_DEBUG
03304 /******************************************************/
03307 UNIV_INTERN
03308 ibool
03309 log_check_log_recs(
03310 /*===============*/
03311   const byte* buf,    
03314   ulint   len,    
03315   ib_uint64_t buf_start_lsn)  
03316 {
03317   ib_uint64_t contiguous_lsn;
03318   ib_uint64_t scanned_lsn;
03319   const byte* start;
03320   const byte* end;
03321   byte*   buf1;
03322   byte*   scan_buf;
03323 
03324   ut_ad(mutex_own(&(log_sys->mutex)));
03325 
03326   if (len == 0) {
03327 
03328     return(TRUE);
03329   }
03330 
03331   start = ut_align_down(buf, OS_FILE_LOG_BLOCK_SIZE);
03332   end = ut_align(buf + len, OS_FILE_LOG_BLOCK_SIZE);
03333 
03334   buf1 = mem_alloc((end - start) + OS_FILE_LOG_BLOCK_SIZE);
03335   scan_buf = ut_align(buf1, OS_FILE_LOG_BLOCK_SIZE);
03336 
03337   ut_memcpy(scan_buf, start, end - start);
03338 
03339   recv_scan_log_recs((buf_pool_get_n_pages()
03340          - (recv_n_pool_free_frames * srv_buf_pool_instances))
03341          * UNIV_PAGE_SIZE, FALSE, scan_buf, end - start,
03342          ut_uint64_align_down(buf_start_lsn,
03343             OS_FILE_LOG_BLOCK_SIZE),
03344          &contiguous_lsn, &scanned_lsn);
03345 
03346   ut_a(scanned_lsn == buf_start_lsn + len);
03347   ut_a(recv_sys->recovered_lsn == scanned_lsn);
03348 
03349   mem_free(buf1);
03350 
03351   return(TRUE);
03352 }
03353 #endif /* UNIV_LOG_DEBUG */
03354 
03355 /******************************************************/
03358 UNIV_INTERN
03359 ibool
03360 log_peek_lsn(
03361 /*=========*/
03362   ib_uint64_t*  lsn)  
03363 {
03364   if (0 == mutex_enter_nowait(&(log_sys->mutex))) {
03365     *lsn = log_sys->lsn;
03366 
03367     mutex_exit(&(log_sys->mutex));
03368 
03369     return(TRUE);
03370   }
03371 
03372   return(FALSE);
03373 }
03374 
03375 /******************************************************/
03377 UNIV_INTERN
03378 void
03379 log_print(
03380 /*======*/
03381   FILE* file) 
03382 {
03383   double  time_elapsed;
03384   time_t  current_time;
03385 
03386   mutex_enter(&(log_sys->mutex));
03387 
03388   fprintf(file,
03389     "Log sequence number %"PRIu64"\n"
03390     "Log flushed up to   %"PRIu64"\n"
03391     "Last checkpoint at  %"PRIu64"\n",
03392     log_sys->lsn,
03393     log_sys->flushed_to_disk_lsn,
03394     log_sys->last_checkpoint_lsn);
03395 
03396   fprintf(file,
03397     "Max checkpoint age    %lu\n"
03398     "Checkpoint age target %lu\n"
03399     "Modified age          %"PRIu64"\n"
03400     "Checkpoint age        %"PRIu64"\n",
03401     log_sys->max_checkpoint_age,
03402     log_max_checkpoint_age_async(),
03403     log_sys->lsn - log_buf_pool_get_oldest_modification(),
03404     log_sys->lsn - log_sys->last_checkpoint_lsn);
03405 
03406   current_time = time(NULL);
03407 
03408   time_elapsed = 0.001 + difftime(current_time,
03409           log_sys->last_printout_time);
03410   fprintf(file,
03411     "%lu pending log writes, %lu pending chkp writes\n"
03412     "%lu log i/o's done, %.2f log i/o's/second\n",
03413     (ulong) log_sys->n_pending_writes,
03414     (ulong) log_sys->n_pending_checkpoint_writes,
03415     (ulong) log_sys->n_log_ios,
03416     ((log_sys->n_log_ios - log_sys->n_log_ios_old)
03417      / time_elapsed));
03418 
03419   log_sys->n_log_ios_old = log_sys->n_log_ios;
03420   log_sys->last_printout_time = current_time;
03421 
03422   mutex_exit(&(log_sys->mutex));
03423 }
03424 
03425 /**********************************************************************/
03427 UNIV_INTERN
03428 void
03429 log_refresh_stats(void)
03430 /*===================*/
03431 {
03432   log_sys->n_log_ios_old = log_sys->n_log_ios;
03433   log_sys->last_printout_time = time(NULL);
03434 }
03435 
03436 /**********************************************************************
03437 Closes a log group. */
03438 static
03439 void
03440 log_group_close(
03441 /*===========*/
03442   log_group_t*  group)    /* in,own: log group to close */
03443 {
03444   ulint i;
03445 
03446   for (i = 0; i < group->n_files; i++) {
03447     mem_free(group->file_header_bufs_ptr[i]);
03448 #ifdef UNIV_LOG_ARCHIVE
03449     mem_free(group->archive_file_header_bufs_ptr[i]);
03450 #endif /* UNIV_LOG_ARCHIVE */
03451   }
03452 
03453   mem_free(group->file_header_bufs_ptr);
03454   mem_free(group->file_header_bufs);
03455 
03456 #ifdef UNIV_LOG_ARCHIVE
03457   mem_free(group->archive_file_header_bufs_ptr);
03458   mem_free(group->archive_file_header_bufs);
03459 #endif /* UNIV_LOG_ARCHIVE */
03460 
03461   mem_free(group->checkpoint_buf_ptr);
03462 
03463   mem_free(group);
03464 }
03465 
03466 /**********************************************************
03467 Shutdown the log system but do not release all the memory. */
03468 UNIV_INTERN
03469 void
03470 log_shutdown(void)
03471 /*==============*/
03472 {
03473   log_group_t*  group;
03474 
03475   group = UT_LIST_GET_FIRST(log_sys->log_groups);
03476 
03477   while (UT_LIST_GET_LEN(log_sys->log_groups) > 0) {
03478     log_group_t*  prev_group = group;
03479 
03480     group = UT_LIST_GET_NEXT(log_groups, group);
03481     UT_LIST_REMOVE(log_groups, log_sys->log_groups, prev_group);
03482 
03483     log_group_close(prev_group);
03484   }
03485 
03486   mem_free(log_sys->buf_ptr);
03487   log_sys->buf_ptr = NULL;
03488   log_sys->buf = NULL;
03489   mem_free(log_sys->checkpoint_buf_ptr);
03490   log_sys->checkpoint_buf_ptr = NULL;
03491   log_sys->checkpoint_buf = NULL;
03492 
03493   os_event_free(log_sys->no_flush_event);
03494   os_event_free(log_sys->one_flushed_event);
03495 
03496   rw_lock_free(&log_sys->checkpoint_lock);
03497 
03498   mutex_free(&log_sys->mutex);
03499 
03500 #ifdef UNIV_LOG_ARCHIVE
03501   rw_lock_free(&log_sys->archive_lock);
03502   os_event_create(log_sys->archiving_on);
03503 #endif /* UNIV_LOG_ARCHIVE */
03504 
03505 #ifdef UNIV_LOG_DEBUG
03506   recv_sys_debug_free();
03507 #endif
03508 
03509   recv_sys_close();
03510 }
03511 
03512 /**********************************************************
03513 Free the log system data structures. */
03514 UNIV_INTERN
03515 void
03516 log_mem_free(void)
03517 /*==============*/
03518 {
03519   if (log_sys != NULL) {
03520     recv_sys_mem_free();
03521     mem_free(log_sys);
03522 
03523     log_sys = NULL;
03524   }
03525 }
03526 #endif /* !UNIV_HOTBACKUP */