diff --git a/mysql-test/r/binlog.result b/mysql-test/r/binlog.result index c49b764ed8d..4a54ccebd58 100644 --- a/mysql-test/r/binlog.result +++ b/mysql-test/r/binlog.result @@ -1,4 +1,5 @@ drop table if exists t1, t2; +reset master; create table t1 (a int) engine=bdb; create table t2 (a int) engine=innodb; begin; @@ -9,14 +10,13 @@ insert t2 values (5); commit; show binlog events from 96; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 96 Query 1 187 use `test`; drop table if exists t1, t2 -master-bin.000001 187 Query 1 285 use `test`; create table t1 (a int) engine=bdb -master-bin.000001 285 Query 1 386 use `test`; create table t2 (a int) engine=innodb -master-bin.000001 386 Query 1 455 use `test`; BEGIN -master-bin.000001 455 Query 1 84 use `test`; insert t1 values (5) -master-bin.000001 539 Query 1 154 use `test`; COMMIT -master-bin.000001 609 Query 1 678 use `test`; BEGIN -master-bin.000001 678 Query 1 84 use `test`; insert t2 values (5) -master-bin.000001 762 Xid 1 111 COMMIT /* xid=10 */ +master-bin.000001 96 Query 1 194 use `test`; create table t1 (a int) engine=bdb +master-bin.000001 194 Query 1 295 use `test`; create table t2 (a int) engine=innodb +master-bin.000001 295 Query 1 364 use `test`; BEGIN +master-bin.000001 364 Query 1 84 use `test`; insert t1 values (5) +master-bin.000001 448 Query 1 518 use `test`; COMMIT +master-bin.000001 518 Query 1 587 use `test`; BEGIN +master-bin.000001 587 Query 1 84 use `test`; insert t2 values (5) +master-bin.000001 671 Xid 1 698 COMMIT /* xid=318 */ reset master; drop table t1,t2; diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 06ca3245535..d4ff95e4e29 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -101,10 +101,9 @@ insert into t1 values(9); insert into t2 select * from t1; show binlog events from 96; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 96 Query 1 # use `test`; BEGIN -master-bin.000001 165 Query 1 # use `test`; insert into t1 values(9) -master-bin.000001 253 Xid 1 # COMMIT /* xid=59 */ -master-bin.000001 280 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 96 Query 1 # use `test`; insert into t1 values(9) +master-bin.000001 184 Xid 1 # COMMIT /* xid=59 */ +master-bin.000001 211 Query 1 # use `test`; insert into t2 select * from t1 delete from t1; delete from t2; reset master; @@ -113,21 +112,19 @@ begin; insert into t2 select * from t1; show binlog events from 96; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 96 Query 1 # use `test`; BEGIN -master-bin.000001 165 Query 1 # use `test`; insert into t1 values(10) -master-bin.000001 254 Xid 1 # COMMIT /* xid=65 */ -master-bin.000001 281 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 96 Query 1 # use `test`; insert into t1 values(10) +master-bin.000001 185 Xid 1 # COMMIT /* xid=65 */ +master-bin.000001 212 Query 1 # use `test`; insert into t2 select * from t1 insert into t1 values(11); commit; show binlog events from 96; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 96 Query 1 # use `test`; BEGIN -master-bin.000001 165 Query 1 # use `test`; insert into t1 values(10) -master-bin.000001 254 Xid 1 # COMMIT /* xid=65 */ -master-bin.000001 281 Query 1 # use `test`; insert into t2 select * from t1 -master-bin.000001 376 Query 1 # use `test`; BEGIN -master-bin.000001 445 Query 1 # use `test`; insert into t1 values(11) -master-bin.000001 534 Xid 1 # COMMIT /* xid=67 */ +master-bin.000001 96 Query 1 # use `test`; insert into t1 values(10) +master-bin.000001 185 Xid 1 # COMMIT /* xid=65 */ +master-bin.000001 212 Query 1 # use `test`; insert into t2 select * from t1 +master-bin.000001 307 Query 1 # use `test`; BEGIN +master-bin.000001 376 Query 1 # use `test`; insert into t1 values(11) +master-bin.000001 465 Xid 1 # COMMIT /* xid=67 */ alter table t2 engine=INNODB; delete from t1; delete from t2; diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index 745d4d8138e..9a8d4b6f936 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -203,7 +203,7 @@ master-bin.000001 9190 Query 1 9016 use `test`; insert into t1 values(4 + 4) master-bin.000001 9282 Query 1 9108 use `test`; insert into t1 values(3 + 4) master-bin.000001 9374 Query 1 9200 use `test`; insert into t1 values(2 + 4) master-bin.000001 9466 Query 1 9292 use `test`; insert into t1 values(1 + 4) -master-bin.000001 9558 Xid 1 9319 COMMIT /* xid=146 */ +master-bin.000001 9558 Xid 1 9585 COMMIT /* xid=146 */ master-bin.000001 9585 Rotate 1 9629 master-bin.000002;pos=4 show binlog events in 'master-bin.000002'; Log_name Pos Event_type Server_id End_log_pos Info diff --git a/mysql-test/t/binlog.test b/mysql-test/t/binlog.test index bf2d949c106..2f97a5088ba 100644 --- a/mysql-test/t/binlog.test +++ b/mysql-test/t/binlog.test @@ -7,6 +7,7 @@ --disable_warnings drop table if exists t1, t2; --enable_warnings +reset master; create table t1 (a int) engine=bdb; create table t2 (a int) engine=innodb; @@ -17,6 +18,7 @@ begin; insert t2 values (5); commit; # first COMMIT must be Query_log_event, second - Xid_log_event +--replace_result "xid=891" "xid=318" "xid=11" "xid=318" "xid=18" "xid=318" show binlog events from 96; reset master; drop table t1,t2; diff --git a/sql/handler.h b/sql/handler.h index ad9345ac75c..633252a24f1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -197,7 +197,7 @@ enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, #define HA_CREATE_USED_COMMENT (1L << 16) #define HA_CREATE_USED_PASSWORD (1L << 17) -typedef ulonglong my_xid; +typedef ulonglong my_xid; // this line is the same as in log_event.h #define MYSQL_XID_PREFIX "MySQLXid" #define MYSQL_XID_PREFIX_LEN 8 // must be a multiple of 8 #define MYSQL_XID_OFFSET (MYSQL_XID_PREFIX_LEN+sizeof(server_id)) diff --git a/sql/log.cc b/sql/log.cc index 1b5d533738a..835b00cf0a4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -80,8 +80,13 @@ static int binlog_close_connection(THD *thd) return 0; } -static inline void binlog_cleanup_trans(IO_CACHE *trans_log) +static int binlog_end_trans(THD *thd, IO_CACHE *trans_log, Log_event *end_ev) { + int error=0; + DBUG_ENTER("binlog_end_trans"); + if (end_ev) + error= mysql_bin_log.write(thd, trans_log, end_ev); + statistic_increment(binlog_cache_use, &LOCK_status); if (trans_log->disk_writes != 0) { @@ -90,6 +95,7 @@ static inline void binlog_cleanup_trans(IO_CACHE *trans_log) } reinit_io_cache(trans_log, WRITE_CACHE, (my_off_t) 0, 0, 1); // cannot fail trans_log->end_of_file= max_binlog_cache_size; + DBUG_RETURN(error); } static int binlog_prepare(THD *thd, bool all) @@ -103,21 +109,10 @@ static int binlog_prepare(THD *thd, bool all) return 0; } -static int binlog_real_commit(THD *thd, IO_CACHE *trans_log) -{ - int error; - DBUG_ENTER("binlog_real_commit"); - - /* Update the binary log as we have cached some queries */ - error= mysql_bin_log.write(thd, trans_log); - binlog_cleanup_trans(trans_log); - DBUG_RETURN(error); -} - static int binlog_commit(THD *thd, bool all) { IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot]; - DBUG_ENTER("binlog_real_commit"); + DBUG_ENTER("binlog_commit"); DBUG_ASSERT(mysql_bin_log.is_open() && (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))); @@ -127,9 +122,7 @@ static int binlog_commit(THD *thd, bool all) DBUG_RETURN(0); } Query_log_event qev(thd, "COMMIT", 6, TRUE, FALSE); - qev.write(trans_log); - - DBUG_RETURN(binlog_real_commit(thd, trans_log)); + DBUG_RETURN(binlog_end_trans(thd, trans_log, &qev)); } static int binlog_rollback(THD *thd, bool all) @@ -153,10 +146,10 @@ static int binlog_rollback(THD *thd, bool all) if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE)) { Query_log_event qev(thd, "ROLLBACK", 8, TRUE, FALSE); - qev.write(trans_log); - error= mysql_bin_log.write(thd, trans_log); + error= binlog_end_trans(thd, trans_log, &qev); } - binlog_cleanup_trans(trans_log); + else + error= binlog_end_trans(thd, trans_log, 0); DBUG_RETURN(error); } @@ -1831,11 +1824,11 @@ uint MYSQL_LOG::next_file_id() that the same updates are run on the slave. */ -bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) +bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) { bool error= 0; VOID(pthread_mutex_lock(&LOCK_log)); - DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *)"); + DBUG_ENTER("MYSQL_LOG::write(THD *, IO_CACHE *, Log_event *)"); if (likely(is_open())) // Should always be true { @@ -1844,9 +1837,8 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) /* Log "BEGIN" at the beginning of the transaction. which may contain more than 1 SQL statement. - There is no need to append "COMMIT", as it's already in the 'cache' - (in fact, Xid_log_event is there which does the commit on slaves) */ + if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { Query_log_event qinfo(thd, "BEGIN", 5, TRUE, FALSE); /* @@ -1878,10 +1870,14 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) if (my_b_write(&log_file, cache->read_pos, length)) goto err; cache->read_pos=cache->read_end; // Mark buffer used up + DBUG_EXECUTE_IF("half_binlogged_transaction", goto DBUG_skip_commit;); } while ((length=my_b_fill(cache))); + if (commit_event->write(&log_file)) + goto err; +DBUG_skip_commit: if (flush_io_cache(&log_file) || sync_binlog(&log_file)) - goto err; + goto err; DBUG_EXECUTE_IF("half_binlogged_transaction", abort();); if (cache->error) // Error on read { @@ -2995,10 +2991,8 @@ int TC_LOG_BINLOG::log(THD *thd, my_xid xid) { Xid_log_event xle(thd, xid); IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot]; - if (xle.write(trans_log)) - return 0; thread_safe_increment(prepared_xids, &LOCK_prep_xids); - return !binlog_real_commit(thd, trans_log); // invert return value + return !binlog_end_trans(thd, trans_log, &xle); // invert return value } void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) diff --git a/sql/log_event.cc b/sql/log_event.cc index 75d682fa6cd..7743e7040f7 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3140,10 +3140,9 @@ void Xid_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_eve #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Xid_log_event::exec_event(struct st_relay_log_info* rli) { - rli->inc_event_relay_log_pos(); /* For a slave Xid_log_event is COMMIT */ mysql_log.write(thd,COM_QUERY,"COMMIT /* implicit, from Xid_log_event */"); - return end_trans(thd, COMMIT); + return end_trans(thd, COMMIT) || Log_event::exec_event(rli); } #endif /* !MYSQL_CLIENT */ diff --git a/sql/log_event.h b/sql/log_event.h index f422a91f358..7a041959f92 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1077,7 +1077,7 @@ class Rand_log_event: public Log_event ****************************************************************************/ #ifdef MYSQL_CLIENT -typedef ulong my_xid; +typedef ulonglong my_xid; // this line is the same as in handler.h #endif class Xid_log_event: public Log_event diff --git a/sql/sql_class.h b/sql/sql_class.h index d57eb3d3cc6..3094b46e51a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -309,7 +309,7 @@ public: bool write(THD *thd, const char *query, uint query_length, time_t query_start=0); bool write(Log_event* event_info); // binary log write - bool write(THD *thd, IO_CACHE *cache); + bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event); /* v stands for vector diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3e2915e6e07..bcac371e0bf 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -129,13 +129,13 @@ static bool end_active_trans(THD *thd) OPTION_TABLE_LOCK)) { DBUG_PRINT("info",("options: 0x%lx", (ulong) thd->options)); - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); /* Safety if one did "drop table" on locked tables */ if (!thd->locked_tables) thd->options&= ~OPTION_TABLE_LOCK; thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (ha_commit(thd)) error=1; + thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); } DBUG_RETURN(error); } @@ -1337,9 +1337,9 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion) even if there is a problem with the OPTION_AUTO_COMMIT flag (Which of course should never happen...) */ - thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->server_status&= ~SERVER_STATUS_IN_TRANS; res= ha_commit(thd); + thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); break; case COMMIT_RELEASE: do_release= 1; /* fall through */