# name : innodb_overwrite_relay_log_info.patch # introduced : 11 or before # maintainer : Yasufumi # #!!! notice !!! # Any small change to this file in the main branch # should be done or reviewed by the maintainer! --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -42,6 +42,8 @@ #pragma implementation // gcc: Class implementation #endif +#define MYSQL_SERVER + #include // explain_filename, nz2, EXPLAIN_PARTITIONS_AS_COMMENT, // EXPLAIN_FILENAME_MAX_EXTRA_LENGTH @@ -53,6 +55,15 @@ #include #include +#ifdef MYSQL_SERVER +#include +#include +// Defined in slave.cc +int init_intvar_from_file(int* var, IO_CACHE* f, int default_val); +int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, + const char *default_val); +#endif /* MYSQL_SERVER */ + /** @file ha_innodb.cc */ /* Include necessary InnoDB headers */ @@ -91,6 +102,14 @@ #include "ha_innodb.h" #include "i_s.h" +#ifdef MYSQL_SERVER +// Defined in trx0sys.c +extern char trx_sys_mysql_master_log_name[]; +extern ib_int64_t trx_sys_mysql_master_log_pos; +extern char trx_sys_mysql_relay_log_name[]; +extern ib_int64_t trx_sys_mysql_relay_log_pos; +#endif /* MYSQL_SERVER */ + # ifndef MYSQL_PLUGIN_IMPORT # define MYSQL_PLUGIN_IMPORT /* nothing */ # endif /* MYSQL_PLUGIN_IMPORT */ @@ -163,6 +182,7 @@ static my_bool innobase_use_doublewrite = TRUE; static my_bool innobase_use_checksums = TRUE; static my_bool innobase_locks_unsafe_for_binlog = FALSE; +static my_bool innobase_overwrite_relay_log_info = FALSE; static my_bool innobase_rollback_on_timeout = FALSE; static my_bool innobase_create_status_file = FALSE; static my_bool innobase_stats_on_metadata = TRUE; @@ -2282,6 +2302,89 @@ } #endif /* DBUG_OFF */ +#ifndef MYSQL_SERVER + innodb_overwrite_relay_log_info = FALSE; +#endif + +#ifdef HAVE_REPLICATION +#ifdef MYSQL_SERVER + /* read master log position from relay-log.info if exists */ + char fname[FN_REFLEN+128]; + int pos; + int info_fd; + IO_CACHE info_file; + + fname[0] = '\0'; + + if(innobase_overwrite_relay_log_info) { + + fprintf(stderr, + "InnoDB: Warning: innodb_overwrite_relay_log_info is enabled." + " Updates by other storage engines may not be synchronized.\n"); + + bzero((char*) &info_file, sizeof(info_file)); + fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32); + + int error=0; + + if (!access(fname,F_OK)) { + /* exist */ + if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) { + error=1; + } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, + READ_CACHE, 0L, 0, MYF(MY_WME))) { + error=1; + } + + if (error) { +relay_info_error: + if (info_fd >= 0) + my_close(info_fd, MYF(0)); + fname[0] = '\0'; + goto skip_relay; + } + } else { + fname[0] = '\0'; + goto skip_relay; + } + + if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") || /* dummy (it is relay-log) */ + init_intvar_from_file(&pos, &info_file, BIN_LOG_HEADER_SIZE)) { + end_io_cache(&info_file); + error=1; + goto relay_info_error; + } + + fprintf(stderr, + "InnoDB: relay-log.info is detected.\n" + "InnoDB: relay log: position %u, file name %s\n", + pos, fname); + + strncpy(trx_sys_mysql_relay_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + trx_sys_mysql_relay_log_pos = (ib_int64_t) pos; + + if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") || + init_intvar_from_file(&pos, &info_file, 0)) { + end_io_cache(&info_file); + error=1; + goto relay_info_error; + } + + fprintf(stderr, + "InnoDB: master log: position %u, file name %s\n", + pos, fname); + + strncpy(trx_sys_mysql_master_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + trx_sys_mysql_master_log_pos = (ib_int64_t) pos; + + end_io_cache(&info_file); + if (info_fd >= 0) + my_close(info_fd, MYF(0)); + } +skip_relay: +#endif /* MYSQL_SERVER */ +#endif /* HAVE_REPLICATION */ + /* Check that values don't overflow on 32-bit systems. */ if (sizeof(ulint) == 4) { if (innobase_buffer_pool_size > UINT_MAX32) { @@ -2580,6 +2683,76 @@ goto mem_free_and_error; } +#ifdef HAVE_REPLICATION +#ifdef MYSQL_SERVER + if(innobase_overwrite_relay_log_info) { + /* If InnoDB progressed from relay-log.info, overwrite it */ + if (fname[0] == '\0') { + fprintf(stderr, + "InnoDB: Something is wrong with the file relay-info.log. InnoDB will not overwrite it.\n"); + } else if (0 != strcmp(fname, trx_sys_mysql_master_log_name) + || pos != trx_sys_mysql_master_log_pos) { + /* Overwrite relay-log.info */ + bzero((char*) &info_file, sizeof(info_file)); + fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32); + + int error = 0; + + if (!access(fname,F_OK)) { + /* exist */ + if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) { + error = 1; + } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, + WRITE_CACHE, 0L, 0, MYF(MY_WME))) { + error = 1; + } + + if (error) { + if (info_fd >= 0) + my_close(info_fd, MYF(0)); + goto skip_overwrite; + } + } else { + error = 1; + goto skip_overwrite; + } + + char buff[FN_REFLEN*2+22*2+4], *pos; + + my_b_seek(&info_file, 0L); + pos=strmov(buff, trx_sys_mysql_relay_log_name); + *pos++='\n'; + pos=longlong2str(trx_sys_mysql_relay_log_pos, pos, 10); + *pos++='\n'; + pos=strmov(pos, trx_sys_mysql_master_log_name); + *pos++='\n'; + pos=longlong2str(trx_sys_mysql_master_log_pos, pos, 10); + *pos='\n'; + + if (my_b_write(&info_file, (uchar*) buff, (size_t) (pos-buff)+1)) + error = 1; + if (flush_io_cache(&info_file)) + error = 1; + + end_io_cache(&info_file); + if (info_fd >= 0) + my_close(info_fd, MYF(0)); +skip_overwrite: + if (error) { + fprintf(stderr, + "InnoDB: ERROR: An error occurred while overwriting relay-log.info.\n"); + } else { + fprintf(stderr, + "InnoDB: The file relay-log.info was successfully overwritten.\n"); + } + } else { + fprintf(stderr, + "InnoDB: InnoDB and relay-log.info are synchronized. InnoDB will not overwrite it.\n"); + } + } +#endif /* MYSQL_SERVER */ +#endif /* HAVE_REPLICATION */ + innobase_old_blocks_pct = buf_LRU_old_ratio_update( innobase_old_blocks_pct, TRUE); @@ -2693,6 +2866,25 @@ trx_t* trx) /*!< in: transaction handle */ { if (trx_is_started(trx)) { +#ifdef HAVE_REPLICATION +#ifdef MYSQL_SERVER + THD *thd=current_thd; + + if (thd && thd->slave_thread) { + /* Update the replication position info inside InnoDB */ + trx->mysql_master_log_file_name + = active_mi->rli.group_master_log_name; + trx->mysql_master_log_pos + = ((ib_int64_t)active_mi->rli.group_master_log_pos + + ((ib_int64_t)active_mi->rli.future_event_relay_log_pos - + (ib_int64_t)active_mi->rli.group_relay_log_pos)); + trx->mysql_relay_log_file_name + = active_mi->rli.group_relay_log_name; + trx->mysql_relay_log_pos + = (ib_int64_t)active_mi->rli.future_event_relay_log_pos; + } +#endif /* MYSQL_SERVER */ +#endif /* HAVE_REPLICATION */ trx_commit_for_mysql(trx); } @@ -11130,6 +11322,12 @@ "The common part for InnoDB table spaces.", NULL, NULL, NULL); +static MYSQL_SYSVAR_BOOL(recovery_update_relay_log, innobase_overwrite_relay_log_info, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "During InnoDB crash recovery on slave overwrite relay-log.info " + "to align master log file position if information in InnoDB and relay-log.info is different.", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite, PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, "Enable InnoDB doublewrite buffer (enabled by default). " @@ -11647,6 +11845,7 @@ MYSQL_SYSVAR(old_blocks_pct), MYSQL_SYSVAR(old_blocks_time), MYSQL_SYSVAR(open_files), + MYSQL_SYSVAR(recovery_update_relay_log), MYSQL_SYSVAR(rollback_on_timeout), MYSQL_SYSVAR(stats_on_metadata), MYSQL_SYSVAR(stats_sample_pages), --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -53,6 +53,9 @@ extern ib_int64_t trx_sys_mysql_master_log_pos; /* @} */ +extern char trx_sys_mysql_relay_log_name[]; +extern ib_int64_t trx_sys_mysql_relay_log_pos; + /** If this MySQL server uses binary logging, after InnoDB has been inited and if it has done a crash recovery, we store the binlog file name and position here. */ @@ -298,7 +301,8 @@ void trx_sys_update_mysql_binlog_offset( /*===============================*/ - const char* file_name,/*!< in: MySQL log file name */ + trx_sysf_t* sys_header, + const char* file_name_in,/*!< in: MySQL log file name */ ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ @@ -493,6 +497,7 @@ @see trx_sys_mysql_master_log_name @see trx_sys_mysql_bin_log_name */ #define TRX_SYS_MYSQL_LOG_NAME_LEN 512 +#define TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN 480 /* (500 - 12) is dead line. */ /** Contents of TRX_SYS_MYSQL_LOG_MAGIC_N_FLD */ #define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344 @@ -502,6 +507,7 @@ /** The offset of the MySQL replication info in the trx system header; this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ #define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000) +#define TRX_SYS_MYSQL_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 1500) /** The offset of the MySQL binlog offset info in the trx system header */ #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000) --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -580,6 +580,20 @@ ib_int64_t mysql_log_offset;/* if MySQL binlog is used, this field contains the end offset of the binlog entry */ + const char* mysql_master_log_file_name; + /* if the database server is a MySQL + replication slave, we have here the + master binlog name up to which + replication has processed; otherwise + this is a pointer to a null + character */ + ib_int64_t mysql_master_log_pos; + /* if the database server is a MySQL + replication slave, this is the + position in the log file up to which + replication has processed */ + const char* mysql_relay_log_file_name; + ib_int64_t mysql_relay_log_pos; /*------------------------------*/ ulint n_mysql_tables_in_use; /* number of Innobase tables used in the processing of the current --- a/storage/innobase/trx/trx0sys.c +++ b/storage/innobase/trx/trx0sys.c @@ -76,13 +76,16 @@ file name and position here. */ /* @{ */ /** Master binlog file name */ -UNIV_INTERN char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_LOG_NAME_LEN]; +UNIV_INTERN char trx_sys_mysql_master_log_name[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN]; /** Master binlog file position. We have successfully got the updates up to this position. -1 means that no crash recovery was needed, or there was no master log position info inside InnoDB.*/ UNIV_INTERN ib_int64_t trx_sys_mysql_master_log_pos = -1; /* @} */ +UNIV_INTERN char trx_sys_mysql_relay_log_name[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN]; +UNIV_INTERN ib_int64_t trx_sys_mysql_relay_log_pos = -1; + /** If this MySQL server uses binary logging, after InnoDB has been inited and if it has done a crash recovery, we store the binlog file name and position here. */ @@ -684,23 +687,25 @@ void trx_sys_update_mysql_binlog_offset( /*===============================*/ - const char* file_name,/*!< in: MySQL log file name */ + trx_sysf_t* sys_header, + const char* file_name_in,/*!< in: MySQL log file name */ ib_int64_t offset, /*!< in: position in that log file */ ulint field, /*!< in: offset of the MySQL log info field in the trx sys header */ mtr_t* mtr) /*!< in: mtr */ { - trx_sysf_t* sys_header; + const char* file_name; - if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) { + if (ut_strlen(file_name_in) >= TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN) { /* We cannot fit the name to the 512 bytes we have reserved */ + /* -> To store relay log file information, file_name must fit to the 480 bytes */ - return; + file_name = ""; + } else { + file_name = file_name_in; } - sys_header = trx_sysf_get(mtr); - if (mach_read_from_4(sys_header + field + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) != TRX_SYS_MYSQL_LOG_MAGIC_N) { @@ -822,13 +827,26 @@ + TRX_SYS_MYSQL_LOG_OFFSET_LOW), sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME); + + fprintf(stderr, + "InnoDB: and relay log file\n" + "InnoDB: position %lu %lu, file name %s\n", + (ulong) mach_read_from_4(sys_header + + TRX_SYS_MYSQL_RELAY_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), + (ulong) mach_read_from_4(sys_header + + TRX_SYS_MYSQL_RELAY_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_LOW), + sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO + + TRX_SYS_MYSQL_LOG_NAME); + /* Copy the master log position info to global variables we can use in ha_innobase.cc to initialize glob_mi to right values */ ut_memcpy(trx_sys_mysql_master_log_name, sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME, - TRX_SYS_MYSQL_LOG_NAME_LEN); + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); trx_sys_mysql_master_log_pos = (((ib_int64_t) mach_read_from_4( @@ -837,6 +855,19 @@ + ((ib_int64_t) mach_read_from_4( sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO + TRX_SYS_MYSQL_LOG_OFFSET_LOW)); + + ut_memcpy(trx_sys_mysql_relay_log_name, + sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO + + TRX_SYS_MYSQL_LOG_NAME, + TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); + + trx_sys_mysql_relay_log_pos + = (((ib_int64_t) mach_read_from_4( + sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32) + + ((ib_int64_t) mach_read_from_4( + sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO + + TRX_SYS_MYSQL_LOG_OFFSET_LOW)); mtr_commit(&mtr); } --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -138,6 +138,10 @@ trx->mysql_log_file_name = NULL; trx->mysql_log_offset = 0; + trx->mysql_master_log_file_name = ""; + trx->mysql_master_log_pos = 0; + trx->mysql_relay_log_file_name = ""; + trx->mysql_relay_log_pos = 0; mutex_create(trx_undo_mutex_key, &trx->undo_mutex, SYNC_TRX_UNDO); @@ -820,6 +824,7 @@ { mtr_t mtr; trx_rseg_t* rseg; + trx_sysf_t* sys_header = NULL; ut_ad(!mutex_own(&kernel_mutex)); @@ -873,8 +878,12 @@ if (trx->mysql_log_file_name && trx->mysql_log_file_name[0] != '\0') { + if (!sys_header) { + sys_header = trx_sysf_get(&mtr); + } trx_sys_update_mysql_binlog_offset( + sys_header, trx->mysql_log_file_name, trx->mysql_log_offset, TRX_SYS_MYSQL_LOG_INFO, &mtr); @@ -882,6 +891,27 @@ trx->mysql_log_file_name = NULL; } + if (trx->mysql_master_log_file_name[0] != '\0') { + /* This database server is a MySQL replication slave */ + if (!sys_header) { + sys_header = trx_sysf_get(&mtr); + } + + trx_sys_update_mysql_binlog_offset( + sys_header, + trx->mysql_relay_log_file_name, + trx->mysql_relay_log_pos, + TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr); + + trx_sys_update_mysql_binlog_offset( + sys_header, + trx->mysql_master_log_file_name, + trx->mysql_master_log_pos, + TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr); + + trx->mysql_master_log_file_name = ""; + } + /* The following call commits the mini-transaction, making the whole transaction committed in the file-based world, at this log sequence number. The transaction becomes 'durable' when