Drizzled Public API Documentation

log0log.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1995, 2010, Innobase Oy. All Rights Reserved.
4 Copyright (C) 2009 Google Inc.
5 
6 Portions of this file contain modifications contributed and copyrighted by
7 Google, Inc. Those modifications are gratefully acknowledged and are described
8 briefly in the InnoDB documentation. The contributions by Google are
9 incorporated with their permission, and subject to the conditions contained in
10 the file COPYING.Google.
11 
12 This program is free software; you can redistribute it and/or modify it under
13 the terms of the GNU General Public License as published by the Free Software
14 Foundation; version 2 of the License.
15 
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22 St, Fifth Floor, Boston, MA 02110-1301 USA
23 
24 *****************************************************************************/
25 
26 /**************************************************/
33 #include "log0log.h"
34 
35 #ifdef UNIV_NONINL
36 #include "log0log.ic"
37 #endif
38 
39 #ifndef UNIV_HOTBACKUP
40 #include "mem0mem.h"
41 #include "buf0buf.h"
42 #include "buf0flu.h"
43 #include "srv0srv.h"
44 #include "log0recv.h"
45 #include "fil0fil.h"
46 #include "dict0boot.h"
47 #include "srv0srv.h"
48 #include "srv0start.h"
49 #include "trx0sys.h"
50 #include "trx0trx.h"
51 #include "ha_prototypes.h"
52 
53 #include <drizzled/errmsg_print.h>
54 
55 /*
56 General philosophy of InnoDB redo-logs:
57 
58 1) Every change to a contents of a data page must be done
59 through mtr, which in mtr_commit() writes log records
60 to the InnoDB redo log.
61 
62 2) Normally these changes are performed using a mlog_write_ulint()
63 or similar function.
64 
65 3) In some page level operations only a code number of a
66 c-function and its parameters are written to the log to
67 reduce the size of the log.
68 
69  3a) You should not add parameters to these kind of functions
70  (e.g. trx_undo_header_create(), trx_undo_insert_header_reuse())
71 
72  3b) You should not add such functionality which either change
73  working when compared with the old or are dependent on data
74  outside of the page. These kind of functions should implement
75  self-contained page transformation and it should be unchanged
76  if you don't have very essential reasons to change log
77  semantics or format.
78 
79 */
80 
81 /* Current free limit of space 0; protected by the log sys mutex; 0 means
82 uninitialized */
83 UNIV_INTERN ulint log_fsp_current_free_limit = 0;
84 
85 /* Global log system variable */
86 UNIV_INTERN log_t* log_sys = NULL;
87 
88 #ifdef UNIV_PFS_RWLOCK
89 UNIV_INTERN mysql_pfs_key_t checkpoint_lock_key;
90 # ifdef UNIV_LOG_ARCHIVE
91 UNIV_INTERN mysql_pfs_key_t archive_lock_key;
92 # endif
93 #endif /* UNIV_PFS_RWLOCK */
94 
95 #ifdef UNIV_PFS_MUTEX
96 UNIV_INTERN mysql_pfs_key_t log_sys_mutex_key;
97 UNIV_INTERN mysql_pfs_key_t log_flush_order_mutex_key;
98 #endif /* UNIV_PFS_MUTEX */
99 
100 #ifdef UNIV_DEBUG
101 UNIV_INTERN ibool log_do_write = TRUE;
102 #endif /* UNIV_DEBUG */
103 
104 /* These control how often we print warnings if the last checkpoint is too
105 old */
106 UNIV_INTERN ibool log_has_printed_chkp_warning = FALSE;
107 UNIV_INTERN time_t log_last_warning_time;
108 
109 #ifdef UNIV_LOG_ARCHIVE
110 /* Pointer to this variable is used as the i/o-message when we do i/o to an
111 archive */
112 UNIV_INTERN byte log_archive_io;
113 #endif /* UNIV_LOG_ARCHIVE */
114 
115 /* A margin for free space in the log buffer before a log entry is catenated */
116 #define LOG_BUF_WRITE_MARGIN (4 * OS_FILE_LOG_BLOCK_SIZE)
117 
118 /* Margins for free space in the log buffer after a log entry is catenated */
119 #define LOG_BUF_FLUSH_RATIO 2
120 #define LOG_BUF_FLUSH_MARGIN (LOG_BUF_WRITE_MARGIN + 4 * UNIV_PAGE_SIZE)
121 
122 /* Margin for the free space in the smallest log group, before a new query
123 step which modifies the database, is started */
124 
125 #define LOG_CHECKPOINT_FREE_PER_THREAD (4 * UNIV_PAGE_SIZE)
126 #define LOG_CHECKPOINT_EXTRA_FREE (8 * UNIV_PAGE_SIZE)
127 
128 /* This parameter controls asynchronous making of a new checkpoint; the value
129 should be bigger than LOG_POOL_PREFLUSH_RATIO_SYNC */
130 
131 #define LOG_POOL_CHECKPOINT_RATIO_ASYNC 32
132 
133 /* This parameter controls synchronous preflushing of modified buffer pages */
134 #define LOG_POOL_PREFLUSH_RATIO_SYNC 16
135 
136 /* The same ratio for asynchronous preflushing; this value should be less than
137 the previous */
138 #define LOG_POOL_PREFLUSH_RATIO_ASYNC 8
139 
140 /* Extra margin, in addition to one log file, used in archiving */
141 #define LOG_ARCHIVE_EXTRA_MARGIN (4 * UNIV_PAGE_SIZE)
142 
143 /* This parameter controls asynchronous writing to the archive */
144 #define LOG_ARCHIVE_RATIO_ASYNC 16
145 
146 /* Codes used in unlocking flush latches */
147 #define LOG_UNLOCK_NONE_FLUSHED_LOCK 1
148 #define LOG_UNLOCK_FLUSH_LOCK 2
149 
150 /* States of an archiving operation */
151 #define LOG_ARCHIVE_READ 1
152 #define LOG_ARCHIVE_WRITE 2
153 
154 /******************************************************/
156 static
157 void
158 log_io_complete_checkpoint(void);
159 /*============================*/
160 #ifdef UNIV_LOG_ARCHIVE
161 /******************************************************/
163 static
164 void
165 log_io_complete_archive(void);
166 /*=========================*/
167 #endif /* UNIV_LOG_ARCHIVE */
168 
169 /****************************************************************/
173 UNIV_INTERN
174 void
176 /*==========================================*/
177  ulint limit)
178 {
179  ibool success;
180 
181  mutex_enter(&(log_sys->mutex));
182 
183  log_fsp_current_free_limit = limit;
184 
185  mutex_exit(&(log_sys->mutex));
186 
187  /* Try to make a synchronous checkpoint */
188 
189  success = FALSE;
190 
191  while (!success) {
192  success = log_checkpoint(TRUE, TRUE);
193  }
194 }
195 
196 /****************************************************************/
200 static
201 ib_uint64_t
202 log_buf_pool_get_oldest_modification(void)
203 /*======================================*/
204 {
205  ib_uint64_t lsn;
206 
207  ut_ad(mutex_own(&(log_sys->mutex)));
208 
210 
211  if (!lsn) {
212 
213  lsn = log_sys->lsn;
214  }
215 
216  return(lsn);
217 }
218 
219 /************************************************************/
223 UNIV_INTERN
224 ib_uint64_t
226 /*=================*/
227  ulint len)
228 {
229  log_t* log = log_sys;
230  ulint len_upper_limit;
231 #ifdef UNIV_LOG_ARCHIVE
232  ulint archived_lsn_age;
233  ulint dummy;
234 #endif /* UNIV_LOG_ARCHIVE */
235 #ifdef UNIV_DEBUG
236  ulint count = 0;
237 #endif /* UNIV_DEBUG */
238 
239  ut_a(len < log->buf_size / 2);
240 loop:
241  mutex_enter(&(log->mutex));
242  ut_ad(!recv_no_log_write);
243 
244  /* Calculate an upper limit for the space the string may take in the
245  log buffer */
246 
247  len_upper_limit = LOG_BUF_WRITE_MARGIN + (5 * len) / 4;
248 
249  if (log->buf_free + len_upper_limit > log->buf_size) {
250 
251  mutex_exit(&(log->mutex));
252 
253  /* Not enough free space, do a syncronous flush of the log
254  buffer */
255 
257 
258  srv_log_waits++;
259 
260  ut_ad(++count < 50);
261 
262  goto loop;
263  }
264 
265 #ifdef UNIV_LOG_ARCHIVE
266  if (log->archiving_state != LOG_ARCH_OFF) {
267 
268  archived_lsn_age = log->lsn - log->archived_lsn;
269  if (archived_lsn_age + len_upper_limit
270  > log->max_archived_lsn_age) {
271  /* Not enough free archived space in log groups: do a
272  synchronous archive write batch: */
273 
274  mutex_exit(&(log->mutex));
275 
276  ut_ad(len_upper_limit <= log->max_archived_lsn_age);
277 
278  log_archive_do(TRUE, &dummy);
279 
280  ut_ad(++count < 50);
281 
282  goto loop;
283  }
284  }
285 #endif /* UNIV_LOG_ARCHIVE */
286 
287 #ifdef UNIV_LOG_DEBUG
288  log->old_buf_free = log->buf_free;
289  log->old_lsn = log->lsn;
290 #endif
291  return(log->lsn);
292 }
293 
294 /************************************************************/
297 UNIV_INTERN
298 void
300 /*==========*/
301  byte* str,
302  ulint str_len)
303 {
304  log_t* log = log_sys;
305  ulint len;
306  ulint data_len;
307  byte* log_block;
308 
309  ut_ad(mutex_own(&(log->mutex)));
310 part_loop:
311  ut_ad(!recv_no_log_write);
312  /* Calculate a part length */
313 
314  data_len = (log->buf_free % OS_FILE_LOG_BLOCK_SIZE) + str_len;
315 
316  if (data_len <= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
317 
318  /* The string fits within the current log block */
319 
320  len = str_len;
321  } else {
322  data_len = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE;
323 
326  - LOG_BLOCK_TRL_SIZE;
327  }
328 
329  ut_memcpy(log->buf + log->buf_free, str, len);
330 
331  str_len -= len;
332  str = str + len;
333 
334  log_block = static_cast<unsigned char *>(ut_align_down(log->buf + log->buf_free,
336  log_block_set_data_len(log_block, data_len);
337 
338  if (data_len == OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) {
339  /* This block became full */
341  log_block_set_checkpoint_no(log_block,
342  log_sys->next_checkpoint_no);
343  len += LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE;
344 
345  log->lsn += len;
346 
347  /* Initialize the next block header */
348  log_block_init(log_block + OS_FILE_LOG_BLOCK_SIZE, log->lsn);
349  } else {
350  log->lsn += len;
351  }
352 
353  log->buf_free += len;
354 
355  ut_ad(log->buf_free <= log->buf_size);
356 
357  if (str_len > 0) {
358  goto part_loop;
359  }
360 
361  srv_log_write_requests++;
362 }
363 
364 /************************************************************/
366 UNIV_INLINE
367 ulint
368 log_max_modified_age_async()
369 /*========================*/
370 {
371  if (srv_checkpoint_age_target) {
372  return(ut_min(log_sys->max_modified_age_async,
373  srv_checkpoint_age_target
374  - srv_checkpoint_age_target / 8));
375  } else {
376  return(log_sys->max_modified_age_async);
377  }
378 }
379 
380 /************************************************************/
382 UNIV_INLINE
383 ulint
384 log_max_checkpoint_age_async()
385 /*==========================*/
386 {
387  if (srv_checkpoint_age_target) {
388  return(ut_min(log_sys->max_checkpoint_age_async,
389  srv_checkpoint_age_target));
390  } else {
391  return(log_sys->max_checkpoint_age_async);
392  }
393 }
394 
395 
396 
397 /************************************************************/
400 UNIV_INTERN
401 ib_uint64_t
403 /*===========*/
404 {
405  byte* log_block;
406  ulint first_rec_group;
407  ib_uint64_t oldest_lsn;
408  ib_uint64_t lsn;
409  log_t* log = log_sys;
410  ib_uint64_t checkpoint_age;
411 
412  ut_ad(mutex_own(&(log->mutex)));
413  ut_ad(!recv_no_log_write);
414 
415  lsn = log->lsn;
416 
417  log_block = static_cast<unsigned char *>(ut_align_down(log->buf + log->buf_free,
419  first_rec_group = log_block_get_first_rec_group(log_block);
420 
421  if (first_rec_group == 0) {
422  /* We initialized a new log block which was not written
423  full by the current mtr: the next mtr log record group
424  will start within this block at the offset data_len */
425 
427  log_block, log_block_get_data_len(log_block));
428  }
429 
430  if (log->buf_free > log->max_buf_free) {
431 
432  log->check_flush_or_checkpoint = TRUE;
433  }
434 
435  checkpoint_age = lsn - log->last_checkpoint_lsn;
436 
437  if (checkpoint_age >= log->log_group_capacity) {
438  /* TODO: split btr_store_big_rec_extern_fields() into small
439  steps so that we can release all latches in the middle, and
440  call log_free_check() to ensure we never write over log written
441  after the latest checkpoint. In principle, we should split all
442  big_rec operations, but other operations are smaller. */
443 
444  if (!log_has_printed_chkp_warning
445  || difftime(time(NULL), log_last_warning_time) > 15) {
446 
447  log_has_printed_chkp_warning = TRUE;
448  log_last_warning_time = time(NULL);
449 
450  ut_print_timestamp(stderr);
451  fprintf(stderr,
452  " InnoDB: ERROR: the age of the last"
453  " checkpoint is %lu,\n"
454  "InnoDB: which exceeds the log group"
455  " capacity %lu.\n"
456  "InnoDB: If you are using big"
457  " BLOB or TEXT rows, you must set the\n"
458  "InnoDB: combined size of log files"
459  " at least 10 times bigger than the\n"
460  "InnoDB: largest such row.\n",
461  (ulong) checkpoint_age,
462  (ulong) log->log_group_capacity);
463  }
464  }
465 
466  if (checkpoint_age <= log_max_modified_age_async()) {
467 
468  goto function_exit;
469  }
470 
471  oldest_lsn = buf_pool_get_oldest_modification();
472 
473  if (!oldest_lsn
474  || lsn - oldest_lsn > log_max_modified_age_async()
475  || checkpoint_age > log_max_checkpoint_age_async()) {
476 
477  log->check_flush_or_checkpoint = TRUE;
478  }
479 function_exit:
480 
481 #ifdef UNIV_LOG_DEBUG
482  log_check_log_recs(log->buf + log->old_buf_free,
483  log->buf_free - log->old_buf_free, log->old_lsn);
484 #endif
485 
486  return(lsn);
487 }
488 
489 #ifdef UNIV_LOG_ARCHIVE
490 /******************************************************/
493 static
494 void
495 log_pad_current_log_block(void)
496 /*===========================*/
497 {
498  byte b = MLOG_DUMMY_RECORD;
499  ulint pad_length;
500  ulint i;
501  ib_uint64_t lsn;
502 
503  /* We retrieve lsn only because otherwise gcc crashed on HP-UX */
505 
506  pad_length = OS_FILE_LOG_BLOCK_SIZE
507  - (log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE)
508  - LOG_BLOCK_TRL_SIZE;
509 
510  for (i = 0; i < pad_length; i++) {
511  log_write_low(&b, 1);
512  }
513 
514  lsn = log_sys->lsn;
515 
516  log_close();
517  log_release();
518 
519  ut_a(lsn % OS_FILE_LOG_BLOCK_SIZE == LOG_BLOCK_HDR_SIZE);
520 }
521 #endif /* UNIV_LOG_ARCHIVE */
522 
523 /******************************************************/
527 UNIV_INTERN
528 ulint
530 /*===================*/
531  const log_group_t* group)
532 {
533  ut_ad(mutex_own(&(log_sys->mutex)));
534 
535  return((group->file_size - LOG_FILE_HDR_SIZE) * group->n_files);
536 }
537 
538 /******************************************************/
542 UNIV_INLINE
543 ulint
544 log_group_calc_size_offset(
545 /*=======================*/
546  ulint offset,
548  const log_group_t* group)
549 {
550  ut_ad(mutex_own(&(log_sys->mutex)));
551 
552  return(offset - LOG_FILE_HDR_SIZE * (1 + offset / group->file_size));
553 }
554 
555 /******************************************************/
559 UNIV_INLINE
560 ulint
561 log_group_calc_real_offset(
562 /*=======================*/
563  ulint offset,
565  const log_group_t* group)
566 {
567  ut_ad(mutex_own(&(log_sys->mutex)));
568 
569  return(offset + LOG_FILE_HDR_SIZE
570  * (1 + offset / (group->file_size - LOG_FILE_HDR_SIZE)));
571 }
572 
573 /******************************************************/
576 static
577 ulint
578 log_group_calc_lsn_offset(
579 /*======================*/
580  ib_uint64_t lsn,
582  const log_group_t* group)
583 {
584  ib_uint64_t gr_lsn;
585  ib_int64_t gr_lsn_size_offset;
586  ib_int64_t difference;
587  ib_int64_t group_size;
588  ib_int64_t offset;
589 
590  ut_ad(mutex_own(&(log_sys->mutex)));
591 
592  /* If total log file size is > 2 GB we can easily get overflows
593  with 32-bit integers. Use 64-bit integers instead. */
594 
595  gr_lsn = group->lsn;
596 
597  gr_lsn_size_offset = (ib_int64_t)
598  log_group_calc_size_offset(group->lsn_offset, group);
599 
600  group_size = (ib_int64_t) log_group_get_capacity(group);
601 
602  if (lsn >= gr_lsn) {
603 
604  difference = (ib_int64_t) (lsn - gr_lsn);
605  } else {
606  difference = (ib_int64_t) (gr_lsn - lsn);
607 
608  difference = difference % group_size;
609 
610  difference = group_size - difference;
611  }
612 
613  offset = (gr_lsn_size_offset + difference) % group_size;
614 
615  /* Offset must be < 4 GB on 32 bit systems */
616  ut_a((sizeof(ulint) != 4) || (offset < (((ib_int64_t) 1) << 32)));
617 
618  /* fprintf(stderr,
619  "Offset is %lu gr_lsn_offset is %lu difference is %lu\n",
620  (ulint)offset,(ulint)gr_lsn_size_offset, (ulint)difference);
621  */
622 
623  return(log_group_calc_real_offset((ulint)offset, group));
624 }
625 #endif /* !UNIV_HOTBACKUP */
626 
627 #ifdef UNIV_DEBUG
628 UNIV_INTERN ibool log_debug_writes = FALSE;
629 #endif /* UNIV_DEBUG */
630 
631 /*******************************************************************/
634 UNIV_INTERN
635 ulint
637 /*==================*/
638  ib_int64_t* log_file_offset,
640  ib_uint64_t first_header_lsn,
642  ib_uint64_t lsn,
644  ulint n_log_files,
646  ib_int64_t log_file_size)
648 {
649  ib_int64_t capacity = log_file_size - LOG_FILE_HDR_SIZE;
650  ulint file_no;
651  ib_int64_t add_this_many;
652 
653  if (lsn < first_header_lsn) {
654  add_this_many = 1 + (first_header_lsn - lsn)
655  / (capacity * (ib_int64_t)n_log_files);
656  lsn += add_this_many
657  * capacity * (ib_int64_t)n_log_files;
658  }
659 
660  ut_a(lsn >= first_header_lsn);
661 
662  file_no = ((ulint)((lsn - first_header_lsn) / capacity))
663  % n_log_files;
664  *log_file_offset = (lsn - first_header_lsn) % capacity;
665 
666  *log_file_offset = *log_file_offset + LOG_FILE_HDR_SIZE;
667 
668  return(file_no);
669 }
670 
671 #ifndef UNIV_HOTBACKUP
672 /********************************************************/
676 UNIV_INTERN
677 void
679 /*=================*/
680  log_group_t* group,
681  ib_uint64_t lsn)
683 {
684  group->lsn_offset = log_group_calc_lsn_offset(lsn, group);
685  group->lsn = lsn;
686 }
687 
688 /*****************************************************************/
693 static
694 ibool
695 log_calc_max_ages(void)
696 /*===================*/
697 {
698  log_group_t* group;
699  ulint margin;
700  ulint free;
701  ibool success = TRUE;
702  ulint smallest_capacity;
703  ulint archive_margin;
704  ulint smallest_archive_margin;
705 
706  mutex_enter(&(log_sys->mutex));
707 
708  group = UT_LIST_GET_FIRST(log_sys->log_groups);
709 
710  ut_ad(group);
711 
712  smallest_capacity = ULINT_MAX;
713  smallest_archive_margin = ULINT_MAX;
714 
715  while (group) {
716  if (log_group_get_capacity(group) < smallest_capacity) {
717 
718  smallest_capacity = log_group_get_capacity(group);
719  }
720 
721  archive_margin = log_group_get_capacity(group)
722  - (group->file_size - LOG_FILE_HDR_SIZE)
723  - LOG_ARCHIVE_EXTRA_MARGIN;
724 
725  if (archive_margin < smallest_archive_margin) {
726 
727  smallest_archive_margin = archive_margin;
728  }
729 
730  group = UT_LIST_GET_NEXT(log_groups, group);
731  }
732 
733  /* Add extra safety */
734  smallest_capacity = smallest_capacity - smallest_capacity / 10;
735 
736  /* For each OS thread we must reserve so much free space in the
737  smallest log group that it can accommodate the log entries produced
738  by single query steps: running out of free log space is a serious
739  system error which requires rebooting the database. */
740 
741  free = LOG_CHECKPOINT_FREE_PER_THREAD * (10 + srv_thread_concurrency)
742  + LOG_CHECKPOINT_EXTRA_FREE;
743  if (free >= smallest_capacity / 2) {
744  success = FALSE;
745 
746  goto failure;
747  } else {
748  margin = smallest_capacity - free;
749  }
750 
751  margin = ut_min(margin, log_sys->adm_checkpoint_interval);
752 
753  margin = margin - margin / 10; /* Add still some extra safety */
754 
755  log_sys->log_group_capacity = smallest_capacity;
756 
757  log_sys->max_modified_age_async = margin
758  - margin / LOG_POOL_PREFLUSH_RATIO_ASYNC;
759  log_sys->max_modified_age_sync = margin
760  - margin / LOG_POOL_PREFLUSH_RATIO_SYNC;
761 
762  log_sys->max_checkpoint_age_async = margin - margin
763  / LOG_POOL_CHECKPOINT_RATIO_ASYNC;
764  log_sys->max_checkpoint_age = margin;
765 
766 #ifdef UNIV_LOG_ARCHIVE
767  log_sys->max_archived_lsn_age = smallest_archive_margin;
768 
769  log_sys->max_archived_lsn_age_async = smallest_archive_margin
770  - smallest_archive_margin / LOG_ARCHIVE_RATIO_ASYNC;
771 #endif /* UNIV_LOG_ARCHIVE */
772 failure:
773  mutex_exit(&(log_sys->mutex));
774 
775  if (!success) {
776  fprintf(stderr,
777  "InnoDB: Error: ib_logfiles are too small"
778  " for innodb_thread_concurrency %lu.\n"
779  "InnoDB: The combined size of ib_logfiles"
780  " should be bigger than\n"
781  "InnoDB: 200 kB * innodb_thread_concurrency.\n"
782  "InnoDB: To get mysqld to start up, set"
783  " innodb_thread_concurrency in my.cnf\n"
784  "InnoDB: to a lower value, for example, to 8."
785  " After an ERROR-FREE shutdown\n"
786  "InnoDB: of mysqld you can adjust the size of"
787  " ib_logfiles, as explained in\n"
788  "InnoDB: " REFMAN "adding-and-removing.html\n"
789  "InnoDB: Cannot continue operation."
790  " Calling exit(1).\n",
791  (ulong)srv_thread_concurrency);
792 
793  exit(1);
794  }
795 
796  return(success);
797 }
798 
799 /******************************************************/
801 UNIV_INTERN
802 void
803 log_init(void)
804 /*==========*/
805 {
806  log_sys = static_cast<log_t *>(mem_alloc(sizeof(log_t)));
807 
808  mutex_create(log_sys_mutex_key, &log_sys->mutex, SYNC_LOG);
809 
810  mutex_create(log_flush_order_mutex_key,
811  &log_sys->log_flush_order_mutex,
812  SYNC_LOG_FLUSH_ORDER);
813 
814  mutex_enter(&(log_sys->mutex));
815 
816  /* Start the lsn from one log block from zero: this way every
817  log record has a start lsn != zero, a fact which we will use */
818 
819  log_sys->lsn = LOG_START_LSN;
820 
821  ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE);
822  ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE);
823 
824  log_sys->buf_ptr = static_cast<unsigned char *>(mem_alloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE));
825  log_sys->buf = static_cast<unsigned char *>(ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE));
826 
827  log_sys->buf_size = LOG_BUFFER_SIZE;
828 
829  memset(log_sys->buf, '\0', LOG_BUFFER_SIZE);
830 
831  log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO
832  - LOG_BUF_FLUSH_MARGIN;
833  log_sys->check_flush_or_checkpoint = TRUE;
834  UT_LIST_INIT(log_sys->log_groups);
835 
836  log_sys->n_log_ios = 0;
837 
838  log_sys->n_log_ios_old = log_sys->n_log_ios;
839  log_sys->last_printout_time = time(NULL);
840  /*----------------------------*/
841 
842  log_sys->buf_next_to_write = 0;
843 
844  log_sys->write_lsn = 0;
845  log_sys->current_flush_lsn = 0;
846  log_sys->flushed_to_disk_lsn = 0;
847 
848  log_sys->written_to_some_lsn = log_sys->lsn;
849  log_sys->written_to_all_lsn = log_sys->lsn;
850 
851  log_sys->n_pending_writes = 0;
852 
853  log_sys->no_flush_event = os_event_create(NULL);
854 
855  os_event_set(log_sys->no_flush_event);
856 
857  log_sys->one_flushed_event = os_event_create(NULL);
858 
860 
861  /*----------------------------*/
862  log_sys->adm_checkpoint_interval = ULINT_MAX;
863 
864  log_sys->next_checkpoint_no = 0;
865  log_sys->last_checkpoint_lsn = log_sys->lsn;
866  log_sys->n_pending_checkpoint_writes = 0;
867 
868  rw_lock_create(checkpoint_lock_key, &log_sys->checkpoint_lock,
869  SYNC_NO_ORDER_CHECK);
870 
871  log_sys->checkpoint_buf_ptr = static_cast<unsigned char *>(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE));
872  log_sys->checkpoint_buf = static_cast<unsigned char *>(ut_align(log_sys->checkpoint_buf_ptr,
874  memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
875  /*----------------------------*/
876 
877 #ifdef UNIV_LOG_ARCHIVE
878  /* Under MySQL, log archiving is always off */
879  log_sys->archiving_state = LOG_ARCH_OFF;
880  log_sys->archived_lsn = log_sys->lsn;
881  log_sys->next_archived_lsn = 0;
882 
883  log_sys->n_pending_archive_ios = 0;
884 
885  rw_lock_create(archive_lock_key, &log_sys->archive_lock,
886  SYNC_NO_ORDER_CHECK);
887 
888  log_sys->archive_buf = NULL;
889 
890  /* ut_align(
891  ut_malloc(LOG_ARCHIVE_BUF_SIZE
892  + OS_FILE_LOG_BLOCK_SIZE),
893  OS_FILE_LOG_BLOCK_SIZE); */
894  log_sys->archive_buf_size = 0;
895 
896  /* memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE); */
897 
898  log_sys->archiving_on = os_event_create(NULL);
899 #endif /* UNIV_LOG_ARCHIVE */
900 
901  /*----------------------------*/
902 
903  log_block_init(log_sys->buf, log_sys->lsn);
904  log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE);
905 
906  log_sys->buf_free = LOG_BLOCK_HDR_SIZE;
907  log_sys->lsn = LOG_START_LSN + LOG_BLOCK_HDR_SIZE;
908 
909  mutex_exit(&(log_sys->mutex));
910 
911 #ifdef UNIV_LOG_DEBUG
912  recv_sys_create();
914 
915  recv_sys->parse_start_lsn = log_sys->lsn;
916  recv_sys->scanned_lsn = log_sys->lsn;
918  recv_sys->recovered_lsn = log_sys->lsn;
919  recv_sys->limit_lsn = IB_ULONGLONG_MAX;
920 #endif
921 }
922 
923 /******************************************************************/
925 UNIV_INTERN
926 void
928 /*===========*/
929  ulint id,
930  ulint n_files,
931  ulint file_size,
932  ulint space_id,
935  ulint /*archive_space_id __attribute__((unused))*/)
941 {
942  ulint i;
943 
944  log_group_t* group;
945 
946  group = static_cast<log_group_t *>(mem_alloc(sizeof(log_group_t)));
947 
948  group->id = id;
949  group->n_files = n_files;
950  group->file_size = file_size;
951  group->space_id = space_id;
952  group->state = LOG_GROUP_OK;
953  group->lsn = LOG_START_LSN;
954  group->lsn_offset = LOG_FILE_HDR_SIZE;
955  group->n_pending_writes = 0;
956 
957  group->file_header_bufs_ptr = static_cast<unsigned char **>(mem_alloc(sizeof(byte*) * n_files));
958  group->file_header_bufs = static_cast<unsigned char **>(mem_alloc(sizeof(byte*) * n_files));
959 #ifdef UNIV_LOG_ARCHIVE
960  group->archive_file_header_bufs_ptr = mem_alloc(
961  sizeof(byte*) * n_files);
962  group->archive_file_header_bufs = mem_alloc(sizeof(byte*) * n_files);
963 #endif /* UNIV_LOG_ARCHIVE */
964 
965  for (i = 0; i < n_files; i++) {
966  group->file_header_bufs_ptr[i] = static_cast<unsigned char *>(mem_alloc(
967  LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE));
968 
969  group->file_header_bufs[i] = static_cast<unsigned char *>(ut_align(
970  group->file_header_bufs_ptr[i],
972 
973  memset(*(group->file_header_bufs + i), '\0',
974  LOG_FILE_HDR_SIZE);
975 
976 #ifdef UNIV_LOG_ARCHIVE
977  group->archive_file_header_bufs_ptr[i] = mem_alloc(
978  LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
979 
980  group->archive_file_header_bufs[i] = ut_align(
981  group->archive_file_header_bufs_ptr[i],
983 
984  memset(*(group->archive_file_header_bufs + i), '\0',
985  LOG_FILE_HDR_SIZE);
986 #endif /* UNIV_LOG_ARCHIVE */
987  }
988 
989 #ifdef UNIV_LOG_ARCHIVE
990  group->archive_space_id = archive_space_id;
991 
992  group->archived_file_no = 0;
993  group->archived_offset = 0;
994 #endif /* UNIV_LOG_ARCHIVE */
995 
996  group->checkpoint_buf_ptr = static_cast<unsigned char *>(mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE));
997  group->checkpoint_buf = static_cast<unsigned char*>(ut_align(group->checkpoint_buf_ptr,
999 
1000  memset(group->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
1001 
1002  UT_LIST_ADD_LAST(log_groups, log_sys->log_groups, group);
1003 
1004  ut_a(log_calc_max_ages());
1005 }
1006 
1007 /******************************************************************/
1009 UNIV_INLINE
1010 void
1011 log_flush_do_unlocks(
1012 /*=================*/
1013  ulint code)
1015 {
1016  ut_ad(mutex_own(&(log_sys->mutex)));
1017 
1018  /* NOTE that we must own the log mutex when doing the setting of the
1019  events: this is because transactions will wait for these events to
1020  be set, and at that moment the log flush they were waiting for must
1021  have ended. If the log mutex were not reserved here, the i/o-thread
1022  calling this function might be preempted for a while, and when it
1023  resumed execution, it might be that a new flush had been started, and
1024  this function would erroneously signal the NEW flush as completed.
1025  Thus, the changes in the state of these events are performed
1026  atomically in conjunction with the changes in the state of
1027  log_sys->n_pending_writes etc. */
1028 
1029  if (code & LOG_UNLOCK_NONE_FLUSHED_LOCK) {
1030  os_event_set(log_sys->one_flushed_event);
1031  }
1032 
1033  if (code & LOG_UNLOCK_FLUSH_LOCK) {
1034  os_event_set(log_sys->no_flush_event);
1035  }
1036 }
1037 
1038 /******************************************************************/
1042 UNIV_INLINE
1043 ulint
1044 log_group_check_flush_completion(
1045 /*=============================*/
1046  log_group_t* group)
1047 {
1048  ut_ad(mutex_own(&(log_sys->mutex)));
1049 
1050  if (!log_sys->one_flushed && group->n_pending_writes == 0) {
1051 #ifdef UNIV_DEBUG
1052  if (log_debug_writes) {
1053  fprintf(stderr,
1054  "Log flushed first to group %lu\n",
1055  (ulong) group->id);
1056  }
1057 #endif /* UNIV_DEBUG */
1058  log_sys->written_to_some_lsn = log_sys->write_lsn;
1059  log_sys->one_flushed = TRUE;
1060 
1061  return(LOG_UNLOCK_NONE_FLUSHED_LOCK);
1062  }
1063 
1064 #ifdef UNIV_DEBUG
1065  if (log_debug_writes && (group->n_pending_writes == 0)) {
1066 
1067  fprintf(stderr, "Log flushed to group %lu\n",
1068  (ulong) group->id);
1069  }
1070 #endif /* UNIV_DEBUG */
1071  return(0);
1072 }
1073 
1074 /******************************************************/
1077 static
1078 ulint
1079 log_sys_check_flush_completion(void)
1080 /*================================*/
1081 {
1082  ulint move_start;
1083  ulint move_end;
1084 
1085  ut_ad(mutex_own(&(log_sys->mutex)));
1086 
1087  if (log_sys->n_pending_writes == 0) {
1088 
1089  log_sys->written_to_all_lsn = log_sys->write_lsn;
1090  log_sys->buf_next_to_write = log_sys->write_end_offset;
1091 
1092  if (log_sys->write_end_offset > log_sys->max_buf_free / 2) {
1093  /* Move the log buffer content to the start of the
1094  buffer */
1095 
1096  move_start = ut_calc_align_down(
1097  log_sys->write_end_offset,
1099  move_end = ut_calc_align(log_sys->buf_free,
1101 
1102  ut_memmove(log_sys->buf, log_sys->buf + move_start,
1103  move_end - move_start);
1104  log_sys->buf_free -= move_start;
1105 
1106  log_sys->buf_next_to_write -= move_start;
1107  }
1108 
1109  return(LOG_UNLOCK_FLUSH_LOCK);
1110  }
1111 
1112  return(0);
1113 }
1114 
1115 /******************************************************/
1117 UNIV_INTERN
1118 void
1120 /*============*/
1121  log_group_t* group)
1122 {
1123  ulint unlock;
1124 
1125 #ifdef UNIV_LOG_ARCHIVE
1126  if ((byte*)group == &log_archive_io) {
1127  /* It was an archive write */
1128 
1129  log_io_complete_archive();
1130 
1131  return;
1132  }
1133 #endif /* UNIV_LOG_ARCHIVE */
1134 
1135  if ((ulint)group & 0x1UL) {
1136  /* It was a checkpoint write */
1137  group = (log_group_t*)((ulint)group - 1);
1138 
1139  if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
1140  && srv_unix_file_flush_method != SRV_UNIX_ALL_O_DIRECT
1141  && srv_unix_file_flush_method != SRV_UNIX_NOSYNC) {
1142 
1143  fil_flush(group->space_id);
1144  }
1145 
1146 #ifdef UNIV_DEBUG
1147  if (log_debug_writes) {
1148  fprintf(stderr,
1149  "Checkpoint info written to group %lu\n",
1150  group->id);
1151  }
1152 #endif /* UNIV_DEBUG */
1153  log_io_complete_checkpoint();
1154 
1155  return;
1156  }
1157 
1158  ut_error;
1161  if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC
1162  && srv_unix_file_flush_method != SRV_UNIX_ALL_O_DIRECT
1163  && srv_unix_file_flush_method != SRV_UNIX_NOSYNC
1164  && srv_flush_log_at_trx_commit != 2) {
1165 
1166  fil_flush(group->space_id);
1167  }
1168 
1169  mutex_enter(&(log_sys->mutex));
1170  ut_ad(!recv_no_log_write);
1171 
1172  ut_a(group->n_pending_writes > 0);
1173  ut_a(log_sys->n_pending_writes > 0);
1174 
1175  group->n_pending_writes--;
1176  log_sys->n_pending_writes--;
1177 
1178  unlock = log_group_check_flush_completion(group);
1179  unlock = unlock | log_sys_check_flush_completion();
1180 
1181  log_flush_do_unlocks(unlock);
1182 
1183  mutex_exit(&(log_sys->mutex));
1184 }
1185 
1186 /******************************************************/
1188 static
1189 void
1190 log_group_file_header_flush(
1191 /*========================*/
1192  log_group_t* group,
1193  ulint nth_file,
1195  ib_uint64_t start_lsn)
1197 {
1198  byte* buf;
1199  ulint dest_offset;
1200 
1201  ut_ad(mutex_own(&(log_sys->mutex)));
1202  ut_ad(!recv_no_log_write);
1203  ut_a(nth_file < group->n_files);
1204 
1205  buf = *(group->file_header_bufs + nth_file);
1206 
1207  mach_write_to_4(buf + LOG_GROUP_ID, group->id);
1208  mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn);
1209 
1210  /* Wipe over possible label of ibbackup --restore */
1211  memcpy(buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, " ", 4);
1212 
1213  mach_write_to_4(buf + LOG_FILE_OS_FILE_LOG_BLOCK_SIZE,
1214  srv_log_block_size);
1215 
1216  dest_offset = nth_file * group->file_size;
1217 
1218 #ifdef UNIV_DEBUG
1219  if (log_debug_writes) {
1220  fprintf(stderr,
1221  "Writing log file header to group %lu file %lu\n",
1222  (ulong) group->id, (ulong) nth_file);
1223  }
1224 #endif /* UNIV_DEBUG */
1225  if (log_do_write) {
1226  log_sys->n_log_ios++;
1227 
1228  srv_os_log_pending_writes++;
1229 
1230  fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id, 0,
1231  dest_offset / UNIV_PAGE_SIZE,
1232  dest_offset % UNIV_PAGE_SIZE,
1234  buf, group);
1235 
1236  srv_os_log_pending_writes--;
1237  }
1238 }
1239 
1240 /******************************************************/
1244 static
1245 void
1246 log_block_store_checksum(
1247 /*=====================*/
1248  byte* block)
1249 {
1251 }
1252 
1253 /******************************************************/
1255 UNIV_INTERN
1256 void
1258 /*================*/
1259  log_group_t* group,
1260  byte* buf,
1261  ulint len,
1263  ib_uint64_t start_lsn,
1266  ulint new_data_offset)
1270 {
1271  ulint write_len;
1272  ibool write_header;
1273  ulint next_offset;
1274  ulint i;
1275 
1276  ut_ad(mutex_own(&(log_sys->mutex)));
1277  ut_ad(!recv_no_log_write);
1278  ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0);
1279  ut_a(((ulint) start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
1280 
1281  if (new_data_offset == 0) {
1282  write_header = TRUE;
1283  } else {
1284  write_header = FALSE;
1285  }
1286 loop:
1287  if (len == 0) {
1288 
1289  return;
1290  }
1291 
1292  next_offset = log_group_calc_lsn_offset(start_lsn, group);
1293 
1294  if ((next_offset % group->file_size == LOG_FILE_HDR_SIZE)
1295  && write_header) {
1296  /* We start to write a new log file instance in the group */
1297 
1298  log_group_file_header_flush(group,
1299  next_offset / group->file_size,
1300  start_lsn);
1301  srv_os_log_written+= OS_FILE_LOG_BLOCK_SIZE;
1302  srv_log_writes++;
1303  }
1304 
1305  if ((next_offset % group->file_size) + len > group->file_size) {
1306 
1307  write_len = group->file_size
1308  - (next_offset % group->file_size);
1309  } else {
1310  write_len = len;
1311  }
1312 
1313 #ifdef UNIV_DEBUG
1314  if (log_debug_writes) {
1315 
1316  fprintf(stderr,
1317  "Writing log file segment to group %lu"
1318  " offset %lu len %lu\n"
1319  "start lsn %"PRIu64"\n"
1320  "First block n:o %lu last block n:o %lu\n",
1321  (ulong) group->id, (ulong) next_offset,
1322  (ulong) write_len,
1323  start_lsn,
1324  (ulong) log_block_get_hdr_no(buf),
1325  (ulong) log_block_get_hdr_no(
1326  buf + write_len - OS_FILE_LOG_BLOCK_SIZE));
1328  == log_block_convert_lsn_to_no(start_lsn));
1329 
1330  for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) {
1331 
1332  ut_a(log_block_get_hdr_no(buf) + i
1334  buf + i * OS_FILE_LOG_BLOCK_SIZE));
1335  }
1336  }
1337 #endif /* UNIV_DEBUG */
1338  /* Calculate the checksums for each log block and write them to
1339  the trailer fields of the log blocks */
1340 
1341  for (i = 0; i < write_len / OS_FILE_LOG_BLOCK_SIZE; i++) {
1342  log_block_store_checksum(buf + i * OS_FILE_LOG_BLOCK_SIZE);
1343  }
1344 
1345  if (log_do_write) {
1346  log_sys->n_log_ios++;
1347 
1348  srv_os_log_pending_writes++;
1349 
1350  fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->space_id, 0,
1351  next_offset / UNIV_PAGE_SIZE,
1352  next_offset % UNIV_PAGE_SIZE, write_len, buf, group);
1353 
1354  srv_os_log_pending_writes--;
1355 
1356  srv_os_log_written+= write_len;
1357  srv_log_writes++;
1358  }
1359 
1360  if (write_len < len) {
1361  start_lsn += write_len;
1362  len -= write_len;
1363  buf += write_len;
1364 
1365  write_header = TRUE;
1366 
1367  goto loop;
1368  }
1369 }
1370 
1371 /******************************************************/
1376 UNIV_INTERN
1377 void
1379 /*============*/
1380  ib_uint64_t lsn,
1383  ulint wait,
1385  ibool flush_to_disk)
1388 {
1389  log_group_t* group;
1390  ulint start_offset;
1391  ulint end_offset;
1392  ulint area_start;
1393  ulint area_end;
1394 #ifdef UNIV_DEBUG
1395  ulint loop_count = 0;
1396 #endif /* UNIV_DEBUG */
1397  ulint unlock;
1398 
1399  if (recv_no_ibuf_operations || srv_fake_write) {
1400  /* Recovery is running and no operations on the log files are
1401  allowed yet (the variable name .._no_ibuf_.. is misleading) */
1402 
1403  return;
1404  }
1405 
1406 loop:
1407 #ifdef UNIV_DEBUG
1408  loop_count++;
1409 
1410  ut_ad(loop_count < 5);
1411 
1412 # if 0
1413  if (loop_count > 2) {
1414  fprintf(stderr, "Log loop count %lu\n", loop_count);
1415  }
1416 # endif
1417 #endif
1418 
1419  mutex_enter(&(log_sys->mutex));
1420  ut_ad(!recv_no_log_write);
1421 
1422  if (flush_to_disk
1423  && log_sys->flushed_to_disk_lsn >= lsn) {
1424 
1425  mutex_exit(&(log_sys->mutex));
1426 
1427  return;
1428  }
1429 
1430  if (!flush_to_disk
1431  && (log_sys->written_to_all_lsn >= lsn
1432  || (log_sys->written_to_some_lsn >= lsn
1433  && wait != LOG_WAIT_ALL_GROUPS))) {
1434 
1435  mutex_exit(&(log_sys->mutex));
1436 
1437  return;
1438  }
1439 
1440  if (log_sys->n_pending_writes > 0) {
1441  /* A write (+ possibly flush to disk) is running */
1442 
1443  if (flush_to_disk
1444  && log_sys->current_flush_lsn >= lsn) {
1445  /* The write + flush will write enough: wait for it to
1446  complete */
1447 
1448  goto do_waits;
1449  }
1450 
1451  if (!flush_to_disk
1452  && log_sys->write_lsn >= lsn) {
1453  /* The write will write enough: wait for it to
1454  complete */
1455 
1456  goto do_waits;
1457  }
1458 
1459  mutex_exit(&(log_sys->mutex));
1460 
1461  /* Wait for the write to complete and try to start a new
1462  write */
1463 
1464  os_event_wait(log_sys->no_flush_event);
1465 
1466  goto loop;
1467  }
1468 
1469  if (!flush_to_disk
1470  && log_sys->buf_free == log_sys->buf_next_to_write) {
1471  /* Nothing to write and no flush to disk requested */
1472 
1473  mutex_exit(&(log_sys->mutex));
1474 
1475  return;
1476  }
1477 
1478 #ifdef UNIV_DEBUG
1479  if (log_debug_writes) {
1480  fprintf(stderr,
1481  "Writing log from %"PRIu64" up to lsn %"PRIu64"\n",
1482  log_sys->written_to_all_lsn,
1483  log_sys->lsn);
1484  }
1485 #endif /* UNIV_DEBUG */
1486  log_sys->n_pending_writes++;
1487 
1488  group = UT_LIST_GET_FIRST(log_sys->log_groups);
1489  group->n_pending_writes++;
1492  os_event_reset(log_sys->no_flush_event);
1494 
1495  start_offset = log_sys->buf_next_to_write;
1496  end_offset = log_sys->buf_free;
1497 
1498  area_start = ut_calc_align_down(start_offset, OS_FILE_LOG_BLOCK_SIZE);
1499  area_end = ut_calc_align(end_offset, OS_FILE_LOG_BLOCK_SIZE);
1500 
1501  ut_ad(area_end - area_start > 0);
1502 
1503  log_sys->write_lsn = log_sys->lsn;
1504 
1505  if (flush_to_disk) {
1506  log_sys->current_flush_lsn = log_sys->lsn;
1507  }
1508 
1509  log_sys->one_flushed = FALSE;
1510 
1511  log_block_set_flush_bit(log_sys->buf + area_start, TRUE);
1512  log_block_set_checkpoint_no(
1513  log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
1514  log_sys->next_checkpoint_no);
1515 
1516  /* Copy the last, incompletely written, log block a log block length
1517  up, so that when the flush operation writes from the log buffer, the
1518  segment to write will not be changed by writers to the log */
1519 
1520  ut_memcpy(log_sys->buf + area_end,
1521  log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
1523 
1524  log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE;
1525  log_sys->write_end_offset = log_sys->buf_free;
1526 
1527  group = UT_LIST_GET_FIRST(log_sys->log_groups);
1528 
1529  /* Do the write to the log files */
1530 
1531  while (group) {
1533  group, log_sys->buf + area_start,
1534  area_end - area_start,
1537  start_offset - area_start);
1538 
1539  log_group_set_fields(group, log_sys->write_lsn);
1540 
1541  group = UT_LIST_GET_NEXT(log_groups, group);
1542  }
1543 
1544  mutex_exit(&(log_sys->mutex));
1545 
1546  if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC
1547  || srv_unix_file_flush_method == SRV_UNIX_ALL_O_DIRECT) {
1548  /* O_DSYNC means the OS did not buffer the log file at all:
1549  so we have also flushed to disk what we have written */
1550 
1551  log_sys->flushed_to_disk_lsn = log_sys->write_lsn;
1552 
1553  } else if (flush_to_disk) {
1554 
1555  group = UT_LIST_GET_FIRST(log_sys->log_groups);
1556 
1557  fil_flush(group->space_id);
1558  log_sys->flushed_to_disk_lsn = log_sys->write_lsn;
1559  }
1560 
1561  mutex_enter(&(log_sys->mutex));
1562 
1563  group = UT_LIST_GET_FIRST(log_sys->log_groups);
1564 
1565  ut_a(group->n_pending_writes == 1);
1566  ut_a(log_sys->n_pending_writes == 1);
1567 
1568  group->n_pending_writes--;
1569  log_sys->n_pending_writes--;
1570 
1571  unlock = log_group_check_flush_completion(group);
1572  unlock = unlock | log_sys_check_flush_completion();
1573 
1574  log_flush_do_unlocks(unlock);
1575 
1576  mutex_exit(&(log_sys->mutex));
1577 
1578  return;
1579 
1580 do_waits:
1581  mutex_exit(&(log_sys->mutex));
1582 
1583  switch (wait) {
1584  case LOG_WAIT_ONE_GROUP:
1585  os_event_wait(log_sys->one_flushed_event);
1586  break;
1587  case LOG_WAIT_ALL_GROUPS:
1588  os_event_wait(log_sys->no_flush_event);
1589  break;
1590 #ifdef UNIV_DEBUG
1591  case LOG_NO_WAIT:
1592  break;
1593  default:
1594  ut_error;
1595 #endif /* UNIV_DEBUG */
1596  }
1597 }
1598 
1599 /****************************************************************/
1601 UNIV_INTERN
1602 void
1604 /*==========================*/
1605 {
1606  ib_uint64_t lsn;
1607 
1608  mutex_enter(&(log_sys->mutex));
1609 
1610  lsn = log_sys->lsn;
1611 
1612  mutex_exit(&(log_sys->mutex));
1613 
1614  log_write_up_to(lsn, LOG_WAIT_ALL_GROUPS, TRUE);
1615 }
1616 
1617 /****************************************************************/
1622 UNIV_INTERN
1623 void
1625 /*==========================*/
1626  ibool flush)
1627 {
1628  ib_uint64_t lsn;
1629 
1630  mutex_enter(&(log_sys->mutex));
1631 
1632  lsn = log_sys->lsn;
1633 
1634  mutex_exit(&(log_sys->mutex));
1635 
1636  log_write_up_to(lsn, LOG_NO_WAIT, flush);
1637 }
1638 
1639 /********************************************************************
1640 
1641 Tries to establish a big enough margin of free space in the log buffer, such
1642 that a new log entry can be catenated without an immediate need for a flush. */
1643 static
1644 void
1645 log_flush_margin(void)
1646 /*==================*/
1647 {
1648  log_t* log = log_sys;
1649  ib_uint64_t lsn = 0;
1650 
1651  mutex_enter(&(log->mutex));
1652 
1653  if (log->buf_free > log->max_buf_free) {
1654 
1655  if (log->n_pending_writes > 0) {
1656  /* A flush is running: hope that it will provide enough
1657  free space */
1658  } else {
1659  lsn = log->lsn;
1660  }
1661  }
1662 
1663  mutex_exit(&(log->mutex));
1664 
1665  if (lsn) {
1666  log_write_up_to(lsn, LOG_NO_WAIT, FALSE);
1667  }
1668 }
1669 
1670 /****************************************************************/
1676 UNIV_INTERN
1677 ibool
1679 /*=============================*/
1680  ib_uint64_t new_oldest,
1683  ibool sync)
1685 {
1686  ulint n_pages;
1687 
1688  if (recv_recovery_on) {
1689  /* If the recovery is running, we must first apply all
1690  log records to their respective file pages to get the
1691  right modify lsn values to these pages: otherwise, there
1692  might be pages on disk which are not yet recovered to the
1693  current lsn, and even after calling this function, we could
1694  not know how up-to-date the disk version of the database is,
1695  and we could not make a new checkpoint on the basis of the
1696  info on the buffer pool only. */
1697 
1699  }
1700 
1701  n_pages = buf_flush_list(ULINT_MAX, new_oldest);
1702 
1703  if (sync) {
1705  }
1706 
1707  if (n_pages == ULINT_UNDEFINED) {
1708 
1709  return(FALSE);
1710  }
1711 
1712  return(TRUE);
1713 }
1714 
1715 /******************************************************/
1717 static
1718 void
1719 log_complete_checkpoint(void)
1720 /*=========================*/
1721 {
1722  ut_ad(mutex_own(&(log_sys->mutex)));
1723  ut_ad(log_sys->n_pending_checkpoint_writes == 0);
1724 
1725  log_sys->next_checkpoint_no++;
1726 
1727  log_sys->last_checkpoint_lsn = log_sys->next_checkpoint_lsn;
1728 
1729  rw_lock_x_unlock_gen(&(log_sys->checkpoint_lock), LOG_CHECKPOINT);
1730 }
1731 
1732 /******************************************************/
1734 static
1735 void
1736 log_io_complete_checkpoint(void)
1737 /*============================*/
1738 {
1739  mutex_enter(&(log_sys->mutex));
1740 
1741  ut_ad(log_sys->n_pending_checkpoint_writes > 0);
1742 
1743  log_sys->n_pending_checkpoint_writes--;
1744 
1745  if (log_sys->n_pending_checkpoint_writes == 0) {
1746  log_complete_checkpoint();
1747  }
1748 
1749  mutex_exit(&(log_sys->mutex));
1750 }
1751 
1752 /*******************************************************************/
1754 static
1755 void
1756 log_checkpoint_set_nth_group_info(
1757 /*==============================*/
1758  byte* buf,
1759  ulint n,
1760  ulint file_no,
1761  ulint offset)
1762 {
1763  ut_ad(n < LOG_MAX_N_GROUPS);
1764 
1765  mach_write_to_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
1766  + 8 * n + LOG_CHECKPOINT_ARCHIVED_FILE_NO, file_no);
1767  mach_write_to_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
1768  + 8 * n + LOG_CHECKPOINT_ARCHIVED_OFFSET, offset);
1769 }
1770 
1771 /*******************************************************************/
1773 UNIV_INTERN
1774 void
1776 /*==============================*/
1777  const byte* buf,
1778  ulint n,
1779  ulint* file_no,
1780  ulint* offset)
1781 {
1782  ut_ad(n < LOG_MAX_N_GROUPS);
1783 
1784  *file_no = mach_read_from_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
1785  + 8 * n + LOG_CHECKPOINT_ARCHIVED_FILE_NO);
1786  *offset = mach_read_from_4(buf + LOG_CHECKPOINT_GROUP_ARRAY
1787  + 8 * n + LOG_CHECKPOINT_ARCHIVED_OFFSET);
1788 }
1789 
1790 /******************************************************/
1792 static
1793 void
1794 log_group_checkpoint(
1795 /*=================*/
1796  log_group_t* group)
1797 {
1798  log_group_t* group2;
1799 #ifdef UNIV_LOG_ARCHIVE
1800  ib_uint64_t archived_lsn;
1801  ib_uint64_t next_archived_lsn;
1802 #endif /* UNIV_LOG_ARCHIVE */
1803  ulint write_offset;
1804  ulint fold;
1805  byte* buf;
1806  ulint i;
1807 
1808  ut_ad(mutex_own(&(log_sys->mutex)));
1809  ut_a(LOG_CHECKPOINT_SIZE <= OS_FILE_LOG_BLOCK_SIZE);
1810 
1811  buf = group->checkpoint_buf;
1812 
1813  mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no);
1814  mach_write_to_8(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn);
1815 
1816  mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET,
1817  log_group_calc_lsn_offset(
1818  log_sys->next_checkpoint_lsn, group));
1819 
1820  mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, log_sys->buf_size);
1821 
1822 #ifdef UNIV_LOG_ARCHIVE
1823  if (log_sys->archiving_state == LOG_ARCH_OFF) {
1824  archived_lsn = IB_ULONGLONG_MAX;
1825  } else {
1826  archived_lsn = log_sys->archived_lsn;
1827 
1828  if (archived_lsn != log_sys->next_archived_lsn) {
1829  next_archived_lsn = log_sys->next_archived_lsn;
1830  /* For debugging only */
1831  }
1832  }
1833 
1834  mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, archived_lsn);
1835 #else /* UNIV_LOG_ARCHIVE */
1836  mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN,
1837  (ib_uint64_t)log_group_calc_lsn_offset(
1838  log_sys->next_checkpoint_lsn, group));
1839 
1840 #endif /* UNIV_LOG_ARCHIVE */
1841 
1842  for (i = 0; i < LOG_MAX_N_GROUPS; i++) {
1843  log_checkpoint_set_nth_group_info(buf, i, 0, 0);
1844  }
1845 
1846  group2 = UT_LIST_GET_FIRST(log_sys->log_groups);
1847 
1848  while (group2) {
1849  log_checkpoint_set_nth_group_info(buf, group2->id,
1850 #ifdef UNIV_LOG_ARCHIVE
1851  group2->archived_file_no,
1852  group2->archived_offset
1853 #else /* UNIV_LOG_ARCHIVE */
1854  0, 0
1855 #endif /* UNIV_LOG_ARCHIVE */
1856  );
1857 
1858  group2 = UT_LIST_GET_NEXT(log_groups, group2);
1859  }
1860 
1861  fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
1862  mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold);
1863 
1864  fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
1865  LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
1866  mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_2, fold);
1867 
1868  /* Starting from InnoDB-3.23.50, we also write info on allocated
1869  size in the tablespace */
1870 
1871  mach_write_to_4(buf + LOG_CHECKPOINT_FSP_FREE_LIMIT,
1872  log_fsp_current_free_limit);
1873 
1874  mach_write_to_4(buf + LOG_CHECKPOINT_FSP_MAGIC_N,
1875  LOG_CHECKPOINT_FSP_MAGIC_N_VAL);
1876 
1877  /* We alternate the physical place of the checkpoint info in the first
1878  log file */
1879 
1880  if ((log_sys->next_checkpoint_no & 1) == 0) {
1881  write_offset = LOG_CHECKPOINT_1;
1882  } else {
1883  write_offset = LOG_CHECKPOINT_2;
1884  }
1885 
1886  if (log_do_write) {
1887  if (log_sys->n_pending_checkpoint_writes == 0) {
1888 
1889  rw_lock_x_lock_gen(&(log_sys->checkpoint_lock),
1890  LOG_CHECKPOINT);
1891  }
1892 
1893  log_sys->n_pending_checkpoint_writes++;
1894 
1895  log_sys->n_log_ios++;
1896 
1897  /* We send as the last parameter the group machine address
1898  added with 1, as we want to distinguish between a normal log
1899  file write and a checkpoint field write */
1900 
1901  fil_io(OS_FILE_WRITE | OS_FILE_LOG, FALSE, group->space_id, 0,
1902  write_offset / UNIV_PAGE_SIZE,
1903  write_offset % UNIV_PAGE_SIZE,
1905  buf, ((byte*)group + 1));
1906 
1907  ut_ad(((ulint)group & 0x1UL) == 0);
1908  }
1909 }
1910 #endif /* !UNIV_HOTBACKUP */
1911 
1912 #ifdef UNIV_HOTBACKUP
1913 /******************************************************/
1916 UNIV_INTERN
1917 void
1918 log_reset_first_header_and_checkpoint(
1919 /*==================================*/
1920  byte* hdr_buf,
1922  ib_uint64_t start)
1925 {
1926  ulint fold;
1927  byte* buf;
1928  ib_uint64_t lsn;
1929 
1930  mach_write_to_4(hdr_buf + LOG_GROUP_ID, 0);
1931  mach_write_to_8(hdr_buf + LOG_FILE_START_LSN, start);
1932 
1933  lsn = start + LOG_BLOCK_HDR_SIZE;
1934 
1935  /* Write the label of ibbackup --restore */
1936  strcpy((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
1937  "ibbackup ");
1938  ut_sprintf_timestamp((char*) hdr_buf
1939  + (LOG_FILE_WAS_CREATED_BY_HOT_BACKUP
1940  + (sizeof "ibbackup ") - 1));
1941  buf = hdr_buf + LOG_CHECKPOINT_1;
1942 
1943  mach_write_to_8(buf + LOG_CHECKPOINT_NO, 0);
1944  mach_write_to_8(buf + LOG_CHECKPOINT_LSN, lsn);
1945 
1946  mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET,
1947  LOG_FILE_HDR_SIZE + LOG_BLOCK_HDR_SIZE);
1948 
1949  mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, 2 * 1024 * 1024);
1950 
1951  mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, IB_ULONGLONG_MAX);
1952 
1953  fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1);
1954  mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold);
1955 
1956  fold = ut_fold_binary(buf + LOG_CHECKPOINT_LSN,
1957  LOG_CHECKPOINT_CHECKSUM_2 - LOG_CHECKPOINT_LSN);
1958  mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_2, fold);
1959 
1960  /* Starting from InnoDB-3.23.50, we should also write info on
1961  allocated size in the tablespace, but unfortunately we do not
1962  know it here */
1963 }
1964 #endif /* UNIV_HOTBACKUP */
1965 
1966 #ifndef UNIV_HOTBACKUP
1967 /******************************************************/
1969 UNIV_INTERN
1970 void
1972 /*===========================*/
1973  log_group_t* group,
1974  ulint field)
1975 {
1976  ut_ad(mutex_own(&(log_sys->mutex)));
1977 
1978  log_sys->n_log_ios++;
1979 
1980  fil_io(OS_FILE_READ | OS_FILE_LOG, TRUE, group->space_id, 0,
1981  field / UNIV_PAGE_SIZE, field % UNIV_PAGE_SIZE,
1982  OS_FILE_LOG_BLOCK_SIZE, log_sys->checkpoint_buf, NULL);
1983 }
1984 
1985 /******************************************************/
1987 UNIV_INTERN
1988 void
1990 /*==================================*/
1991 {
1992  log_group_t* group;
1993 
1994  ut_ad(mutex_own(&(log_sys->mutex)));
1995 
1996  group = UT_LIST_GET_FIRST(log_sys->log_groups);
1997 
1998  while (group) {
1999  log_group_checkpoint(group);
2000 
2001  group = UT_LIST_GET_NEXT(log_groups, group);
2002  }
2003 }
2004 
2005 /******************************************************/
2011 UNIV_INTERN
2012 ibool
2014 /*===========*/
2015  ibool sync,
2017  ibool write_always)
2023 {
2024  ib_uint64_t oldest_lsn;
2025 
2026  if (recv_recovery_is_on()) {
2028  }
2029 
2030  if (srv_unix_file_flush_method != SRV_UNIX_NOSYNC) {
2032  }
2033 
2034  mutex_enter(&(log_sys->mutex));
2035 
2036  ut_ad(!recv_no_log_write);
2037  oldest_lsn = log_buf_pool_get_oldest_modification();
2038 
2039  mutex_exit(&(log_sys->mutex));
2040 
2041  /* Because log also contains headers and dummy log records,
2042  if the buffer pool contains no dirty buffers, oldest_lsn
2043  gets the value log_sys->lsn from the previous function,
2044  and we must make sure that the log is flushed up to that
2045  lsn. If there are dirty buffers in the buffer pool, then our
2046  write-ahead-logging algorithm ensures that the log has been flushed
2047  up to oldest_lsn. */
2048 
2049  log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
2050 
2051  mutex_enter(&(log_sys->mutex));
2052 
2053  if (!write_always
2054  && log_sys->last_checkpoint_lsn >= oldest_lsn) {
2055 
2056  mutex_exit(&(log_sys->mutex));
2057 
2058  return(TRUE);
2059  }
2060 
2061  ut_ad(log_sys->flushed_to_disk_lsn >= oldest_lsn);
2062 
2063  if (log_sys->n_pending_checkpoint_writes > 0) {
2064  /* A checkpoint write is running */
2065 
2066  mutex_exit(&(log_sys->mutex));
2067 
2068  if (sync) {
2069  /* Wait for the checkpoint write to complete */
2070  rw_lock_s_lock(&(log_sys->checkpoint_lock));
2071  rw_lock_s_unlock(&(log_sys->checkpoint_lock));
2072  }
2073 
2074  return(FALSE);
2075  }
2076 
2077  log_sys->next_checkpoint_lsn = oldest_lsn;
2078 
2079 #ifdef UNIV_DEBUG
2080  if (log_debug_writes) {
2081  fprintf(stderr, "Making checkpoint no %lu at lsn %"PRIu64"\n",
2082  (ulong) log_sys->next_checkpoint_no,
2083  oldest_lsn);
2084  }
2085 #endif /* UNIV_DEBUG */
2086 
2088 
2089  mutex_exit(&(log_sys->mutex));
2090 
2091  if (sync) {
2092  /* Wait for the checkpoint write to complete */
2093  rw_lock_s_lock(&(log_sys->checkpoint_lock));
2094  rw_lock_s_unlock(&(log_sys->checkpoint_lock));
2095  }
2096 
2097  return(TRUE);
2098 }
2099 
2100 /****************************************************************/
2102 UNIV_INTERN
2103 void
2105 /*===================*/
2106  ib_uint64_t lsn,
2109  ibool write_always)
2116 {
2117  /* Preflush pages synchronously */
2118 
2119  while (!log_preflush_pool_modified_pages(lsn, TRUE)) {}
2120 
2121  while (!log_checkpoint(TRUE, write_always)) {}
2122 }
2123 
2124 /****************************************************************/
2129 static
2130 void
2131 log_checkpoint_margin(void)
2132 /*=======================*/
2133 {
2134  log_t* log = log_sys;
2135  ib_uint64_t age;
2136  ib_uint64_t checkpoint_age;
2137  ib_uint64_t advance;
2138  ib_uint64_t oldest_lsn;
2139  ibool sync;
2140  ibool checkpoint_sync;
2141  ibool do_checkpoint;
2142  ibool success;
2143 loop:
2144  sync = FALSE;
2145  checkpoint_sync = FALSE;
2146  do_checkpoint = FALSE;
2147 
2148  mutex_enter(&(log->mutex));
2149  ut_ad(!recv_no_log_write);
2150 
2151  if (log->check_flush_or_checkpoint == FALSE) {
2152  mutex_exit(&(log->mutex));
2153 
2154  return;
2155  }
2156 
2157  oldest_lsn = log_buf_pool_get_oldest_modification();
2158 
2159  age = log->lsn - oldest_lsn;
2160 
2161  if (age > log->max_modified_age_sync) {
2162 
2163  /* A flush is urgent: we have to do a synchronous preflush */
2164 
2165  sync = TRUE;
2166  advance = 2 * (age - log->max_modified_age_sync);
2167  } else if (age > log_max_modified_age_async()) {
2168 
2169  /* A flush is not urgent: we do an asynchronous preflush */
2170  advance = age - log_max_modified_age_async();
2171  } else {
2172  advance = 0;
2173  }
2174 
2175  checkpoint_age = log->lsn - log->last_checkpoint_lsn;
2176 
2177  if (checkpoint_age > log->max_checkpoint_age) {
2178  /* A checkpoint is urgent: we do it synchronously */
2179 
2180  checkpoint_sync = TRUE;
2181 
2182  do_checkpoint = TRUE;
2183 
2184  } else if (checkpoint_age > log_max_checkpoint_age_async()) {
2185  /* A checkpoint is not urgent: do it asynchronously */
2186 
2187  do_checkpoint = TRUE;
2188 
2189  log->check_flush_or_checkpoint = FALSE;
2190  } else {
2191  log->check_flush_or_checkpoint = FALSE;
2192  }
2193 
2194  mutex_exit(&(log->mutex));
2195 
2196  if (advance) {
2197  ib_uint64_t new_oldest = oldest_lsn + advance;
2198 
2199  success = log_preflush_pool_modified_pages(new_oldest, sync);
2200 
2201  /* If the flush succeeded, this thread has done its part
2202  and can proceed. If it did not succeed, there was another
2203  thread doing a flush at the same time. If sync was FALSE,
2204  the flush was not urgent, and we let this thread proceed.
2205  Otherwise, we let it start from the beginning again. */
2206 
2207  if (sync && !success) {
2208  mutex_enter(&(log->mutex));
2209 
2210  log->check_flush_or_checkpoint = TRUE;
2211 
2212  mutex_exit(&(log->mutex));
2213  goto loop;
2214  }
2215  }
2216 
2217  if (do_checkpoint) {
2218  log_checkpoint(checkpoint_sync, FALSE);
2219 
2220  if (checkpoint_sync) {
2221 
2222  goto loop;
2223  }
2224  }
2225 }
2226 
2227 /******************************************************/
2229 UNIV_INTERN
2230 void
2232 /*===================*/
2233  ulint type,
2234  byte* buf,
2235  log_group_t* group,
2236  ib_uint64_t start_lsn,
2237  ib_uint64_t end_lsn)
2238 {
2239  ulint len;
2240  ulint source_offset;
2241  ibool sync;
2242 
2243  ut_ad(mutex_own(&(log_sys->mutex)));
2244 
2245  sync = (type == LOG_RECOVER);
2246 loop:
2247  source_offset = log_group_calc_lsn_offset(start_lsn, group);
2248 
2249  len = (ulint) (end_lsn - start_lsn);
2250 
2251  ut_ad(len != 0);
2252 
2253  if ((source_offset % group->file_size) + len > group->file_size) {
2254 
2255  len = group->file_size - (source_offset % group->file_size);
2256  }
2257 
2258 #ifdef UNIV_LOG_ARCHIVE
2259  if (type == LOG_ARCHIVE) {
2260 
2261  log_sys->n_pending_archive_ios++;
2262  }
2263 #endif /* UNIV_LOG_ARCHIVE */
2264 
2265  log_sys->n_log_ios++;
2266 
2267  fil_io(OS_FILE_READ | OS_FILE_LOG, sync, group->space_id, 0,
2268  source_offset / UNIV_PAGE_SIZE, source_offset % UNIV_PAGE_SIZE,
2269  len, buf, NULL);
2270 
2271  start_lsn += len;
2272  buf += len;
2273 
2274  if (start_lsn != end_lsn) {
2275 
2276  goto loop;
2277  }
2278 }
2279 
2280 #ifdef UNIV_LOG_ARCHIVE
2281 /******************************************************/
2283 UNIV_INTERN
2284 void
2286 /*=======================*/
2287  char* buf,
2288  ulint /*id __attribute__((unused))*/,
2291  ulint file_no)
2292 {
2293  sprintf(buf, "%sib_arch_log_%010lu", srv_arch_dir, (ulong) file_no);
2294 }
2295 
2296 /******************************************************/
2298 static
2299 void
2300 log_group_archive_file_header_write(
2301 /*================================*/
2302  log_group_t* group,
2303  ulint nth_file,
2305  ulint file_no,
2306  ib_uint64_t start_lsn)
2308 {
2309  byte* buf;
2310  ulint dest_offset;
2311 
2312  ut_ad(mutex_own(&(log_sys->mutex)));
2313 
2314  ut_a(nth_file < group->n_files);
2315 
2316  buf = *(group->archive_file_header_bufs + nth_file);
2317 
2318  mach_write_to_4(buf + LOG_GROUP_ID, group->id);
2319  mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn);
2320  mach_write_to_4(buf + LOG_FILE_NO, file_no);
2321 
2322  mach_write_to_4(buf + LOG_FILE_ARCH_COMPLETED, FALSE);
2323 
2324  dest_offset = nth_file * group->file_size;
2325 
2326  log_sys->n_log_ios++;
2327 
2328  fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->archive_space_id,
2329  dest_offset / UNIV_PAGE_SIZE,
2330  dest_offset % UNIV_PAGE_SIZE,
2332  buf, &log_archive_io);
2333 }
2334 
2335 /******************************************************/
2337 static
2338 void
2339 log_group_archive_completed_header_write(
2340 /*=====================================*/
2341  log_group_t* group,
2342  ulint nth_file,
2344  ib_uint64_t end_lsn)
2345 {
2346  byte* buf;
2347  ulint dest_offset;
2348 
2349  ut_ad(mutex_own(&(log_sys->mutex)));
2350  ut_a(nth_file < group->n_files);
2351 
2352  buf = *(group->archive_file_header_bufs + nth_file);
2353 
2354  mach_write_to_4(buf + LOG_FILE_ARCH_COMPLETED, TRUE);
2355  mach_write_to_8(buf + LOG_FILE_END_LSN, end_lsn);
2356 
2357  dest_offset = nth_file * group->file_size + LOG_FILE_ARCH_COMPLETED;
2358 
2359  log_sys->n_log_ios++;
2360 
2361  fil_io(OS_FILE_WRITE | OS_FILE_LOG, TRUE, group->archive_space_id,
2362  dest_offset / UNIV_PAGE_SIZE,
2363  dest_offset % UNIV_PAGE_SIZE,
2365  buf + LOG_FILE_ARCH_COMPLETED,
2366  &log_archive_io);
2367 }
2368 
2369 /******************************************************/
2371 static
2372 void
2373 log_group_archive(
2374 /*==============*/
2375  log_group_t* group)
2376 {
2377  os_file_t file_handle;
2378  ib_uint64_t start_lsn;
2379  ib_uint64_t end_lsn;
2380  char name[1024];
2381  byte* buf;
2382  ulint len;
2383  ibool ret;
2384  ulint next_offset;
2385  ulint n_files;
2386  ulint open_mode;
2387 
2388  ut_ad(mutex_own(&(log_sys->mutex)));
2389 
2390  start_lsn = log_sys->archived_lsn;
2391 
2392  ut_a(start_lsn % OS_FILE_LOG_BLOCK_SIZE == 0);
2393 
2394  end_lsn = log_sys->next_archived_lsn;
2395 
2396  ut_a(end_lsn % OS_FILE_LOG_BLOCK_SIZE == 0);
2397 
2398  buf = log_sys->archive_buf;
2399 
2400  n_files = 0;
2401 
2402  next_offset = group->archived_offset;
2403 loop:
2404  if ((next_offset % group->file_size == 0)
2405  || (fil_space_get_size(group->archive_space_id) == 0)) {
2406 
2407  /* Add the file to the archive file space; create or open the
2408  file */
2409 
2410  if (next_offset % group->file_size == 0) {
2411  open_mode = OS_FILE_CREATE;
2412  } else {
2413  open_mode = OS_FILE_OPEN;
2414  }
2415 
2416  log_archived_file_name_gen(name, group->id,
2417  group->archived_file_no + n_files);
2418 
2419  file_handle = os_file_create(innodb_file_log_key,
2420  name, open_mode,
2421  OS_FILE_AIO,
2422  OS_DATA_FILE, &ret);
2423 
2424  if (!ret && (open_mode == OS_FILE_CREATE)) {
2425  file_handle = os_file_create(
2426  innodb_file_log_key, name, OS_FILE_OPEN,
2427  OS_FILE_AIO, OS_DATA_FILE, &ret);
2428  }
2429 
2430  if (!ret) {
2431  fprintf(stderr,
2432  "InnoDB: Cannot create or open"
2433  " archive log file %s.\n"
2434  "InnoDB: Cannot continue operation.\n"
2435  "InnoDB: Check that the log archive"
2436  " directory exists,\n"
2437  "InnoDB: you have access rights to it, and\n"
2438  "InnoDB: there is space available.\n", name);
2439  exit(1);
2440  }
2441 
2442 #ifdef UNIV_DEBUG
2443  if (log_debug_writes) {
2444  fprintf(stderr, "Created archive file %s\n", name);
2445  }
2446 #endif /* UNIV_DEBUG */
2447 
2448  ret = os_file_close(file_handle);
2449 
2450  ut_a(ret);
2451 
2452  /* Add the archive file as a node to the space */
2453 
2454  fil_node_create(name, group->file_size / UNIV_PAGE_SIZE,
2455  group->archive_space_id, FALSE);
2456 
2457  if (next_offset % group->file_size == 0) {
2458  log_group_archive_file_header_write(
2459  group, n_files,
2460  group->archived_file_no + n_files,
2461  start_lsn);
2462 
2463  next_offset += LOG_FILE_HDR_SIZE;
2464  }
2465  }
2466 
2467  len = end_lsn - start_lsn;
2468 
2469  if (group->file_size < (next_offset % group->file_size) + len) {
2470 
2471  len = group->file_size - (next_offset % group->file_size);
2472  }
2473 
2474 #ifdef UNIV_DEBUG
2475  if (log_debug_writes) {
2476  fprintf(stderr,
2477  "Archiving starting at lsn %"PRIu64", len %lu"
2478  " to group %lu\n",
2479  start_lsn,
2480  (ulong) len, (ulong) group->id);
2481  }
2482 #endif /* UNIV_DEBUG */
2483 
2484  log_sys->n_pending_archive_ios++;
2485 
2486  log_sys->n_log_ios++;
2487 
2488  fil_io(OS_FILE_WRITE | OS_FILE_LOG, FALSE, group->archive_space_id,
2489  next_offset / UNIV_PAGE_SIZE, next_offset % UNIV_PAGE_SIZE,
2491  &log_archive_io);
2492 
2493  start_lsn += len;
2494  next_offset += len;
2495  buf += len;
2496 
2497  if (next_offset % group->file_size == 0) {
2498  n_files++;
2499  }
2500 
2501  if (end_lsn != start_lsn) {
2502 
2503  goto loop;
2504  }
2505 
2506  group->next_archived_file_no = group->archived_file_no + n_files;
2507  group->next_archived_offset = next_offset % group->file_size;
2508 
2509  ut_a(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
2510 }
2511 
2512 /*****************************************************/
2515 static
2516 void
2517 log_archive_groups(void)
2518 /*====================*/
2519 {
2520  log_group_t* group;
2521 
2522  ut_ad(mutex_own(&(log_sys->mutex)));
2523 
2524  group = UT_LIST_GET_FIRST(log_sys->log_groups);
2525 
2526  log_group_archive(group);
2527 }
2528 
2529 /*****************************************************/
2532 static
2533 void
2534 log_archive_write_complete_groups(void)
2535 /*===================================*/
2536 {
2537  log_group_t* group;
2538  ulint end_offset;
2539  ulint trunc_files;
2540  ulint n_files;
2541  ib_uint64_t start_lsn;
2542  ib_uint64_t end_lsn;
2543  ulint i;
2544 
2545  ut_ad(mutex_own(&(log_sys->mutex)));
2546 
2547  group = UT_LIST_GET_FIRST(log_sys->log_groups);
2548 
2549  group->archived_file_no = group->next_archived_file_no;
2550  group->archived_offset = group->next_archived_offset;
2551 
2552  /* Truncate from the archive file space all but the last
2553  file, or if it has been written full, all files */
2554 
2555  n_files = (UNIV_PAGE_SIZE
2556  * fil_space_get_size(group->archive_space_id))
2557  / group->file_size;
2558  ut_ad(n_files > 0);
2559 
2560  end_offset = group->archived_offset;
2561 
2562  if (end_offset % group->file_size == 0) {
2563 
2564  trunc_files = n_files;
2565  } else {
2566  trunc_files = n_files - 1;
2567  }
2568 
2569 #ifdef UNIV_DEBUG
2570  if (log_debug_writes && trunc_files) {
2571  fprintf(stderr,
2572  "Complete file(s) archived to group %lu\n",
2573  (ulong) group->id);
2574  }
2575 #endif /* UNIV_DEBUG */
2576 
2577  /* Calculate the archive file space start lsn */
2578  start_lsn = log_sys->next_archived_lsn
2579  - (end_offset - LOG_FILE_HDR_SIZE + trunc_files
2580  * (group->file_size - LOG_FILE_HDR_SIZE));
2581  end_lsn = start_lsn;
2582 
2583  for (i = 0; i < trunc_files; i++) {
2584 
2585  end_lsn += group->file_size - LOG_FILE_HDR_SIZE;
2586 
2587  /* Write a notice to the headers of archived log
2588  files that the file write has been completed */
2589 
2590  log_group_archive_completed_header_write(group, i, end_lsn);
2591  }
2592 
2593  fil_space_truncate_start(group->archive_space_id,
2594  trunc_files * group->file_size);
2595 
2596 #ifdef UNIV_DEBUG
2597  if (log_debug_writes) {
2598  fputs("Archiving writes completed\n", stderr);
2599  }
2600 #endif /* UNIV_DEBUG */
2601 }
2602 
2603 /******************************************************/
2605 static
2606 void
2607 log_archive_check_completion_low(void)
2608 /*==================================*/
2609 {
2610  ut_ad(mutex_own(&(log_sys->mutex)));
2611 
2612  if (log_sys->n_pending_archive_ios == 0
2613  && log_sys->archiving_phase == LOG_ARCHIVE_READ) {
2614 
2615 #ifdef UNIV_DEBUG
2616  if (log_debug_writes) {
2617  fputs("Archiving read completed\n", stderr);
2618  }
2619 #endif /* UNIV_DEBUG */
2620 
2621  /* Archive buffer has now been read in: start archive writes */
2622 
2623  log_sys->archiving_phase = LOG_ARCHIVE_WRITE;
2624 
2625  log_archive_groups();
2626  }
2627 
2628  if (log_sys->n_pending_archive_ios == 0
2629  && log_sys->archiving_phase == LOG_ARCHIVE_WRITE) {
2630 
2631  log_archive_write_complete_groups();
2632 
2633  log_sys->archived_lsn = log_sys->next_archived_lsn;
2634 
2635  rw_lock_x_unlock_gen(&(log_sys->archive_lock), LOG_ARCHIVE);
2636  }
2637 }
2638 
2639 /******************************************************/
2641 static
2642 void
2643 log_io_complete_archive(void)
2644 /*=========================*/
2645 {
2646  log_group_t* group;
2647 
2648  mutex_enter(&(log_sys->mutex));
2649 
2650  group = UT_LIST_GET_FIRST(log_sys->log_groups);
2651 
2652  mutex_exit(&(log_sys->mutex));
2653 
2654  fil_flush(group->archive_space_id);
2655 
2656  mutex_enter(&(log_sys->mutex));
2657 
2658  ut_ad(log_sys->n_pending_archive_ios > 0);
2659 
2660  log_sys->n_pending_archive_ios--;
2661 
2662  log_archive_check_completion_low();
2663 
2664  mutex_exit(&(log_sys->mutex));
2665 }
2666 
2667 /********************************************************************/
2670 UNIV_INTERN
2671 ibool
2673 /*===========*/
2674  ibool sync,
2675  ulint* n_bytes)
2677 {
2678  ibool calc_new_limit;
2679  ib_uint64_t start_lsn;
2680  ib_uint64_t limit_lsn;
2681 
2682  calc_new_limit = TRUE;
2683 loop:
2684  mutex_enter(&(log_sys->mutex));
2685 
2686  switch (log_sys->archiving_state) {
2687  case LOG_ARCH_OFF:
2688 arch_none:
2689  mutex_exit(&(log_sys->mutex));
2690 
2691  *n_bytes = 0;
2692 
2693  return(TRUE);
2694  case LOG_ARCH_STOPPED:
2695  case LOG_ARCH_STOPPING2:
2696  mutex_exit(&(log_sys->mutex));
2697 
2698  os_event_wait(log_sys->archiving_on);
2699 
2700  goto loop;
2701  }
2702 
2703  start_lsn = log_sys->archived_lsn;
2704 
2705  if (calc_new_limit) {
2706  ut_a(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE == 0);
2707  limit_lsn = start_lsn + log_sys->archive_buf_size;
2708 
2709  *n_bytes = log_sys->archive_buf_size;
2710 
2711  if (limit_lsn >= log_sys->lsn) {
2712 
2713  limit_lsn = ut_uint64_align_down(
2714  log_sys->lsn, OS_FILE_LOG_BLOCK_SIZE);
2715  }
2716  }
2717 
2718  if (log_sys->archived_lsn >= limit_lsn) {
2719 
2720  goto arch_none;
2721  }
2722 
2723  if (log_sys->written_to_all_lsn < limit_lsn) {
2724 
2725  mutex_exit(&(log_sys->mutex));
2726 
2727  log_write_up_to(limit_lsn, LOG_WAIT_ALL_GROUPS, TRUE);
2728 
2729  calc_new_limit = FALSE;
2730 
2731  goto loop;
2732  }
2733 
2734  if (log_sys->n_pending_archive_ios > 0) {
2735  /* An archiving operation is running */
2736 
2737  mutex_exit(&(log_sys->mutex));
2738 
2739  if (sync) {
2740  rw_lock_s_lock(&(log_sys->archive_lock));
2741  rw_lock_s_unlock(&(log_sys->archive_lock));
2742  }
2743 
2744  *n_bytes = log_sys->archive_buf_size;
2745 
2746  return(FALSE);
2747  }
2748 
2749  rw_lock_x_lock_gen(&(log_sys->archive_lock), LOG_ARCHIVE);
2750 
2751  log_sys->archiving_phase = LOG_ARCHIVE_READ;
2752 
2753  log_sys->next_archived_lsn = limit_lsn;
2754 
2755 #ifdef UNIV_DEBUG
2756  if (log_debug_writes) {
2757  fprintf(stderr,
2758  "Archiving from lsn %"PRIu64" to lsn %"PRIu64"\n",
2759  log_sys->archived_lsn, limit_lsn);
2760  }
2761 #endif /* UNIV_DEBUG */
2762 
2763  /* Read the log segment to the archive buffer */
2764 
2765  log_group_read_log_seg(LOG_ARCHIVE, log_sys->archive_buf,
2766  UT_LIST_GET_FIRST(log_sys->log_groups),
2767  start_lsn, limit_lsn);
2768 
2769  mutex_exit(&(log_sys->mutex));
2770 
2771  if (sync) {
2772  rw_lock_s_lock(&(log_sys->archive_lock));
2773  rw_lock_s_unlock(&(log_sys->archive_lock));
2774  }
2775 
2776  *n_bytes = log_sys->archive_buf_size;
2777 
2778  return(TRUE);
2779 }
2780 
2781 /****************************************************************/
2784 static
2785 void
2786 log_archive_all(void)
2787 /*=================*/
2788 {
2789  ib_uint64_t present_lsn;
2790  ulint dummy;
2791 
2792  mutex_enter(&(log_sys->mutex));
2793 
2794  if (log_sys->archiving_state == LOG_ARCH_OFF) {
2795  mutex_exit(&(log_sys->mutex));
2796 
2797  return;
2798  }
2799 
2800  present_lsn = log_sys->lsn;
2801 
2802  mutex_exit(&(log_sys->mutex));
2803 
2804  log_pad_current_log_block();
2805 
2806  for (;;) {
2807  mutex_enter(&(log_sys->mutex));
2808 
2809  if (present_lsn <= log_sys->archived_lsn) {
2810 
2811  mutex_exit(&(log_sys->mutex));
2812 
2813  return;
2814  }
2815 
2816  mutex_exit(&(log_sys->mutex));
2817 
2818  log_archive_do(TRUE, &dummy);
2819  }
2820 }
2821 
2822 /*****************************************************/
2825 static
2826 void
2827 log_archive_close_groups(
2828 /*=====================*/
2829  ibool increment_file_count)
2831 {
2832  log_group_t* group;
2833  ulint trunc_len;
2834 
2835  ut_ad(mutex_own(&(log_sys->mutex)));
2836 
2837  if (log_sys->archiving_state == LOG_ARCH_OFF) {
2838 
2839  return;
2840  }
2841 
2842  group = UT_LIST_GET_FIRST(log_sys->log_groups);
2843 
2844  trunc_len = UNIV_PAGE_SIZE
2845  * fil_space_get_size(group->archive_space_id);
2846  if (trunc_len > 0) {
2847  ut_a(trunc_len == group->file_size);
2848 
2849  /* Write a notice to the headers of archived log
2850  files that the file write has been completed */
2851 
2852  log_group_archive_completed_header_write(
2853  group, 0, log_sys->archived_lsn);
2854 
2855  fil_space_truncate_start(group->archive_space_id,
2856  trunc_len);
2857  if (increment_file_count) {
2858  group->archived_offset = 0;
2859  group->archived_file_no += 2;
2860  }
2861 
2862 #ifdef UNIV_DEBUG
2863  if (log_debug_writes) {
2864  fprintf(stderr,
2865  "Incrementing arch file no to %lu"
2866  " in log group %lu\n",
2867  (ulong) group->archived_file_no + 2,
2868  (ulong) group->id);
2869  }
2870 #endif /* UNIV_DEBUG */
2871  }
2872 }
2873 
2874 /****************************************************************/
2880 UNIV_INTERN
2881 ulint
2882 log_archive_stop(void)
2883 /*==================*/
2884 {
2885  ibool success;
2886 
2887  mutex_enter(&(log_sys->mutex));
2888 
2889  if (log_sys->archiving_state != LOG_ARCH_ON) {
2890 
2891  mutex_exit(&(log_sys->mutex));
2892 
2893  return(DB_ERROR);
2894  }
2895 
2896  log_sys->archiving_state = LOG_ARCH_STOPPING;
2897 
2898  mutex_exit(&(log_sys->mutex));
2899 
2900  log_archive_all();
2901 
2902  mutex_enter(&(log_sys->mutex));
2903 
2904  log_sys->archiving_state = LOG_ARCH_STOPPING2;
2905  os_event_reset(log_sys->archiving_on);
2906 
2907  mutex_exit(&(log_sys->mutex));
2908 
2909  /* Wait for a possible archiving operation to end */
2910 
2911  rw_lock_s_lock(&(log_sys->archive_lock));
2912  rw_lock_s_unlock(&(log_sys->archive_lock));
2913 
2914  mutex_enter(&(log_sys->mutex));
2915 
2916  /* Close all archived log files, incrementing the file count by 2,
2917  if appropriate */
2918 
2919  log_archive_close_groups(TRUE);
2920 
2921  mutex_exit(&(log_sys->mutex));
2922 
2923  /* Make a checkpoint, so that if recovery is needed, the file numbers
2924  of new archived log files will start from the right value */
2925 
2926  success = FALSE;
2927 
2928  while (!success) {
2929  success = log_checkpoint(TRUE, TRUE);
2930  }
2931 
2932  mutex_enter(&(log_sys->mutex));
2933 
2934  log_sys->archiving_state = LOG_ARCH_STOPPED;
2935 
2936  mutex_exit(&(log_sys->mutex));
2937 
2938  return(DB_SUCCESS);
2939 }
2940 
2941 /****************************************************************/
2944 UNIV_INTERN
2945 ulint
2946 log_archive_start(void)
2947 /*===================*/
2948 {
2949  mutex_enter(&(log_sys->mutex));
2950 
2951  if (log_sys->archiving_state != LOG_ARCH_STOPPED) {
2952 
2953  mutex_exit(&(log_sys->mutex));
2954 
2955  return(DB_ERROR);
2956  }
2957 
2958  log_sys->archiving_state = LOG_ARCH_ON;
2959 
2960  os_event_set(log_sys->archiving_on);
2961 
2962  mutex_exit(&(log_sys->mutex));
2963 
2964  return(DB_SUCCESS);
2965 }
2966 
2967 /****************************************************************/
2970 UNIV_INTERN
2971 ulint
2973 /*==========================*/
2974 {
2975 loop:
2976  mutex_enter(&(log_sys->mutex));
2977 
2978  if (log_sys->archiving_state == LOG_ARCH_STOPPED
2979  || log_sys->archiving_state == LOG_ARCH_OFF) {
2980 
2981  log_sys->archiving_state = LOG_ARCH_OFF;
2982 
2983  os_event_set(log_sys->archiving_on);
2984 
2985  mutex_exit(&(log_sys->mutex));
2986 
2987  return(DB_SUCCESS);
2988  }
2989 
2990  mutex_exit(&(log_sys->mutex));
2991 
2992  log_archive_stop();
2993 
2994  os_thread_sleep(500000);
2995 
2996  goto loop;
2997 }
2998 
2999 /****************************************************************/
3002 UNIV_INTERN
3003 ulint
3005 /*========================*/
3006 {
3007  mutex_enter(&(log_sys->mutex));
3008 
3009  if (log_sys->archiving_state == LOG_ARCH_OFF) {
3010 
3011  log_sys->archiving_state = LOG_ARCH_ON;
3012 
3013  log_sys->archived_lsn
3014  = ut_uint64_align_down(log_sys->lsn,
3016  mutex_exit(&(log_sys->mutex));
3017 
3018  return(DB_SUCCESS);
3019  }
3020 
3021  mutex_exit(&(log_sys->mutex));
3022 
3023  return(DB_ERROR);
3024 }
3025 
3026 /****************************************************************/
3030 static
3031 void
3032 log_archive_margin(void)
3033 /*====================*/
3034 {
3035  log_t* log = log_sys;
3036  ulint age;
3037  ibool sync;
3038  ulint dummy;
3039 loop:
3040  mutex_enter(&(log->mutex));
3041 
3042  if (log->archiving_state == LOG_ARCH_OFF) {
3043  mutex_exit(&(log->mutex));
3044 
3045  return;
3046  }
3047 
3048  age = log->lsn - log->archived_lsn;
3049 
3050  if (age > log->max_archived_lsn_age) {
3051 
3052  /* An archiving is urgent: we have to do synchronous i/o */
3053 
3054  sync = TRUE;
3055 
3056  } else if (age > log->max_archived_lsn_age_async) {
3057 
3058  /* An archiving is not urgent: we do asynchronous i/o */
3059 
3060  sync = FALSE;
3061  } else {
3062  /* No archiving required yet */
3063 
3064  mutex_exit(&(log->mutex));
3065 
3066  return;
3067  }
3068 
3069  mutex_exit(&(log->mutex));
3070 
3071  log_archive_do(sync, &dummy);
3072 
3073  if (sync == TRUE) {
3074  /* Check again that enough was written to the archive */
3075 
3076  goto loop;
3077  }
3078 }
3079 #endif /* UNIV_LOG_ARCHIVE */
3080 
3081 /********************************************************************/
3086 UNIV_INTERN
3087 void
3089 /*===================*/
3090 {
3091 loop:
3092  log_flush_margin();
3093 
3094  log_checkpoint_margin();
3095 
3096 #ifdef UNIV_LOG_ARCHIVE
3097  log_archive_margin();
3098 #endif /* UNIV_LOG_ARCHIVE */
3099 
3100  mutex_enter(&(log_sys->mutex));
3101  ut_ad(!recv_no_log_write);
3102 
3103  if (log_sys->check_flush_or_checkpoint) {
3104 
3105  mutex_exit(&(log_sys->mutex));
3106 
3107  goto loop;
3108  }
3109 
3110  mutex_exit(&(log_sys->mutex));
3111 }
3112 
3113 /****************************************************************/
3118 UNIV_INTERN
3119 void
3121 /*=======================================*/
3122 {
3123  ib_uint64_t lsn;
3124  ulint arch_log_no;
3125 
3126  if (srv_print_verbose_log) {
3127  ut_print_timestamp(stderr);
3128  fprintf(stderr, " InnoDB: Starting shutdown...\n");
3129  }
3130  /* Wait until the master thread and all other operations are idle: our
3131  algorithm only works if the server is idle at shutdown */
3132 
3134 loop:
3135  os_thread_sleep(100000);
3136 
3137  mutex_enter(&kernel_mutex);
3138 
3139  /* We need the monitor threads to stop before we proceed with a
3140  normal shutdown. In case of very fast shutdown, however, we can
3141  proceed without waiting for monitor threads. */
3142 
3143  if (srv_fast_shutdown < 2
3144  && (srv_error_monitor_active
3145  || srv_lock_timeout_active
3146  || srv_monitor_active)) {
3147 
3148  mutex_exit(&kernel_mutex);
3149 
3150  os_event_set(srv_error_event);
3151  os_event_set(srv_monitor_event);
3152  os_event_set(srv_timeout_event);
3153 
3154  goto loop;
3155  }
3156 
3157  /* Check that there are no longer transactions. We need this wait even
3158  for the 'very fast' shutdown, because the InnoDB layer may have
3159  committed or prepared transactions and we don't want to lose them. */
3160 
3161  if (! srv_apply_log_only) {
3162  if (trx_n_mysql_transactions > 0
3163  || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
3164 
3165  mutex_exit(&kernel_mutex);
3166 
3167  goto loop;
3168  }
3169  }
3170 
3171  if (srv_fast_shutdown == 2) {
3172  /* In this fastest shutdown we do not flush the buffer pool:
3173  it is essentially a 'crash' of the InnoDB server. Make sure
3174  that the log is all flushed to disk, so that we can recover
3175  all committed transactions in a crash recovery. We must not
3176  write the lsn stamps to the data files, since at a startup
3177  InnoDB deduces from the stamps if the previous shutdown was
3178  clean. */
3179 
3181 
3182  mutex_exit(&kernel_mutex);
3183 
3184  return; /* We SKIP ALL THE REST !! */
3185  }
3186 
3187  mutex_exit(&kernel_mutex);
3188 
3189  /* Check that the background threads are suspended */
3190 
3192  goto loop;
3193  }
3194 
3195  mutex_enter(&(log_sys->mutex));
3196 
3197  if (log_sys->n_pending_checkpoint_writes
3198 #ifdef UNIV_LOG_ARCHIVE
3199  || log_sys->n_pending_archive_ios
3200 #endif /* UNIV_LOG_ARCHIVE */
3201  || log_sys->n_pending_writes) {
3202 
3203  mutex_exit(&(log_sys->mutex));
3204 
3205  goto loop;
3206  }
3207 
3208  mutex_exit(&(log_sys->mutex));
3209 
3211 
3212  goto loop;
3213  }
3214 
3215 #ifdef UNIV_LOG_ARCHIVE
3216  log_archive_all();
3217 #endif /* UNIV_LOG_ARCHIVE */
3218 
3219  log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
3220 
3221  mutex_enter(&(log_sys->mutex));
3222 
3223  lsn = log_sys->lsn;
3224 
3225  if (lsn != log_sys->last_checkpoint_lsn
3226 #ifdef UNIV_LOG_ARCHIVE
3227  || (srv_log_archive_on
3228  && lsn != log_sys->archived_lsn + LOG_BLOCK_HDR_SIZE)
3229 #endif /* UNIV_LOG_ARCHIVE */
3230  ) {
3231 
3232  mutex_exit(&(log_sys->mutex));
3233 
3234  goto loop;
3235  }
3236 
3237  arch_log_no = 0;
3238 
3239 #ifdef UNIV_LOG_ARCHIVE
3240  UT_LIST_GET_FIRST(log_sys->log_groups)->archived_file_no;
3241 
3242  if (0 == UT_LIST_GET_FIRST(log_sys->log_groups)->archived_offset) {
3243 
3244  arch_log_no--;
3245  }
3246 
3247  log_archive_close_groups(TRUE);
3248 #endif /* UNIV_LOG_ARCHIVE */
3249 
3250  mutex_exit(&(log_sys->mutex));
3251 
3252  /* Check that the background threads stay suspended */
3254  fprintf(stderr,
3255  "InnoDB: Warning: some background thread woke up"
3256  " during shutdown\n");
3257 
3258  goto loop;
3259  }
3260 
3263 
3264  /* The call fil_write_flushed_lsn_to_data_files() will pass the buffer
3265  pool: therefore it is essential that the buffer pool has been
3266  completely flushed to disk! (We do not call fil_write... if the
3267  'very fast' shutdown is enabled.) */
3268 
3269  if (!buf_all_freed()) {
3270 
3271  goto loop;
3272  }
3273 
3275 
3276  /* Make some checks that the server really is quiet */
3278 
3279  ut_a(buf_all_freed());
3280  ut_a(lsn == log_sys->lsn);
3281 
3282  if (lsn < srv_start_lsn) {
3283  drizzled::errmsg_printf(drizzled::error::ERROR,
3284  "InnoDB: Error: log sequence number at shutdown %"PRIu64" is lower than at startup %"PRIu64"!",
3285  lsn, srv_start_lsn);
3286  }
3287 
3288  srv_shutdown_lsn = lsn;
3289 
3290  fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
3291 
3293 
3295 
3296  /* Make some checks that the server really is quiet */
3298 
3299  ut_a(buf_all_freed());
3300  ut_a(lsn == log_sys->lsn);
3301 }
3302 
3303 #ifdef UNIV_LOG_DEBUG
3304 /******************************************************/
3307 UNIV_INTERN
3308 ibool
3309 log_check_log_recs(
3310 /*===============*/
3311  const byte* buf,
3314  ulint len,
3315  ib_uint64_t buf_start_lsn)
3316 {
3317  ib_uint64_t contiguous_lsn;
3318  ib_uint64_t scanned_lsn;
3319  const byte* start;
3320  const byte* end;
3321  byte* buf1;
3322  byte* scan_buf;
3323 
3324  ut_ad(mutex_own(&(log_sys->mutex)));
3325 
3326  if (len == 0) {
3327 
3328  return(TRUE);
3329  }
3330 
3331  start = ut_align_down(buf, OS_FILE_LOG_BLOCK_SIZE);
3332  end = ut_align(buf + len, OS_FILE_LOG_BLOCK_SIZE);
3333 
3334  buf1 = mem_alloc((end - start) + OS_FILE_LOG_BLOCK_SIZE);
3335  scan_buf = ut_align(buf1, OS_FILE_LOG_BLOCK_SIZE);
3336 
3337  ut_memcpy(scan_buf, start, end - start);
3338 
3341  * UNIV_PAGE_SIZE, FALSE, scan_buf, end - start,
3342  ut_uint64_align_down(buf_start_lsn,
3344  &contiguous_lsn, &scanned_lsn);
3345 
3346  ut_a(scanned_lsn == buf_start_lsn + len);
3347  ut_a(recv_sys->recovered_lsn == scanned_lsn);
3348 
3349  mem_free(buf1);
3350 
3351  return(TRUE);
3352 }
3353 #endif /* UNIV_LOG_DEBUG */
3354 
3355 /******************************************************/
3358 UNIV_INTERN
3359 ibool
3361 /*=========*/
3362  ib_uint64_t* lsn)
3363 {
3364  if (0 == mutex_enter_nowait(&(log_sys->mutex))) {
3365  *lsn = log_sys->lsn;
3366 
3367  mutex_exit(&(log_sys->mutex));
3368 
3369  return(TRUE);
3370  }
3371 
3372  return(FALSE);
3373 }
3374 
3375 /******************************************************/
3377 UNIV_INTERN
3378 void
3380 /*======*/
3381  FILE* file)
3382 {
3383  double time_elapsed;
3384  time_t current_time;
3385 
3386  mutex_enter(&(log_sys->mutex));
3387 
3388  fprintf(file,
3389  "Log sequence number %"PRIu64"\n"
3390  "Log flushed up to %"PRIu64"\n"
3391  "Last checkpoint at %"PRIu64"\n",
3392  log_sys->lsn,
3393  log_sys->flushed_to_disk_lsn,
3394  log_sys->last_checkpoint_lsn);
3395 
3396  fprintf(file,
3397  "Max checkpoint age %lu\n"
3398  "Checkpoint age target %lu\n"
3399  "Modified age %"PRIu64"\n"
3400  "Checkpoint age %"PRIu64"\n",
3401  log_sys->max_checkpoint_age,
3402  log_max_checkpoint_age_async(),
3403  log_sys->lsn - log_buf_pool_get_oldest_modification(),
3404  log_sys->lsn - log_sys->last_checkpoint_lsn);
3405 
3406  current_time = time(NULL);
3407 
3408  time_elapsed = 0.001 + difftime(current_time,
3409  log_sys->last_printout_time);
3410  fprintf(file,
3411  "%lu pending log writes, %lu pending chkp writes\n"
3412  "%lu log i/o's done, %.2f log i/o's/second\n",
3413  (ulong) log_sys->n_pending_writes,
3414  (ulong) log_sys->n_pending_checkpoint_writes,
3415  (ulong) log_sys->n_log_ios,
3416  ((log_sys->n_log_ios - log_sys->n_log_ios_old)
3417  / time_elapsed));
3418 
3419  log_sys->n_log_ios_old = log_sys->n_log_ios;
3420  log_sys->last_printout_time = current_time;
3421 
3422  mutex_exit(&(log_sys->mutex));
3423 }
3424 
3425 /**********************************************************************/
3427 UNIV_INTERN
3428 void
3430 /*===================*/
3431 {
3432  log_sys->n_log_ios_old = log_sys->n_log_ios;
3433  log_sys->last_printout_time = time(NULL);
3434 }
3435 
3436 /**********************************************************************
3437 Closes a log group. */
3438 static
3439 void
3440 log_group_close(
3441 /*===========*/
3442  log_group_t* group) /* in,own: log group to close */
3443 {
3444  ulint i;
3445 
3446  for (i = 0; i < group->n_files; i++) {
3447  mem_free(group->file_header_bufs_ptr[i]);
3448 #ifdef UNIV_LOG_ARCHIVE
3449  mem_free(group->archive_file_header_bufs_ptr[i]);
3450 #endif /* UNIV_LOG_ARCHIVE */
3451  }
3452 
3454  mem_free(group->file_header_bufs);
3455 
3456 #ifdef UNIV_LOG_ARCHIVE
3457  mem_free(group->archive_file_header_bufs_ptr);
3458  mem_free(group->archive_file_header_bufs);
3459 #endif /* UNIV_LOG_ARCHIVE */
3460 
3461  mem_free(group->checkpoint_buf_ptr);
3462 
3463  mem_free(group);
3464 }
3465 
3466 /**********************************************************
3467 Shutdown the log system but do not release all the memory. */
3468 UNIV_INTERN
3469 void
3470 log_shutdown(void)
3471 /*==============*/
3472 {
3473  log_group_t* group;
3474 
3475  group = UT_LIST_GET_FIRST(log_sys->log_groups);
3476 
3477  while (UT_LIST_GET_LEN(log_sys->log_groups) > 0) {
3478  log_group_t* prev_group = group;
3479 
3480  group = UT_LIST_GET_NEXT(log_groups, group);
3481  UT_LIST_REMOVE(log_groups, log_sys->log_groups, prev_group);
3482 
3483  log_group_close(prev_group);
3484  }
3485 
3486  mem_free(log_sys->buf_ptr);
3487  log_sys->buf_ptr = NULL;
3488  log_sys->buf = NULL;
3489  mem_free(log_sys->checkpoint_buf_ptr);
3490  log_sys->checkpoint_buf_ptr = NULL;
3491  log_sys->checkpoint_buf = NULL;
3492 
3493  os_event_free(log_sys->no_flush_event);
3494  os_event_free(log_sys->one_flushed_event);
3495 
3496  rw_lock_free(&log_sys->checkpoint_lock);
3497 
3498  mutex_free(&log_sys->mutex);
3499 
3500 #ifdef UNIV_LOG_ARCHIVE
3501  rw_lock_free(&log_sys->archive_lock);
3502  os_event_create(log_sys->archiving_on);
3503 #endif /* UNIV_LOG_ARCHIVE */
3504 
3505 #ifdef UNIV_LOG_DEBUG
3506  recv_sys_debug_free();
3507 #endif
3508 
3509  recv_sys_close();
3510 }
3511 
3512 /**********************************************************
3513 Free the log system data structures. */
3514 UNIV_INTERN
3515 void
3516 log_mem_free(void)
3517 /*==============*/
3518 {
3519  if (log_sys != NULL) {
3521  mem_free(log_sys);
3522 
3523  log_sys = NULL;
3524  }
3525 }
3526 #endif /* !UNIV_HOTBACKUP */
#define UT_LIST_GET_LEN(BASE)
Definition: ut0lst.h:217
trx_sys_t * trx_sys
Definition: trx0sys.cc:61
UNIV_INTERN void log_io_complete(log_group_t *group)
Definition: log0log.cc:1119
int os_file_t
Definition: os0file.h:87
recv_sys_t * recv_sys
Definition: log0recv.cc:73
UNIV_INTERN ulint log_calc_where_lsn_is(ib_int64_t *log_file_offset, ib_uint64_t first_header_lsn, ib_uint64_t lsn, ulint n_log_files, ib_int64_t log_file_size)
Definition: log0log.cc:636
#define rw_lock_create(K, L, level)
Definition: sync0rw.h:147
UNIV_INLINE void log_block_set_checksum(byte *log_block, ulint checksum)
ib_uint64_t written_to_some_lsn
Definition: log0log.h:813
#define UT_LIST_GET_NEXT(NAME, N)
Definition: ut0lst.h:201
ulint max_checkpoint_age
Definition: log0log.h:908
#define MLOG_DUMMY_RECORD
Definition: mtr0mtr.h:164
UNIV_INLINE void * ut_memmove(void *dest, const void *sour, ulint n)
UNIV_INTERN ulint fil_io(ulint type, ibool sync, ulint space_id, ulint zip_size, ulint block_offset, ulint byte_offset, ulint len, void *buf, void *message)
Definition: fil0fil.cc:4287
UNIV_INTERN void recv_sys_mem_free(void)
Definition: log0recv.cc:232
UNIV_INTERN void log_make_checkpoint_at(ib_uint64_t lsn, ibool write_always)
Definition: log0log.cc:2104
UNIV_INLINE void mach_write_to_4(byte *b, ulint n)
UNIV_INTERN void log_buffer_sync_in_background(ibool flush)
Definition: log0log.cc:1624
UNIV_INTERN void logs_empty_and_mark_files_at_shutdown(void)
Definition: log0log.cc:3120
UNIV_INTERN void log_group_read_checkpoint_info(log_group_t *group, ulint field)
Definition: log0log.cc:1971
ib_uint64_t flushed_to_disk_lsn
Definition: log0log.h:844
#define mem_free(PTR)
Definition: mem0mem.h:249
UNIV_INTERN ibool buf_pool_check_no_pending_io(void)
Definition: buf0buf.cc:5197
UNIV_INTERN void log_init(void)
Definition: log0log.cc:803
UNIV_INTERN void log_group_read_log_seg(ulint type, byte *buf, log_group_t *group, ib_uint64_t start_lsn, ib_uint64_t end_lsn)
Definition: log0log.cc:2231
#define LOG_MAX_N_GROUPS
Definition: log0log.h:66
UNIV_INLINE void * ut_memcpy(void *dest, const void *sour, ulint n)
ulint buf_next_to_write
Definition: log0log.h:806
UNIV_INTERN os_event_t os_event_create(const char *name)
Definition: os0sync.cc:365
ulint n_log_ios
Definition: log0log.h:872
ib_uint64_t old_lsn
Definition: log0log.h:788
UNIV_INLINE void mach_write_to_8(byte *b, ib_uint64_t n)
UNIV_INTERN void log_print(FILE *file)
Definition: log0log.cc:3379
UNIV_INTERN void fil_flush(ulint space_id)
Definition: fil0fil.cc:4634
UNIV_INLINE ulint log_block_convert_lsn_to_no(ib_uint64_t lsn)
ulint recv_n_pool_free_frames
Definition: log0recv.cc:149
UNIV_INTERN void fil_node_create(const char *name, ulint size, ulint id, ibool is_raw)
Definition: fil0fil.cc:596
ulint adm_checkpoint_interval
Definition: log0log.h:898
UNIV_INTERN void log_group_write_buf(log_group_t *group, byte *buf, ulint len, ib_uint64_t start_lsn, ulint new_data_offset)
Definition: log0log.cc:1257
UNIV_INTERN ulint log_archive_stop(void)
UNIV_INTERN ulint log_archive_archivelog(void)
ulint old_buf_free
Definition: log0log.h:785
#define OS_FILE_READ
Definition: os0file.h:144
UNIV_INTERN void log_write_up_to(ib_uint64_t lsn, ulint wait, ibool flush_to_disk)
Definition: log0log.cc:1378
ib_uint64_t next_checkpoint_no
Definition: log0log.h:912
ib_uint64_t recovered_lsn
Definition: log0recv.h:422
ulint max_checkpoint_age_async
Definition: log0log.h:903
UNIV_INTERN ulint log_archive_noarchivelog(void)
ulint n_pending_writes
Definition: log0log.h:847
UNIV_INTERN void recv_sys_close(void)
Definition: log0recv.cc:201
UNIV_INTERN void log_check_margins(void)
Definition: log0log.cc:3088
#define FIL_TABLESPACE
Definition: fil0fil.h:190
UNIV_INLINE void log_block_set_first_rec_group(byte *log_block, ulint offset)
ulint max_modified_age_async
Definition: log0log.h:886
byte * checkpoint_buf_ptr
Definition: log0log.h:752
ib_uint64_t limit_lsn
Definition: log0recv.h:425
UNIV_INLINE ulint ut_min(ulint n1, ulint n2)
UNIV_INLINE void log_block_set_data_len(byte *log_block, ulint len)
#define FIL_LOG
Definition: fil0fil.h:191
#define log_do_write
Definition: log0log.h:57
ib_uint64_t write_lsn
Definition: log0log.h:835
ib_uint64_t lsn
Definition: log0log.h:764
ulint lsn_offset
Definition: log0log.h:720
#define UT_LIST_REMOVE(NAME, BASE, N)
Definition: ut0lst.h:178
#define OS_FILE_LOG_BLOCK_SIZE
Definition: os0file.h:104
UNIV_INLINE ulint log_block_get_data_len(const byte *log_block)
ulint buf_size
Definition: log0log.h:781
ulint space_id
Definition: log0log.h:714
UNIV_INTERN ibool log_peek_lsn(ib_uint64_t *lsn)
Definition: log0log.cc:3360
UNIV_INTERN void log_buffer_flush_to_disk(void)
Definition: log0log.cc:1603
UNIV_INTERN ib_uint64_t buf_pool_get_oldest_modification(void)
Definition: buf0buf.cc:315
UNIV_INTERN ibool log_archive_do(ibool sync, ulint *n_bytes)
ibool check_flush_or_checkpoint
Definition: log0log.h:791
byte ** file_header_bufs
Definition: log0log.h:724
UNIV_INTERN void recv_sys_create(void)
Definition: log0recv.cc:180
UNIV_INTERN void log_group_init(ulint id, ulint n_files, ulint file_size, ulint space_id, ulint archive_space_id)
Definition: log0log.cc:927
UNIV_INTERN void log_fsp_current_free_limit_set_and_checkpoint(ulint limit)
Definition: log0log.cc:175
UNIV_INLINE void log_block_init(byte *log_block, ib_uint64_t lsn)
UNIV_INLINE void * ut_align(const void *ptr, ulint align_no)
UNIV_INTERN void os_event_set(os_event_t event)
Definition: os0sync.cc:434
UNIV_INLINE ulint log_block_get_first_rec_group(const byte *log_block)
UNIV_INTERN void os_thread_sleep(ulint tm)
Definition: os0thread.cc:265
UNIV_INTERN void log_refresh_stats(void)
Definition: log0log.cc:3429
UNIV_INTERN void recv_apply_hashed_log_recs(ibool allow_ibuf)
Definition: log0recv.cc:1738
ib_uint64_t next_checkpoint_lsn
Definition: log0log.h:916
#define ut_calc_align_down(n, m)
Definition: ut0ut.h:180
UNIV_INTERN ib_int64_t os_event_reset(os_event_t event)
Definition: os0sync.cc:472
ib_uint64_t written_to_all_lsn
Definition: log0log.h:819
#define ut_a(EXPR)
Definition: ut0dbg.h:105
UNIV_INLINE ulint buf_pool_get_n_pages(void)
UNIV_INTERN void fil_close_all_files(void)
Definition: fil0fil.cc:1661
ib_uint64_t srv_start_lsn
Definition: srv0start.cc:99
UNIV_INTERN ulint log_archive_start(void)
UNIV_INLINE void * ut_align_down(const void *ptr, ulint align_no) __attribute__((const ))
UNIV_INTERN ib_uint64_t log_reserve_and_open(ulint len)
Definition: log0log.cc:225
UNIV_INTERN ulint fil_space_get_size(ulint id)
Definition: fil0fil.cc:1435
ib_uint64_t last_checkpoint_lsn
Definition: log0log.h:914
UNIV_INTERN void recv_sys_init(ulint available_memory)
Definition: log0recv.cc:303
UNIV_INLINE ib_uint64_t ut_uint64_align_down(ib_uint64_t n, ulint align_no)
UNIV_INTERN ulint buf_flush_list(ulint min_n, ib_uint64_t lsn_limit)
Definition: buf0flu.cc:1925
#define UT_LIST_ADD_LAST(NAME, BASE, N)
Definition: ut0lst.h:119
byte * checkpoint_buf
Definition: log0log.h:753
#define UT_LIST_GET_FIRST(BASE)
Definition: ut0lst.h:224
ulint n_pending_writes
Definition: log0log.h:721
mutex_t mutex
Definition: log0log.h:768
UNIV_INTERN ibool buf_all_freed(void)
Definition: buf0buf.cc:5173
os_event_t one_flushed_event
Definition: log0log.h:863
UNIV_INTERN ulint log_group_get_capacity(const log_group_t *group)
Definition: log0log.cc:529
#define rw_lock_s_lock(M)
Definition: sync0rw.h:155
UNIV_INLINE ulint ut_fold_binary(const byte *str, ulint len) __attribute__((pure))
#define OS_DATA_FILE
Definition: os0file.h:125
UNIV_INTERN void log_group_set_fields(log_group_t *group, ib_uint64_t lsn)
Definition: log0log.cc:678
ib_uint64_t parse_start_lsn
Definition: log0recv.h:408
UNIV_INTERN void log_archived_file_name_gen(char *buf, ulint id, ulint file_no)
byte * checkpoint_buf
Definition: log0log.h:927
#define ut_ad(EXPR)
Definition: ut0dbg.h:127
UNIV_INTERN ibool recv_scan_log_recs(ulint available_memory, ibool store_to_hash, const byte *buf, ulint len, ib_uint64_t start_lsn, ib_uint64_t *contiguous_lsn, ib_uint64_t *group_scanned_lsn)
Definition: log0recv.cc:2567
ib_uint64_t lsn
Definition: log0log.h:718
UNIV_INTERN ib_uint64_t log_close(void)
Definition: log0log.cc:402
#define UT_LIST_INIT(BASE)
Definition: ut0lst.h:84
ulint max_buf_free
Definition: log0log.h:782
#define ut_error
Definition: ut0dbg.h:115
UNIV_INTERN void ut_sprintf_timestamp(char *buf)
Definition: ut0ut.cc:290
ib_uint64_t current_flush_lsn
Definition: log0log.h:842
byte * buf
Definition: log0log.h:780
ulint scanned_checkpoint_no
Definition: log0recv.h:416
UNIV_INTERN ibool log_checkpoint(ibool sync, ibool write_always)
Definition: log0log.cc:2013
UNIV_INTERN void os_event_free(os_event_t event)
Definition: os0sync.cc:535
ibool recv_no_ibuf_operations
Definition: log0recv.cc:116
UNIV_INTERN void buf_flush_wait_batch_end(buf_pool_t *buf_pool, enum buf_flush type)
Definition: buf0flu.cc:1865
UNIV_INLINE ulint mach_read_from_4(const byte *b) __attribute__((nonnull
#define ut_calc_align(n, m)
Definition: ut0ut.h:187
byte ** file_header_bufs_ptr
Definition: log0log.h:723
UNIV_INTERN void fil_flush_file_spaces(ulint purpose)
Definition: fil0fil.cc:4749
UNIV_INTERN void ut_print_timestamp(FILE *file)
Definition: ut0ut.cc:247
UNIV_INTERN ulint fil_write_flushed_lsn_to_data_files(ib_uint64_t lsn, ulint arch_log_no)
Definition: fil0fil.cc:1754
#define OS_FILE_OPEN
Definition: os0file.h:107
ibool recv_recovery_on
Definition: log0recv.cc:77
srv_shutdown_state
Definition: srv0start.h:113
UNIV_INTERN ibool srv_is_any_background_thread_active(void)
Definition: srv0srv.cc:2589
os_event_t no_flush_event
Definition: log0log.h:853
UNIV_INTERN void log_groups_write_checkpoint_info(void)
Definition: log0log.cc:1989
ib_uint64_t scanned_lsn
Definition: log0recv.h:413
UNIV_INTERN ibool log_preflush_pool_modified_pages(ib_uint64_t new_oldest, ibool sync)
Definition: log0log.cc:1678
ulint n_log_ios_old
Definition: log0log.h:874
UNIV_INLINE ulint log_block_calc_checksum(const byte *block)
ulint buf_free
Definition: log0log.h:765
UNIV_INLINE void log_release(void)
ulint trx_n_mysql_transactions
Definition: trx0trx.cc:52
ulint log_group_capacity
Definition: log0log.h:881
UNIV_INLINE ibool recv_recovery_is_on(void)
UNIV_INLINE ulint log_block_get_hdr_no(const byte *log_block)
ulint n_pending_checkpoint_writes
Definition: log0log.h:918
UNIV_INTERN void log_checkpoint_get_nth_group_info(const byte *buf, ulint n, ulint *file_no, ulint *offset)
Definition: log0log.cc:1775
ib_uint64_t srv_shutdown_lsn
Definition: srv0start.cc:101
ulint file_size
Definition: log0log.h:712
mutex_t log_flush_order_mutex
Definition: log0log.h:771
time_t last_printout_time
Definition: log0log.h:876
rw_lock_t checkpoint_lock
Definition: log0log.h:921
ulint srv_buf_pool_instances
Definition: srv0srv.cc:255
ulint max_modified_age_sync
Definition: log0log.h:892
ulint write_end_offset
Definition: log0log.h:837
UNIV_INTERN void log_write_low(byte *str, ulint str_len)
Definition: log0log.cc:299
UNIV_INLINE ulint buf_pool_get_curr_size(void)
#define LOG_NO_WAIT
Definition: log0log.h:61
ibool one_flushed
Definition: log0log.h:859