MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
trx0sys.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "trx0sys.h"
27 
28 #ifdef UNIV_NONINL
29 #include "trx0sys.ic"
30 #endif
31 
32 #ifndef UNIV_HOTBACKUP
33 #include "fsp0fsp.h"
34 #include "mtr0log.h"
35 #include "mtr0log.h"
36 #include "trx0trx.h"
37 #include "trx0rseg.h"
38 #include "trx0undo.h"
39 #include "srv0srv.h"
40 #include "srv0start.h"
41 #include "trx0purge.h"
42 #include "log0log.h"
43 #include "log0recv.h"
44 #include "os0file.h"
45 #include "read0read.h"
46 
48 struct file_format_t {
49  ulint id;
50  const char* name;
54 };
55 
57 UNIV_INTERN trx_sys_t* trx_sys = NULL;
58 
61 /* @{ */
67 UNIV_INTERN ib_int64_t trx_sys_mysql_master_log_pos = -1;
68 /* @} */
69 
73 /* @{ */
77 UNIV_INTERN ib_int64_t trx_sys_mysql_bin_log_pos = -1;
78 /* @} */
79 #endif /* !UNIV_HOTBACKUP */
80 
82 static const char* file_format_name_map[] = {
83  "Antelope",
84  "Barracuda",
85  "Cheetah",
86  "Dragon",
87  "Elk",
88  "Fox",
89  "Gazelle",
90  "Hornet",
91  "Impala",
92  "Jaguar",
93  "Kangaroo",
94  "Leopard",
95  "Moose",
96  "Nautilus",
97  "Ocelot",
98  "Porpoise",
99  "Quail",
100  "Rabbit",
101  "Shark",
102  "Tiger",
103  "Urchin",
104  "Viper",
105  "Whale",
106  "Xenops",
107  "Yak",
108  "Zebra"
109 };
110 
112 static const ulint FILE_FORMAT_NAME_N
113  = sizeof(file_format_name_map) / sizeof(file_format_name_map[0]);
114 
115 #ifdef UNIV_PFS_MUTEX
116 /* Key to register the mutex with performance schema */
117 UNIV_INTERN mysql_pfs_key_t file_format_max_mutex_key;
118 UNIV_INTERN mysql_pfs_key_t trx_sys_mutex_key;
119 #endif /* UNIV_PFS_RWLOCK */
120 
121 #ifndef UNIV_HOTBACKUP
122 #ifdef UNIV_DEBUG
123 /* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */
124 UNIV_INTERN uint trx_rseg_n_slots_debug = 0;
125 #endif
126 
130 static file_format_t file_format_max;
131 
132 #ifdef UNIV_DEBUG
133 /****************************************************************/
136 UNIV_INTERN
137 ibool
138 trx_in_trx_list(
139 /*============*/
140  const trx_t* in_trx)
141 {
142  const trx_t* trx;
143  trx_list_t* trx_list;
144 
145  /* Non-locking autocommits should not hold any locks. */
146  assert_trx_in_list(in_trx);
147 
148  trx_list = in_trx->read_only
150 
151  ut_ad(mutex_own(&trx_sys->mutex));
152 
153  ut_ad(trx_assert_started(in_trx));
154 
155  for (trx = UT_LIST_GET_FIRST(*trx_list);
156  trx != NULL && trx != in_trx;
157  trx = UT_LIST_GET_NEXT(trx_list, trx)) {
158 
159  assert_trx_in_list(trx);
160  ut_ad(trx->read_only == (trx_list == &trx_sys->ro_trx_list));
161  }
162 
163  return(trx != NULL);
164 }
165 #endif /* UNIV_DEBUG */
166 
167 /*****************************************************************/
169 UNIV_INTERN
170 void
172 /*==========================*/
173 {
174  mtr_t mtr;
175  trx_sysf_t* sys_header;
176 
177  ut_ad(mutex_own(&trx_sys->mutex));
178 
179  if (!srv_read_only_mode) {
180  mtr_start(&mtr);
181 
182  sys_header = trx_sysf_get(&mtr);
183 
185  sys_header + TRX_SYS_TRX_ID_STORE,
186  trx_sys->max_trx_id, &mtr);
187 
188  mtr_commit(&mtr);
189  }
190 }
191 
192 /*****************************************************************/
197 UNIV_INTERN
198 void
200 /*===============================*/
201  const char* file_name,
202  ib_int64_t offset,
203  ulint field,
205  mtr_t* mtr)
206 {
207  trx_sysf_t* sys_header;
208 
209  if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
210 
211  /* We cannot fit the name to the 512 bytes we have reserved */
212 
213  return;
214  }
215 
216  sys_header = trx_sysf_get(mtr);
217 
218  if (mach_read_from_4(sys_header + field
221 
222  mlog_write_ulint(sys_header + field
225  MLOG_4BYTES, mtr);
226  }
227 
228  if (0 != strcmp((char*) (sys_header + field + TRX_SYS_MYSQL_LOG_NAME),
229  file_name)) {
230 
231  mlog_write_string(sys_header + field
233  (byte*) file_name, 1 + ut_strlen(file_name),
234  mtr);
235  }
236 
237  if (mach_read_from_4(sys_header + field
239  || (offset >> 32) > 0) {
240 
241  mlog_write_ulint(sys_header + field
243  (ulint)(offset >> 32),
244  MLOG_4BYTES, mtr);
245  }
246 
247  mlog_write_ulint(sys_header + field
249  (ulint)(offset & 0xFFFFFFFFUL),
250  MLOG_4BYTES, mtr);
251 }
252 
253 /*****************************************************************/
256 UNIV_INTERN
257 void
259 /*===================================*/
260 {
261  trx_sysf_t* sys_header;
262  mtr_t mtr;
263  ulint trx_sys_mysql_bin_log_pos_high;
264  ulint trx_sys_mysql_bin_log_pos_low;
265 
266  mtr_start(&mtr);
267 
268  sys_header = trx_sysf_get(&mtr);
269 
273 
274  mtr_commit(&mtr);
275 
276  return;
277  }
278 
279  trx_sys_mysql_bin_log_pos_high = mach_read_from_4(
280  sys_header + TRX_SYS_MYSQL_LOG_INFO
282  trx_sys_mysql_bin_log_pos_low = mach_read_from_4(
283  sys_header + TRX_SYS_MYSQL_LOG_INFO
285 
287  = (((ib_int64_t) trx_sys_mysql_bin_log_pos_high) << 32)
288  + (ib_int64_t) trx_sys_mysql_bin_log_pos_low;
289 
291  sys_header + TRX_SYS_MYSQL_LOG_INFO
293 
294  fprintf(stderr,
295  "InnoDB: Last MySQL binlog file position %lu %lu,"
296  " file name %s\n",
297  trx_sys_mysql_bin_log_pos_high, trx_sys_mysql_bin_log_pos_low,
299 
300  mtr_commit(&mtr);
301 }
302 
303 /*****************************************************************/
306 UNIV_INTERN
307 void
309 /*====================================*/
310 {
311  trx_sysf_t* sys_header;
312  mtr_t mtr;
313 
314  mtr_start(&mtr);
315 
316  sys_header = trx_sysf_get(&mtr);
317 
321 
322  mtr_commit(&mtr);
323 
324  return;
325  }
326 
327  fprintf(stderr,
328  "InnoDB: In a MySQL replication slave the last"
329  " master binlog file\n"
330  "InnoDB: position %lu %lu, file name %s\n",
331  (ulong) mach_read_from_4(sys_header
334  (ulong) mach_read_from_4(sys_header
337  sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
339  /* Copy the master log position info to global variables we can
340  use in ha_innobase.cc to initialize glob_mi to right values */
341 
343  sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
346 
348  = (((ib_int64_t) mach_read_from_4(
349  sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
351  + ((ib_int64_t) mach_read_from_4(
352  sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
354  mtr_commit(&mtr);
355 }
356 
357 /****************************************************************/
360 UNIV_INTERN
361 ulint
363 /*====================*/
364  mtr_t* mtr)
365 {
366  ulint i;
367  trx_sysf_t* sys_header;
368 
369  sys_header = trx_sysf_get(mtr);
370 
371  for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
372  ulint page_no;
373 
374  page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
375 
376  if (page_no == FIL_NULL) {
377 
378  return(i);
379  }
380  }
381 
382  return(ULINT_UNDEFINED);
383 }
384 
385 /*****************************************************************/
388 static
389 void
390 trx_sysf_create(
391 /*============*/
392  mtr_t* mtr)
393 {
394  trx_sysf_t* sys_header;
395  ulint slot_no;
397  page_t* page;
398  ulint page_no;
399  byte* ptr;
400  ulint len;
401 
402  ut_ad(mtr);
403 
404  /* Note that below we first reserve the file space x-latch, and
405  then enter the kernel: we must do it in this order to conform
406  to the latching order rules. */
407 
408  mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), mtr);
409 
410  /* Create the trx sys file block in a new allocated file segment */
411  block = fseg_create(TRX_SYS_SPACE, 0, TRX_SYS + TRX_SYS_FSEG_HEADER,
412  mtr);
413  buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER);
414 
415  ut_a(buf_block_get_page_no(block) == TRX_SYS_PAGE_NO);
416 
417  page = buf_block_get_frame(block);
418 
420  MLOG_2BYTES, mtr);
421 
422  /* Reset the doublewrite buffer magic number to zero so that we
423  know that the doublewrite buffer has not yet been created (this
424  suppresses a Valgrind warning) */
425 
428 
429  sys_header = trx_sysf_get(mtr);
430 
431  /* Start counting transaction ids from number 1 up */
432  mach_write_to_8(sys_header + TRX_SYS_TRX_ID_STORE, 1);
433 
434  /* Reset the rollback segment slots. Old versions of InnoDB
435  define TRX_SYS_N_RSEGS as 256 (TRX_SYS_OLD_N_RSEGS) and expect
436  that the whole array is initialized. */
437  ptr = TRX_SYS_RSEGS + sys_header;
438  len = ut_max(TRX_SYS_OLD_N_RSEGS, TRX_SYS_N_RSEGS)
439  * TRX_SYS_RSEG_SLOT_SIZE;
440  memset(ptr, 0xff, len);
441  ptr += len;
442  ut_a(ptr <= page + (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END));
443 
444  /* Initialize all of the page. This part used to be uninitialized. */
445  memset(ptr, 0, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page - ptr);
446 
447  mlog_log_string(sys_header, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END
448  + page - sys_header, mtr);
449 
450  /* Create the first rollback segment in the SYSTEM tablespace */
451  slot_no = trx_sysf_rseg_find_free(mtr);
452  page_no = trx_rseg_header_create(TRX_SYS_SPACE, 0, ULINT_MAX, slot_no,
453  mtr);
454 
455  ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID);
456  ut_a(page_no == FSP_FIRST_RSEG_PAGE_NO);
457 }
458 
459 /*****************************************************************/
461 static
462 int
463 trx_rseg_compare_last_trx_no(
464 /*=========================*/
465  const void* p1,
466  const void* p2)
467 {
468  ib_int64_t cmp;
469 
470  const rseg_queue_t* rseg_q1 = (const rseg_queue_t*) p1;
471  const rseg_queue_t* rseg_q2 = (const rseg_queue_t*) p2;
472 
473  cmp = rseg_q1->trx_no - rseg_q2->trx_no;
474 
475  if (cmp < 0) {
476  return(-1);
477  } else if (cmp > 0) {
478  return(1);
479  }
480 
481  return(0);
482 }
483 
484 /*****************************************************************/
488 UNIV_INTERN
489 ib_bh_t*
491 /*==========================*/
492 {
493  mtr_t mtr;
494  ib_bh_t* ib_bh;
495  trx_sysf_t* sys_header;
496  ib_uint64_t rows_to_undo = 0;
497  const char* unit = "";
498 
499  /* We create the min binary heap here and pass ownership to
500  purge when we init the purge sub-system. Purge is responsible
501  for freeing the binary heap. */
502 
503  ib_bh = ib_bh_create(
504  trx_rseg_compare_last_trx_no,
505  sizeof(rseg_queue_t), TRX_SYS_N_RSEGS);
506 
507  mtr_start(&mtr);
508 
509  sys_header = trx_sysf_get(&mtr);
510 
512  trx_rseg_array_init(sys_header, ib_bh, &mtr);
513  }
514 
515  /* VERY important: after the database is started, max_trx_id value is
516  divisible by TRX_SYS_TRX_ID_WRITE_MARGIN, and the 'if' in
517  trx_sys_get_new_trx_id will evaluate to TRUE when the function
518  is first time called, and the value for trx id will be written
519  to the disk-based header! Thus trx id values will not overlap when
520  the database is repeatedly started! */
521 
526 
527  ut_d(trx_sys->rw_max_trx_id = trx_sys->max_trx_id);
528 
530 
532 
534 
535  /* This S lock is not strictly required, it is here only to satisfy
536  the debug code (assertions). We are still running in single threaded
537  bootstrap mode. */
538 
539  mutex_enter(&trx_sys->mutex);
540 
542 
543  if (UT_LIST_GET_LEN(trx_sys->rw_trx_list) > 0) {
544  const trx_t* trx;
545 
547  trx != NULL;
548  trx = UT_LIST_GET_NEXT(trx_list, trx)) {
549 
550  ut_ad(trx->is_recovered);
552 
553  if (trx_state_eq(trx, TRX_STATE_ACTIVE)) {
554  rows_to_undo += trx->undo_no;
555  }
556  }
557 
558  if (rows_to_undo > 1000000000) {
559  unit = "M";
560  rows_to_undo = rows_to_undo / 1000000;
561  }
562 
563  fprintf(stderr,
564  "InnoDB: %lu transaction(s) which must be"
565  " rolled back or cleaned up\n"
566  "InnoDB: in total %lu%s row operations to undo\n",
568  (ulong) rows_to_undo, unit);
569 
570  fprintf(stderr, "InnoDB: Trx id counter is " TRX_ID_FMT "\n",
572  }
573 
574  mutex_exit(&trx_sys->mutex);
575 
576  UT_LIST_INIT(trx_sys->view_list);
577 
578  mtr_commit(&mtr);
579 
580  return(ib_bh);
581 }
582 
583 /*****************************************************************/
585 UNIV_INTERN
586 void
588 /*================*/
589 {
590  ut_ad(trx_sys == NULL);
591 
592  trx_sys = static_cast<trx_sys_t*>(mem_zalloc(sizeof(*trx_sys)));
593 
594  mutex_create(trx_sys_mutex_key, &trx_sys->mutex, SYNC_TRX_SYS);
595 }
596 
597 /*****************************************************************/
599 UNIV_INTERN
600 void
602 /*==========================*/
603 {
604  mtr_t mtr;
605 
606  mtr_start(&mtr);
607 
608  trx_sysf_create(&mtr);
609 
610  mtr_commit(&mtr);
611 }
612 
613 /*****************************************************************/
616 static
617 ibool
618 trx_sys_file_format_max_write(
619 /*==========================*/
620  ulint format_id,
621  const char** name)
623 {
624  mtr_t mtr;
625  byte* ptr;
627  ib_uint64_t tag_value;
628 
629  mtr_start(&mtr);
630 
631  block = buf_page_get(
632  TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
633 
634  file_format_max.id = format_id;
635  file_format_max.name = trx_sys_file_format_id_to_name(format_id);
636 
637  ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
638  tag_value = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
639 
640  if (name) {
641  *name = file_format_max.name;
642  }
643 
644  mlog_write_ull(ptr, tag_value, &mtr);
645 
646  mtr_commit(&mtr);
647 
648  return(TRUE);
649 }
650 
651 /*****************************************************************/
654 static
655 ulint
656 trx_sys_file_format_max_read(void)
657 /*==============================*/
658 {
659  mtr_t mtr;
660  const byte* ptr;
661  const buf_block_t* block;
662  ib_id_t file_format_id;
663 
664  /* Since this is called during the startup phase it's safe to
665  read the value without a covering mutex. */
666  mtr_start(&mtr);
667 
668  block = buf_page_get(
669  TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
670 
671  ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
672  file_format_id = mach_read_from_8(ptr);
673 
674  mtr_commit(&mtr);
675 
676  file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
677 
678  if (file_format_id >= FILE_FORMAT_NAME_N) {
679 
680  /* Either it has never been tagged, or garbage in it. */
681  return(ULINT_UNDEFINED);
682  }
683 
684  return((ulint) file_format_id);
685 }
686 
687 /*****************************************************************/
690 UNIV_INTERN
691 const char*
693 /*===========================*/
694  const ulint id)
695 {
696  ut_a(id < FILE_FORMAT_NAME_N);
697 
698  return(file_format_name_map[id]);
699 }
700 
701 /*****************************************************************/
705 UNIV_INTERN
706 dberr_t
708 /*==========================*/
709  ulint max_format_id)
710 {
711  ulint format_id;
712 
713  /* Check the file format in the tablespace. Do not try to
714  recover if the file format is not supported by the engine
715  unless forced by the user. */
716  format_id = trx_sys_file_format_max_read();
717  if (format_id == ULINT_UNDEFINED) {
718  /* Format ID was not set. Set it to minimum possible
719  value. */
720  format_id = UNIV_FORMAT_MIN;
721  }
722 
723  ib_logf(IB_LOG_LEVEL_INFO,
724  "Highest supported file format is %s.",
725  trx_sys_file_format_id_to_name(UNIV_FORMAT_MAX));
726 
727  if (format_id > UNIV_FORMAT_MAX) {
728 
729  ut_a(format_id < FILE_FORMAT_NAME_N);
730 
731  ib_logf(max_format_id <= UNIV_FORMAT_MAX
732  ? IB_LOG_LEVEL_ERROR : IB_LOG_LEVEL_WARN,
733  "The system tablespace is in a file "
734  "format that this version doesn't support - %s.",
735  trx_sys_file_format_id_to_name(format_id));
736 
737  if (max_format_id <= UNIV_FORMAT_MAX) {
738  return(DB_ERROR);
739  }
740  }
741 
742  format_id = (format_id > max_format_id) ? format_id : max_format_id;
743 
744  /* We don't need a mutex here, as this function should only
745  be called once at start up. */
746  file_format_max.id = format_id;
747  file_format_max.name = trx_sys_file_format_id_to_name(format_id);
748 
749  return(DB_SUCCESS);
750 }
751 
752 /*****************************************************************/
756 UNIV_INTERN
757 ibool
759 /*========================*/
760  ulint format_id,
761  const char** name)
763 {
764  ibool ret = FALSE;
765 
766  ut_a(format_id <= UNIV_FORMAT_MAX);
767 
768  mutex_enter(&file_format_max.mutex);
769 
770  /* Only update if not already same value. */
771  if (format_id != file_format_max.id) {
772 
773  ret = trx_sys_file_format_max_write(format_id, name);
774  }
775 
776  mutex_exit(&file_format_max.mutex);
777 
778  return(ret);
779 }
780 
781 /********************************************************************/
786 UNIV_INTERN
787 void
789 /*==============================*/
790 {
791  ulint format_id;
792 
793  format_id = trx_sys_file_format_max_read();
794 
795  /* If format_id is not set then set it to the minimum. */
796  if (format_id == ULINT_UNDEFINED) {
797  trx_sys_file_format_max_set(UNIV_FORMAT_MIN, NULL);
798  }
799 }
800 
801 /********************************************************************/
805 UNIV_INTERN
806 ibool
808 /*============================*/
809  const char** name,
810  ulint format_id)
811 {
812  ibool ret = FALSE;
813 
814  ut_a(name);
815  ut_a(file_format_max.name != NULL);
816  ut_a(format_id <= UNIV_FORMAT_MAX);
817 
818  mutex_enter(&file_format_max.mutex);
819 
820  if (format_id > file_format_max.id) {
821 
822  ret = trx_sys_file_format_max_write(format_id, name);
823  }
824 
825  mutex_exit(&file_format_max.mutex);
826 
827  return(ret);
828 }
829 
830 /*****************************************************************/
833 UNIV_INTERN
834 const char*
836 /*=============================*/
837 {
838  return(file_format_max.name);
839 }
840 
841 /*****************************************************************/
843 UNIV_INTERN
844 void
846 /*==========================*/
847 {
848  mutex_create(file_format_max_mutex_key,
849  &file_format_max.mutex, SYNC_FILE_FORMAT_TAG);
850 
851  /* We don't need a mutex here, as this function should only
852  be called once at start up. */
853  file_format_max.id = UNIV_FORMAT_MIN;
854 
855  file_format_max.name = trx_sys_file_format_id_to_name(
856  file_format_max.id);
857 }
858 
859 /*****************************************************************/
861 UNIV_INTERN
862 void
864 /*===========================*/
865 {
866  /* Does nothing at the moment */
867 }
868 
869 /*********************************************************************
870 Creates the rollback segments.
871 @return number of rollback segments that are active. */
872 UNIV_INTERN
873 ulint
875 /*=================*/
876  ulint n_spaces,
877  ulint n_rsegs)
878 {
879  mtr_t mtr;
880  ulint n_used;
881 
882  ut_a(n_spaces < TRX_SYS_N_RSEGS);
883  ut_a(n_rsegs <= TRX_SYS_N_RSEGS);
884 
886  return(ULINT_UNDEFINED);
887  }
888 
889  /* This is executed in single-threaded mode therefore it is not
890  necessary to use the same mtr in trx_rseg_create(). n_used cannot
891  change while the function is executing. */
892 
893  mtr_start(&mtr);
894  n_used = trx_sysf_rseg_find_free(&mtr);
895  mtr_commit(&mtr);
896 
897  if (n_used == ULINT_UNDEFINED) {
898  n_used = TRX_SYS_N_RSEGS;
899  }
900 
901  /* Do not create additional rollback segments if innodb_force_recovery
902  has been set and the database was not shutdown cleanly. */
903 
904  if (!srv_force_recovery && !recv_needed_recovery && n_used < n_rsegs) {
905  ulint i;
906  ulint new_rsegs = n_rsegs - n_used;
907 
908  for (i = 0; i < new_rsegs; ++i) {
909  ulint space;
910 
911  /* Tablespace 0 is the system tablespace. All UNDO
912  log tablespaces start from 1. */
913 
914  if (n_spaces > 0) {
915  space = (i % n_spaces) + 1;
916  } else {
917  space = 0; /* System tablespace */
918  }
919 
920  if (trx_rseg_create(space) != NULL) {
921  ++n_used;
922  } else {
923  break;
924  }
925  }
926  }
927 
928  ib_logf(IB_LOG_LEVEL_INFO,
929  "%lu rollback segment(s) are active.", n_used);
930 
931  return(n_used);
932 }
933 
934 #else /* !UNIV_HOTBACKUP */
935 /*****************************************************************/
938 UNIV_INTERN
939 void
940 trx_sys_print_mysql_binlog_offset_from_page(
941 /*========================================*/
942  const byte* page)
945 {
946  const trx_sysf_t* sys_header;
947 
948  sys_header = page + TRX_SYS;
949 
953 
954  fprintf(stderr,
955  "ibbackup: Last MySQL binlog file position %lu %lu,"
956  " file name %s\n",
957  (ulong) mach_read_from_4(
958  sys_header + TRX_SYS_MYSQL_LOG_INFO
960  (ulong) mach_read_from_4(
961  sys_header + TRX_SYS_MYSQL_LOG_INFO
963  sys_header + TRX_SYS_MYSQL_LOG_INFO
965  }
966 }
967 
968 /*****************************************************************/
974 UNIV_INTERN
975 ibool
976 trx_sys_read_file_format_id(
977 /*========================*/
978  const char *pathname,
980  ulint *format_id)
982 {
983  os_file_t file;
984  ibool success;
985  byte buf[UNIV_PAGE_SIZE * 2];
986  page_t* page = ut_align(buf, UNIV_PAGE_SIZE);
987  const byte* ptr;
988  ib_id_t file_format_id;
989 
990  *format_id = ULINT_UNDEFINED;
991 
992  file = os_file_create_simple_no_error_handling(
993  innodb_file_data_key,
994  pathname,
995  OS_FILE_OPEN,
996  OS_FILE_READ_ONLY,
997  &success
998  );
999  if (!success) {
1000  /* The following call prints an error message */
1001  os_file_get_last_error(true);
1002 
1003  ut_print_timestamp(stderr);
1004 
1005  fprintf(stderr,
1006  " ibbackup: Error: trying to read system tablespace "
1007  "file format,\n"
1008  " ibbackup: but could not open the tablespace "
1009  "file %s!\n", pathname);
1010  return(FALSE);
1011  }
1012 
1013  /* Read the page on which file format is stored */
1014 
1015  success = os_file_read_no_error_handling(
1016  file, page, TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE, UNIV_PAGE_SIZE);
1017 
1018  if (!success) {
1019  /* The following call prints an error message */
1020  os_file_get_last_error(true);
1021 
1022  ut_print_timestamp(stderr);
1023 
1024  fprintf(stderr,
1025  " ibbackup: Error: trying to read system tablespace "
1026  "file format,\n"
1027  " ibbackup: but failed to read the tablespace "
1028  "file %s!\n", pathname);
1029 
1030  os_file_close(file);
1031  return(FALSE);
1032  }
1033  os_file_close(file);
1034 
1035  /* get the file format from the page */
1036  ptr = page + TRX_SYS_FILE_FORMAT_TAG;
1037  file_format_id = mach_read_from_8(ptr);
1038  file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N;
1039 
1040  if (file_format_id >= FILE_FORMAT_NAME_N) {
1041 
1042  /* Either it has never been tagged, or garbage in it. */
1043  return(TRUE);
1044  }
1045 
1046  *format_id = (ulint) file_format_id;
1047 
1048  return(TRUE);
1049 }
1050 
1051 /*****************************************************************/
1054 UNIV_INTERN
1055 ibool
1056 trx_sys_read_pertable_file_format_id(
1057 /*=================================*/
1058  const char *pathname,
1060  ulint *format_id)
1062 {
1063  os_file_t file;
1064  ibool success;
1065  byte buf[UNIV_PAGE_SIZE * 2];
1066  page_t* page = ut_align(buf, UNIV_PAGE_SIZE);
1067  const byte* ptr;
1068  ib_uint32_t flags;
1069 
1070  *format_id = ULINT_UNDEFINED;
1071 
1072  file = os_file_create_simple_no_error_handling(
1073  innodb_file_data_key,
1074  pathname,
1075  OS_FILE_OPEN,
1076  OS_FILE_READ_ONLY,
1077  &success
1078  );
1079  if (!success) {
1080  /* The following call prints an error message */
1081  os_file_get_last_error(true);
1082 
1083  ut_print_timestamp(stderr);
1084 
1085  fprintf(stderr,
1086  " ibbackup: Error: trying to read per-table "
1087  "tablespace format,\n"
1088  " ibbackup: but could not open the tablespace "
1089  "file %s!\n", pathname);
1090 
1091  return(FALSE);
1092  }
1093 
1094  /* Read the first page of the per-table datafile */
1095 
1096  success = os_file_read_no_error_handling(file, page, 0, UNIV_PAGE_SIZE);
1097 
1098  if (!success) {
1099  /* The following call prints an error message */
1100  os_file_get_last_error(true);
1101 
1102  ut_print_timestamp(stderr);
1103 
1104  fprintf(stderr,
1105  " ibbackup: Error: trying to per-table data file "
1106  "format,\n"
1107  " ibbackup: but failed to read the tablespace "
1108  "file %s!\n", pathname);
1109 
1110  os_file_close(file);
1111  return(FALSE);
1112  }
1113  os_file_close(file);
1114 
1115  /* get the file format from the page */
1116  ptr = page + 54;
1117  flags = mach_read_from_4(ptr);
1118  if (flags == 0) {
1119  /* file format is Antelope */
1120  *format_id = 0;
1121  return(TRUE);
1122  } else if (flags & 1) {
1123  /* tablespace flags are ok */
1124  *format_id = (flags / 32) % 128;
1125  return(TRUE);
1126  } else {
1127  /* bad tablespace flags */
1128  return(FALSE);
1129  }
1130 }
1131 
1132 
1133 /*****************************************************************/
1136 UNIV_INTERN
1137 const char*
1139 /*===========================*/
1140  const ulint id)
1141 {
1142  if (!(id < FILE_FORMAT_NAME_N)) {
1143  /* unknown id */
1144  return("Unknown");
1145  }
1146 
1147  return(file_format_name_map[id]);
1148 }
1149 
1150 #endif /* !UNIV_HOTBACKUP */
1151 
1152 #ifndef UNIV_HOTBACKUP
1153 /*********************************************************************
1154 Shutdown/Close the transaction system. */
1155 UNIV_INTERN
1156 void
1158 /*===============*/
1159 {
1160  ulint i;
1161  trx_t* trx;
1162  read_view_t* view;
1163 
1164  ut_ad(trx_sys != NULL);
1166 
1167  /* Check that all read views are closed except read view owned
1168  by a purge. */
1169 
1170  mutex_enter(&trx_sys->mutex);
1171 
1172  if (UT_LIST_GET_LEN(trx_sys->view_list) > 1) {
1173  fprintf(stderr,
1174  "InnoDB: Error: all read views were not closed"
1175  " before shutdown:\n"
1176  "InnoDB: %lu read views open \n",
1177  UT_LIST_GET_LEN(trx_sys->view_list) - 1);
1178  }
1179 
1180  mutex_exit(&trx_sys->mutex);
1181 
1183  trx_dummy_sess = NULL;
1184 
1186 
1187  /* Free the double write data structures. */
1188  buf_dblwr_free();
1189 
1190  mutex_enter(&trx_sys->mutex);
1191 
1193 
1194  /* Only prepared transactions may be left in the system. Free them. */
1196 
1197  while ((trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list)) != NULL) {
1198  trx_free_prepared(trx);
1199  }
1200 
1201  /* There can't be any active transactions. */
1202  for (i = 0; i < TRX_SYS_N_RSEGS; ++i) {
1203  trx_rseg_t* rseg;
1204 
1205  rseg = trx_sys->rseg_array[i];
1206 
1207  if (rseg != NULL) {
1208  trx_rseg_mem_free(rseg);
1209  } else {
1210  break;
1211  }
1212  }
1213 
1214  view = UT_LIST_GET_FIRST(trx_sys->view_list);
1215 
1216  while (view != NULL) {
1217  read_view_t* prev_view = view;
1218 
1219  view = UT_LIST_GET_NEXT(view_list, prev_view);
1220 
1221  /* Views are allocated from the trx_sys->global_read_view_heap.
1222  So, we simply remove the element here. */
1223  UT_LIST_REMOVE(view_list, trx_sys->view_list, prev_view);
1224  }
1225 
1226  ut_a(UT_LIST_GET_LEN(trx_sys->view_list) == 0);
1230 
1231  mutex_exit(&trx_sys->mutex);
1232 
1233  mutex_free(&trx_sys->mutex);
1234 
1235  mem_free(trx_sys);
1236 
1237  trx_sys = NULL;
1238 }
1239 
1240 /*********************************************************************
1241 Check if there are any active (non-prepared) transactions.
1242 @return total number of active transactions or 0 if none */
1243 UNIV_INTERN
1244 ulint
1245 trx_sys_any_active_transactions(void)
1246 /*=================================*/
1247 {
1248  ulint total_trx = 0;
1249 
1250  mutex_enter(&trx_sys->mutex);
1251 
1252  total_trx = UT_LIST_GET_LEN(trx_sys->rw_trx_list)
1254 
1255  ut_a(total_trx >= trx_sys->n_prepared_trx);
1256  total_trx -= trx_sys->n_prepared_trx;
1257 
1258  mutex_exit(&trx_sys->mutex);
1259 
1260  return(total_trx);
1261 }
1262 
1263 #ifdef UNIV_DEBUG
1264 /*************************************************************/
1267 static
1268 ibool
1269 trx_sys_validate_trx_list_low(
1270 /*===========================*/
1271  trx_list_t* trx_list)
1273 {
1274  const trx_t* trx;
1275  const trx_t* prev_trx = NULL;
1276 
1277  ut_ad(mutex_own(&trx_sys->mutex));
1278 
1279  ut_ad(trx_list == &trx_sys->ro_trx_list
1280  || trx_list == &trx_sys->rw_trx_list);
1281 
1282  for (trx = UT_LIST_GET_FIRST(*trx_list);
1283  trx != NULL;
1284  prev_trx = trx, trx = UT_LIST_GET_NEXT(trx_list, prev_trx)) {
1285 
1286  assert_trx_in_list(trx);
1287  ut_ad(trx->read_only == (trx_list == &trx_sys->ro_trx_list));
1288 
1289  ut_a(prev_trx == NULL || prev_trx->id > trx->id);
1290  }
1291 
1292  return(TRUE);
1293 }
1294 
1295 /*************************************************************/
1298 UNIV_INTERN
1299 ibool
1300 trx_sys_validate_trx_list(void)
1301 /*===========================*/
1302 {
1303  ut_ad(mutex_own(&trx_sys->mutex));
1304 
1305  ut_a(trx_sys_validate_trx_list_low(&trx_sys->ro_trx_list));
1306  ut_a(trx_sys_validate_trx_list_low(&trx_sys->rw_trx_list));
1307 
1308  return(TRUE);
1309 }
1310 #endif /* UNIV_DEBUG */
1311 #endif /* !UNIV_HOTBACKUP */