Commit 4a82bd47 authored by guilhem@mysql.com's avatar guilhem@mysql.com

Final part of WL#1717 "innodb/binlog consistency". This is to resolve

a limitation of yesterday's implementation:
if there was an unfinished transaction (COMMIT not typed), and some MyISAM tables were
then updated, and then mysqld crashes, then at restart the server would use the too old
binlog offset known by InnoDB to cut the binlog, thus cutting the successful MyISAM
updates. We fix this by reporting the binlog offset into InnoDB even if InnoDB was not
affected at all by the update.
But the feature is still disabled until we decide if it can go into 4.1.3.
parent 7480ef38
...@@ -385,17 +385,25 @@ int ha_report_binlog_offset_and_commit(THD *thd, ...@@ -385,17 +385,25 @@ int ha_report_binlog_offset_and_commit(THD *thd,
#ifdef HAVE_INNOBASE_DB #ifdef HAVE_INNOBASE_DB
THD_TRANS *trans; THD_TRANS *trans;
trans = &thd->transaction.all; trans = &thd->transaction.all;
if (trans->innobase_tid) if (trans->innobase_tid && trans->innodb_active_trans)
{ {
/*
If we updated some InnoDB tables (innodb_active_trans is true), the
binlog coords will be reported into InnoDB during the InnoDB commit
(innobase_report_binlog_offset_and_commit). But if we updated only
non-InnoDB tables, we need an explicit call to report it.
*/
if ((error=innobase_report_binlog_offset_and_commit(thd, if ((error=innobase_report_binlog_offset_and_commit(thd,
trans->innobase_tid, trans->innobase_tid,
log_file_name, log_file_name,
end_offset))) end_offset)))
{ {
my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
error=1; error=1;
} }
} }
else if (opt_innodb_safe_binlog) // Don't report if not useful
innobase_store_binlog_offset_and_flush_log(log_file_name, end_offset);
#endif #endif
return error; return error;
} }
......
...@@ -283,7 +283,7 @@ class handler :public Sql_alloc ...@@ -283,7 +283,7 @@ class handler :public Sql_alloc
create_time(0), check_time(0), update_time(0), create_time(0), check_time(0), update_time(0),
key_used_on_scan(MAX_KEY), active_index(MAX_KEY), key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
ref_length(sizeof(my_off_t)), block_size(0), ref_length(sizeof(my_off_t)), block_size(0),
raid_type(0), ft_handler(0), implicit_emptied(0), inited(NONE) raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0)
{} {}
virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ } virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ }
int ha_open(const char *name, int mode, int test_if_locked); int ha_open(const char *name, int mode, int test_if_locked);
......
...@@ -2073,9 +2073,9 @@ bool MYSQL_LOG::cut_spurious_tail() ...@@ -2073,9 +2073,9 @@ bool MYSQL_LOG::cut_spurious_tail()
name); name);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
sql_print_error("After InnoDB crash recovery, trying to truncate " sql_print_error("After InnoDB crash recovery, checking if the binary log "
"the binary log '%s' at position %s corresponding to the " "'%s' contains rolled back transactions which must be "
"last committed transaction...", name, llstr(pos, llbuf1)); "removed from it...", name);
/* If we have a too long binlog, cut. If too short, print error */ /* If we have a too long binlog, cut. If too short, print error */
int fd= my_open(name, O_EXCL | O_APPEND | O_BINARY | O_WRONLY, MYF(MY_WME)); int fd= my_open(name, O_EXCL | O_APPEND | O_BINARY | O_WRONLY, MYF(MY_WME));
if (fd < 0) if (fd < 0)
...@@ -2091,10 +2091,17 @@ bool MYSQL_LOG::cut_spurious_tail() ...@@ -2091,10 +2091,17 @@ bool MYSQL_LOG::cut_spurious_tail()
if (pos > (actual_size= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME)))) if (pos > (actual_size= my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME))))
{ {
/*
Note that when we have MyISAM rollback this error message should be
reconsidered.
*/
sql_print_error("The binary log '%s' is shorter than its expected size " sql_print_error("The binary log '%s' is shorter than its expected size "
"(actual: %s, expected: %s) so it misses at least one " "(actual: %s, expected: %s) so it misses at least one "
"committed transaction; so it should not be used for " "committed transaction; so it should not be used for "
"replication.", name, llstr(actual_size, llbuf1), "replication or point-in-time recovery. You would need "
"to restart slaves from a fresh master's data "
"snapshot ",
name, llstr(actual_size, llbuf1),
llstr(pos, llbuf2)); llstr(pos, llbuf2));
error= 1; error= 1;
goto err; goto err;
......
...@@ -869,7 +869,7 @@ extern ulong rpl_recovery_rank, thread_cache_size; ...@@ -869,7 +869,7 @@ extern ulong rpl_recovery_rank, thread_cache_size;
extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log; extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log;
extern ulong specialflag, current_pid; extern ulong specialflag, current_pid;
extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter; extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
extern my_bool relay_log_purge; extern my_bool relay_log_purge, opt_innodb_safe_binlog;
extern uint test_flags,select_errors,ha_open_options; extern uint test_flags,select_errors,ha_open_options;
extern uint protocol_version, mysqld_port, dropping_tables; extern uint protocol_version, mysqld_port, dropping_tables;
extern uint delay_key_write_options, lower_case_table_names; extern uint delay_key_write_options, lower_case_table_names;
......
...@@ -2538,6 +2538,12 @@ server."); ...@@ -2538,6 +2538,12 @@ server.");
if (opt_innodb_safe_binlog) if (opt_innodb_safe_binlog)
{ {
if (have_innodb != SHOW_OPTION_YES)
{
sql_print_error("Error: --innodb-safe-binlog is meaningful only if "
"the InnoDB storage engine is enabled in the server.");
unireg_abort(1);
}
if (innobase_flush_log_at_trx_commit != 1) if (innobase_flush_log_at_trx_commit != 1)
{ {
sql_print_error("Warning: --innodb-safe-binlog is meaningful only if " sql_print_error("Warning: --innodb-safe-binlog is meaningful only if "
...@@ -4641,9 +4647,8 @@ replicating a LOAD DATA INFILE command.", ...@@ -4641,9 +4647,8 @@ replicating a LOAD DATA INFILE command.",
effect). effect).
*/ */
{"innodb_safe_binlog", OPT_INNODB_SAFE_BINLOG, {"innodb_safe_binlog", OPT_INNODB_SAFE_BINLOG,
"After a crash recovery by InnoDB, truncate the binary log to the last \ "After a crash recovery by InnoDB, truncate the binary log after the last "
InnoDB committed transaction. Use only if this server updates ONLY InnoDB \ "not-rolled-back statement/transaction.",
tables.",
(gptr*) &opt_innodb_safe_binlog, (gptr*) &opt_innodb_safe_binlog, (gptr*) &opt_innodb_safe_binlog, (gptr*) &opt_innodb_safe_binlog,
0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0},
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment