Index: sql/sql_class.h =================================================================== --- sql/sql_class.h (revision 7136) +++ sql/sql_class.h (working copy) @@ -3734,6 +3734,7 @@ gtids, owned_gtid.sidno==-1. */ Gtid owned_gtid; + bool gtid_precommit; /** If this thread owns a set of GTIDs (i.e., GTID_NEXT_LIST != NULL), then this member variable contains the subset of those GTIDs that Index: sql/rpl_gtid.h =================================================================== --- sql/rpl_gtid.h (revision 7136) +++ sql/rpl_gtid.h (working copy) @@ -2145,6 +2145,12 @@ @return RETURN_STATUS_OK or RETURN_STATUS_REPORTED_ERROR. */ enum_return_status acquire_ownership(THD *thd, const Gtid >id); + + /* Remove gtid from logged_gtid set while failed to flush binlog + from cache to file. */ + enum_return_status remove_gtid_on_failure(THD *thd); + /* Add gtid into logged_gtid set. */ + enum_return_status mark_gtid_executed(THD *thd, const Gtid >id); /** Update the state after the given thread has flushed cache to binlog. Index: sql/rpl_gtid_state.cc =================================================================== --- sql/rpl_gtid_state.cc (revision 7136) +++ sql/rpl_gtid_state.cc (working copy) @@ -32,7 +32,54 @@ DBUG_VOID_RETURN; } +enum_return_status Gtid_state::remove_gtid_on_failure(THD *thd) +{ + DBUG_ENTER("Gtid_state::remove_gtid_on_failure"); + global_sid_lock->assert_some_lock(); + if (thd->owned_gtid.sidno > 0) + { + DBUG_ASSERT(thd->gtid_precommit); + sid_locks.lock(thd->owned_gtid.sidno); + /* Remove Gtid from logged_gtid set. */ + if (logged_gtids._remove_gtid(thd->owned_gtid) != RETURN_STATUS_OK) + { + sid_locks.unlock(thd->owned_gtid.sidno); + + RETURN_REPORTED_ERROR; + } + + sid_locks.unlock(thd->owned_gtid.sidno); + thd->owned_gtid.sidno= 0; + } + + RETURN_OK; +} + +enum_return_status Gtid_state::mark_gtid_executed(THD *thd, const Gtid >id) +{ + DBUG_ENTER("Gtid_state::mark_gtid_executed"); + // caller must take lock on the SIDNO. + global_sid_lock->assert_some_lock(); + gtid_state->assert_sidno_lock_owner(gtid.sidno); + DBUG_ASSERT(!logged_gtids.contains_gtid(gtid)); + DBUG_ASSERT(thd->owned_gtid.sidno == 0); + DBUG_ASSERT(thd->gtid_precommit); + + if (logged_gtids._add_gtid(gtid) != RETURN_STATUS_OK) + goto err; + + thd->owned_gtid= gtid; + + RETURN_OK; + +err: + thd->owned_gtid_set.clear(); + thd->owned_gtid.sidno= 0; + RETURN_REPORTED_ERROR; +} + + enum_return_status Gtid_state::acquire_ownership(THD *thd, const Gtid >id) { DBUG_ENTER("Gtid_state::acquire_ownership"); Index: sql/binlog.cc =================================================================== --- sql/binlog.cc (revision 7136) +++ sql/binlog.cc (working copy) @@ -62,6 +62,7 @@ static handlerton *binlog_hton; bool opt_binlog_order_commits= true; +bool opt_gtid_precommit= false; const char *log_bin_index= 0; const char *log_bin_basename= 0; @@ -5940,13 +5941,16 @@ goto err; } - global_sid_lock->rdlock(); - if (gtid_state->update_on_flush(thd) != RETURN_STATUS_OK) + if (!thd->gtid_precommit) { + global_sid_lock->rdlock(); + if (gtid_state->update_on_flush(thd) != RETURN_STATUS_OK) + { + global_sid_lock->unlock(); + goto err; + } global_sid_lock->unlock(); - goto err; } - global_sid_lock->unlock(); } update_thd_next_event_pos(thd); } @@ -5963,6 +5967,13 @@ } thd->commit_error= THD::CE_FLUSH_ERROR; + /* Remove gtid from logged_gtid set if necessary. */ + if (thd->gtid_precommit) + { + global_sid_lock->rdlock(); + gtid_state->remove_gtid_on_failure(thd); + global_sid_lock->unlock(); + } DBUG_RETURN(1); } @@ -6858,13 +6869,24 @@ else if (thd->transaction.flags.xid_written) dec_prep_xids(thd); - /* - Remove committed GTID from owned_gtids, it was already logged on - MYSQL_BIN_LOG::write_cache(). - */ - global_sid_lock->rdlock(); - gtid_state->update_on_commit(thd); - global_sid_lock->unlock(); + if (!thd->gtid_precommit) + { + /* + Remove committed GTID from owned_gtids, it was already logged on + MYSQL_BIN_LOG::write_cache(). + */ + global_sid_lock->rdlock(); + gtid_state->update_on_commit(thd); + global_sid_lock->unlock(); + } + else + { + /* Reset gtid_precommit. */ + thd->gtid_precommit= false; + /* Clear gtid owned by current THD. */ + thd->clear_owned_gtids(); + thd->variables.gtid_next.set_undefined(); + } DBUG_ASSERT(thd->commit_error || !thd->transaction.flags.run_hooks); DBUG_ASSERT(!thd_get_cache_mngr(thd)->dbug_any_finalized()); @@ -6951,6 +6973,8 @@ thd->transaction.flags.xid_written= false; thd->transaction.flags.commit_low= !skip_commit; thd->transaction.flags.run_hooks= !skip_commit; + thd->gtid_precommit= (opt_gtid_precommit && + (thd->variables.gtid_next.type == AUTOMATIC_GROUP)); #ifndef DBUG_OFF /* The group commit Leader may have to wait for follower whose transaction Index: sql/binlog.h =================================================================== --- sql/binlog.h (revision 7136) +++ sql/binlog.h (working copy) @@ -716,6 +716,7 @@ extern const char *log_bin_index; extern const char *log_bin_basename; extern bool opt_binlog_order_commits; +extern bool opt_gtid_precommit; /** Turns a relative log binary log path into a full path, based on the Index: sql/sys_vars.cc =================================================================== --- sql/sys_vars.cc (revision 7136) +++ sql/sys_vars.cc (working copy) @@ -4629,6 +4629,10 @@ ); #endif +static Sys_var_mybool Sys_gtid_precommit("gtid_precommit", + "add gtid into gtid_exectued before flushing binlog from cache to file.", + GLOBAL_VAR(opt_gtid_precommit), CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + #endif // HAVE_REPLICATION Index: sql/rpl_gtid_cache.cc =================================================================== --- sql/rpl_gtid_cache.cc (revision 7136) +++ sql/rpl_gtid_cache.cc (working copy) @@ -156,7 +156,11 @@ gtid_state->unlock_sidno(automatic_gtid.sidno); RETURN_REPORTED_ERROR; } - gtid_state->acquire_ownership(thd, automatic_gtid); + if (thd->gtid_precommit) + gtid_state->mark_gtid_executed(thd, automatic_gtid); + else + gtid_state->acquire_ownership(thd, automatic_gtid); + gtid_state->unlock_sidno(automatic_gtid.sidno); } }