22
22
#include "log0log.h"
23
23
#include "os0file.h"
25
/* The file format tag structure with id and name. */
26
struct file_format_struct {
27
uint id; /* id of the file format */
28
const char* name; /* text representation of the
30
mutex_t mutex; /* covers changes to the above
34
typedef struct file_format_struct file_format_t;
36
25
/* The transaction system */
37
UNIV_INTERN trx_sys_t* trx_sys = NULL;
38
UNIV_INTERN trx_doublewrite_t* trx_doublewrite = NULL;
26
trx_sys_t* trx_sys = NULL;
27
trx_doublewrite_t* trx_doublewrite = NULL;
40
29
/* The following is set to TRUE when we are upgrading from the old format data
41
30
files to the new >= 4.1.x format multiple tablespaces format data files */
43
UNIV_INTERN ibool trx_doublewrite_must_reset_space_ids = FALSE;
32
ibool trx_doublewrite_must_reset_space_ids = FALSE;
45
34
/* The following is TRUE when we are using the database in the new format,
46
35
i.e., we have successfully upgraded, or have created a new database
49
UNIV_INTERN ibool trx_sys_multiple_tablespace_format = FALSE;
38
ibool trx_sys_multiple_tablespace_format = FALSE;
51
40
/* In a MySQL replication slave, in crash recovery we store the master log
52
41
file name and position here. We have successfully got the updates to InnoDB
53
42
up to this position. If .._pos is -1, it means no crash recovery was needed,
54
43
or there was no master log position info inside InnoDB. */
56
UNIV_INTERN char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
57
UNIV_INTERN ib_int64_t trx_sys_mysql_master_log_pos = -1;
45
char trx_sys_mysql_master_log_name[TRX_SYS_DRIZZLE_LOG_NAME_LEN];
46
ib_longlong trx_sys_mysql_master_log_pos = -1;
59
48
/* If this MySQL server uses binary logging, after InnoDB has been inited
60
49
and if it has done a crash recovery, we store the binlog file name and position
61
50
here. If .._pos is -1, it means there was no binlog position info inside
64
UNIV_INTERN char trx_sys_mysql_bin_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN];
65
UNIV_INTERN ib_int64_t trx_sys_mysql_bin_log_pos = -1;
67
/* List of animal names representing file format. */
68
static const char* file_format_name_map[] = {
97
/* The number of elements in the file format name array. */
98
static const ulint FILE_FORMAT_NAME_N =
99
sizeof(file_format_name_map) / sizeof(file_format_name_map[0]);
101
/* This is used to track the maximum file format id known to InnoDB. It's
102
updated via SET GLOBAL innodb_file_format_check = 'x' or when we open
103
or create a table. */
104
static file_format_t file_format_max;
53
char trx_sys_mysql_bin_log_name[TRX_SYS_DRIZZLE_LOG_NAME_LEN];
54
ib_longlong trx_sys_mysql_bin_log_pos = -1;
106
57
/********************************************************************
107
58
Determines if a page number is located inside the doublewrite buffer. */
110
61
trx_doublewrite_page_inside(
111
62
/*========================*/
525
472
/* It is an unwritten doublewrite buffer page:
528
ulint zip_size = fil_space_get_zip_size(space_id);
530
/* Read in the actual page from the file */
531
fil_io(OS_FILE_READ, TRUE, space_id, zip_size,
533
zip_size ? zip_size : UNIV_PAGE_SIZE,
475
/* Read in the actual page from the data files */
477
fil_io(OS_FILE_READ, TRUE, space_id, page_no, 0,
478
UNIV_PAGE_SIZE, read_buf, NULL);
536
479
/* Check if the page is corrupt */
539
(buf_page_is_corrupted(read_buf, zip_size))) {
481
if (buf_page_is_corrupted(read_buf)) {
542
484
"InnoDB: Warning: database page"
543
485
" corruption or a failed\n"
544
"InnoDB: file read of"
545
" space %lu page %lu.\n"
486
"InnoDB: file read of page %lu.\n",
546
489
"InnoDB: Trying to recover it from"
547
" the doublewrite buffer.\n",
548
(ulong) space_id, (ulong) page_no);
490
" the doublewrite buffer.\n");
550
if (buf_page_is_corrupted(page, zip_size)) {
492
if (buf_page_is_corrupted(page)) {
552
494
"InnoDB: Dump of the page:\n");
553
buf_page_print(read_buf, zip_size);
495
buf_page_print(read_buf);
555
497
"InnoDB: Dump of"
556
498
" corresponding page"
557
499
" in doublewrite buffer:\n");
558
buf_page_print(page, zip_size);
500
buf_page_print(page);
561
503
"InnoDB: Also the page in the"
671
612
sys_header = trx_sysf_get(mtr);
673
614
if (mach_read_from_4(sys_header + field
674
+ TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
675
!= TRX_SYS_MYSQL_LOG_MAGIC_N) {
615
+ TRX_SYS_DRIZZLE_LOG_MAGIC_N_FLD)
616
!= TRX_SYS_DRIZZLE_LOG_MAGIC_N) {
677
618
mlog_write_ulint(sys_header + field
678
+ TRX_SYS_MYSQL_LOG_MAGIC_N_FLD,
679
TRX_SYS_MYSQL_LOG_MAGIC_N,
619
+ TRX_SYS_DRIZZLE_LOG_MAGIC_N_FLD,
620
TRX_SYS_DRIZZLE_LOG_MAGIC_N,
680
621
MLOG_4BYTES, mtr);
683
if (0 != strcmp((char*) (sys_header + field + TRX_SYS_MYSQL_LOG_NAME),
624
if (0 != strcmp((char*) (sys_header + field + TRX_SYS_DRIZZLE_LOG_NAME),
686
627
mlog_write_string(sys_header + field
687
+ TRX_SYS_MYSQL_LOG_NAME,
628
+ TRX_SYS_DRIZZLE_LOG_NAME,
688
629
(byte*) file_name, 1 + ut_strlen(file_name),
692
633
if (mach_read_from_4(sys_header + field
693
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH) > 0
634
+ TRX_SYS_DRIZZLE_LOG_OFFSET_HIGH) > 0
694
635
|| (offset >> 32) > 0) {
696
637
mlog_write_ulint(sys_header + field
697
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH,
638
+ TRX_SYS_DRIZZLE_LOG_OFFSET_HIGH,
698
639
(ulint)(offset >> 32),
699
640
MLOG_4BYTES, mtr);
702
643
mlog_write_ulint(sys_header + field
703
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW,
644
+ TRX_SYS_DRIZZLE_LOG_OFFSET_LOW,
704
645
(ulint)(offset & 0xFFFFFFFFUL),
705
646
MLOG_4BYTES, mtr);
709
650
/*********************************************************************
710
651
Prints to stderr the MySQL binlog info in the system header if the
711
652
magic number shows it valid. */
714
655
trx_sys_print_mysql_binlog_offset_from_page(
715
656
/*========================================*/
716
const byte* page) /* in: buffer containing the trx
717
system header page, i.e., page number
718
TRX_SYS_PAGE_NO in the tablespace */
657
byte* page) /* in: buffer containing the trx system header page,
658
i.e., page number TRX_SYS_PAGE_NO in the tablespace */
720
const trx_sysf_t* sys_header;
660
trx_sysf_t* sys_header;
722
662
sys_header = page + TRX_SYS;
724
if (mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
725
+ TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
726
== TRX_SYS_MYSQL_LOG_MAGIC_N) {
664
if (mach_read_from_4(sys_header + TRX_SYS_DRIZZLE_LOG_INFO
665
+ TRX_SYS_DRIZZLE_LOG_MAGIC_N_FLD)
666
== TRX_SYS_DRIZZLE_LOG_MAGIC_N) {
729
669
"ibbackup: Last MySQL binlog file position %lu %lu,"
730
670
" file name %s\n",
731
671
(ulong) mach_read_from_4(
732
sys_header + TRX_SYS_MYSQL_LOG_INFO
733
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
672
sys_header + TRX_SYS_DRIZZLE_LOG_INFO
673
+ TRX_SYS_DRIZZLE_LOG_OFFSET_HIGH),
734
674
(ulong) mach_read_from_4(
735
sys_header + TRX_SYS_MYSQL_LOG_INFO
736
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW),
737
sys_header + TRX_SYS_MYSQL_LOG_INFO
738
+ TRX_SYS_MYSQL_LOG_NAME);
675
sys_header + TRX_SYS_DRIZZLE_LOG_INFO
676
+ TRX_SYS_DRIZZLE_LOG_OFFSET_LOW),
677
sys_header + TRX_SYS_DRIZZLE_LOG_INFO
678
+ TRX_SYS_DRIZZLE_LOG_NAME);
741
681
#endif /* UNIV_HOTBACKUP */
769
709
trx_sys_mysql_bin_log_pos_high = mach_read_from_4(
770
sys_header + TRX_SYS_MYSQL_LOG_INFO
771
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH);
710
sys_header + TRX_SYS_DRIZZLE_LOG_INFO
711
+ TRX_SYS_DRIZZLE_LOG_OFFSET_HIGH);
772
712
trx_sys_mysql_bin_log_pos_low = mach_read_from_4(
773
sys_header + TRX_SYS_MYSQL_LOG_INFO
774
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW);
713
sys_header + TRX_SYS_DRIZZLE_LOG_INFO
714
+ TRX_SYS_DRIZZLE_LOG_OFFSET_LOW);
776
716
trx_sys_mysql_bin_log_pos
777
= (((ib_int64_t)trx_sys_mysql_bin_log_pos_high) << 32)
778
+ (ib_int64_t)trx_sys_mysql_bin_log_pos_low;
717
= (((ib_longlong)trx_sys_mysql_bin_log_pos_high) << 32)
718
+ (ib_longlong)trx_sys_mysql_bin_log_pos_low;
780
720
ut_memcpy(trx_sys_mysql_bin_log_name,
781
sys_header + TRX_SYS_MYSQL_LOG_INFO
782
+ TRX_SYS_MYSQL_LOG_NAME, TRX_SYS_MYSQL_LOG_NAME_LEN);
721
sys_header + TRX_SYS_DRIZZLE_LOG_INFO
722
+ TRX_SYS_DRIZZLE_LOG_NAME, TRX_SYS_DRIZZLE_LOG_NAME_LEN);
785
725
"InnoDB: Last MySQL binlog file position %lu %lu,"
819
759
" master binlog file\n"
820
760
"InnoDB: position %lu %lu, file name %s\n",
821
761
(ulong) mach_read_from_4(sys_header
822
+ TRX_SYS_MYSQL_MASTER_LOG_INFO
823
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
762
+ TRX_SYS_DRIZZLE_MASTER_LOG_INFO
763
+ TRX_SYS_DRIZZLE_LOG_OFFSET_HIGH),
824
764
(ulong) mach_read_from_4(sys_header
825
+ TRX_SYS_MYSQL_MASTER_LOG_INFO
826
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW),
827
sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
828
+ TRX_SYS_MYSQL_LOG_NAME);
765
+ TRX_SYS_DRIZZLE_MASTER_LOG_INFO
766
+ TRX_SYS_DRIZZLE_LOG_OFFSET_LOW),
767
sys_header + TRX_SYS_DRIZZLE_MASTER_LOG_INFO
768
+ TRX_SYS_DRIZZLE_LOG_NAME);
829
769
/* Copy the master log position info to global variables we can
830
770
use in ha_innobase.cc to initialize glob_mi to right values */
832
772
ut_memcpy(trx_sys_mysql_master_log_name,
833
sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
834
+ TRX_SYS_MYSQL_LOG_NAME,
835
TRX_SYS_MYSQL_LOG_NAME_LEN);
773
sys_header + TRX_SYS_DRIZZLE_MASTER_LOG_INFO
774
+ TRX_SYS_DRIZZLE_LOG_NAME,
775
TRX_SYS_DRIZZLE_LOG_NAME_LEN);
837
777
trx_sys_mysql_master_log_pos
838
= (((ib_int64_t) mach_read_from_4(
839
sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
840
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32)
841
+ ((ib_int64_t) mach_read_from_4(
842
sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
843
+ TRX_SYS_MYSQL_LOG_OFFSET_LOW));
778
= (((ib_longlong) mach_read_from_4(
779
sys_header + TRX_SYS_DRIZZLE_MASTER_LOG_INFO
780
+ TRX_SYS_DRIZZLE_LOG_OFFSET_HIGH)) << 32)
781
+ ((ib_longlong) mach_read_from_4(
782
sys_header + TRX_SYS_DRIZZLE_MASTER_LOG_INFO
783
+ TRX_SYS_DRIZZLE_LOG_OFFSET_LOW));
844
784
mtr_commit(&mtr);
847
787
/********************************************************************
848
788
Looks for a free slot for a rollback segment in the trx system file copy. */
851
791
trx_sysf_rseg_find_free(
852
792
/*====================*/
1058
996
trx_sys_init_at_db_start();
1061
/*********************************************************************
1062
Update the file format tag. */
1065
trx_sys_file_format_max_write(
1066
/*==========================*/
1067
/* out: always TRUE */
1068
ulint format_id, /* in: file format id */
1069
char** name) /* out: max file format name, can
1075
ulint tag_value_low;
1079
block = buf_page_get(
1080
TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
1082
file_format_max.id = format_id;
1083
file_format_max.name = trx_sys_file_format_id_to_name(format_id);
1085
ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
1086
tag_value_low = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW;
1089
*name = (char*) file_format_max.name;
1094
ut_dulint_create(TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH,
1103
/*********************************************************************
1104
Read the file format tag. */
1107
trx_sys_file_format_max_read(void)
1108
/*==============================*/
1109
/* out: the file format */
1113
const buf_block_t* block;
1115
dulint file_format_id;
1117
/* Since this is called during the startup phase it's safe to
1118
read the value without a covering mutex. */
1121
block = buf_page_get(
1122
TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, RW_X_LATCH, &mtr);
1124
ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG;
1125
file_format_id = mach_read_from_8(ptr);
1129
format_id = file_format_id.low - TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW;
1131
if (file_format_id.high != TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH
1132
|| format_id >= FILE_FORMAT_NAME_N) {
1134
/* Either it has never been tagged, or garbage in it.
1135
Reset the tag in either case. */
1136
format_id = DICT_TF_FORMAT_51;
1137
trx_sys_file_format_max_write(format_id, NULL);
1143
/*********************************************************************
1144
Get the name representation of the file format from its id. */
1147
trx_sys_file_format_id_to_name(
1148
/*===========================*/
1149
/* out: pointer to the name */
1150
const uint id) /* in: id of the file format */
1152
ut_a(id < FILE_FORMAT_NAME_N);
1154
return(file_format_name_map[id]);
1157
/*********************************************************************
1158
Check for the max file format tag stored on disk. Note: If max_format_id
1159
is == DICT_TF_FORMAT_MAX + 1 then we only print a warning. */
1162
trx_sys_file_format_max_check(
1163
/*==========================*/
1164
/* out: DB_SUCCESS or error code */
1165
ulint max_format_id) /* in: max format id to check */
1169
/* Check the file format in the tablespace. Do not try to
1170
recover if the file format is not supported by the engine
1171
unless forced by the user. */
1172
format_id = trx_sys_file_format_max_read();
1174
ut_print_timestamp(stderr);
1176
" InnoDB: highest supported file format is %s.\n",
1177
trx_sys_file_format_id_to_name(DICT_TF_FORMAT_MAX));
1179
if (format_id > DICT_TF_FORMAT_MAX) {
1181
ut_a(format_id < FILE_FORMAT_NAME_N);
1183
ut_print_timestamp(stderr);
1185
" InnoDB: %s: the system tablespace is in a file "
1186
"format that this version doesn't support - %s\n",
1187
((max_format_id <= DICT_TF_FORMAT_MAX)
1188
? "Error" : "Warning"),
1189
trx_sys_file_format_id_to_name(format_id));
1191
if (max_format_id <= DICT_TF_FORMAT_MAX) {
1196
format_id = (format_id > max_format_id) ? format_id : max_format_id;
1198
/* We don't need a mutex here, as this function should only
1199
be called once at start up. */
1200
file_format_max.id = format_id;
1201
file_format_max.name = trx_sys_file_format_id_to_name(format_id);
1206
/*********************************************************************
1207
Set the file format id unconditionally except if it's already the
1211
trx_sys_file_format_max_set(
1212
/*========================*/
1213
/* out: TRUE if value updated */
1214
ulint format_id, /* in: file format id */
1215
char** name) /* out: max file format name */
1220
ut_a(format_id <= DICT_TF_FORMAT_MAX);
1222
mutex_enter(&file_format_max.mutex);
1224
/* Only update if not already same value. */
1225
if (format_id != file_format_max.id) {
1227
ret = trx_sys_file_format_max_write(format_id, name);
1230
mutex_exit(&file_format_max.mutex);
1235
/************************************************************************
1236
Update the file format tag in the tablespace only if the given format id
1237
is greater than the known max id. */
1240
trx_sys_file_format_max_update(
1241
/*===========================*/
1242
uint flags, /* in: flags of the table.*/
1243
char** name) /* out: max file format name */
1248
format_id = (flags & DICT_TF_FORMAT_MASK) >> DICT_TF_FORMAT_SHIFT;
1251
ut_a(file_format_max.name != NULL);
1252
ut_a(format_id <= DICT_TF_FORMAT_MAX);
1254
mutex_enter(&file_format_max.mutex);
1256
if (format_id > file_format_max.id) {
1258
ret = trx_sys_file_format_max_write(format_id, name);
1261
mutex_exit(&file_format_max.mutex);
1266
/*********************************************************************
1267
Get the name representation of the file format from its id. */
1270
trx_sys_file_format_max_get(void)
1271
/*=============================*/
1272
/* out: pointer to the max format name */
1274
return(file_format_max.name);
1277
/*********************************************************************
1278
Initializes the tablespace tag system. */
1281
trx_sys_file_format_init(void)
1282
/*==========================*/
1284
mutex_create(&file_format_max.mutex, SYNC_FILE_FORMAT_TAG);
1286
/* We don't need a mutex here, as this function should only
1287
be called once at start up. */
1288
file_format_max.id = DICT_TF_FORMAT_51;
1290
file_format_max.name = trx_sys_file_format_id_to_name(
1291
file_format_max.id);
1294
/*********************************************************************
1295
Closes the tablespace tag system. */
1298
trx_sys_file_format_close(void)
1299
/*===========================*/
1301
/* Does nothing at the moment */