Bug #74279 GTIDs not written to binlog should be included in gtid_purged
Submitted: 8 Oct 2014 15:56 Modified: 1 Apr 2015 11:48
Reporter: Sven Sandberg Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Replication Severity:S2 (Serious)
Version:5.7 OS:Any
Assigned to: CPU Architecture:Any

[8 Oct 2014 15:56] Sven Sandberg
Description:
In 5.7, GTIDs can be enabled even if log-bin is not enabled or log-slave-updates is not enabled. In this case, when a transactions with a GTID is committed, the GTID is added to the table mysql.gtid_executed.

Since 5.6, @@GLOBAL.GTID_PURGED contains the set of GTIDs which are included in @@GLOBAL.GTID_EXECUTED but not in the binary log.

However, when a transaction is committed and the binary log is off, the GTID is not included in @@GLOBAL.GTID_PURGED.

The GTID is added to @@GLOBAL.GTID_PURGED the next time the server restarts, since the procedure to read GTIDs from the binary log on server start is correct. But the GTID should be added to @@GLOBAL.GTID_PURGED already when the transaction is committed.

How to repeat:
--source include/have_gtid.inc
--source include/master-slave.inc

CREATE TABLE t1 (a INT);
--source include/sync_slave_sql_with_master.inc
SELECT @@GLOBAL.GTID_EXECUTED, @@GLOBAL.GTID_PURGED;

--let $rpl_server_number= 2
--source include/rpl_restart_server.inc
SELECT @@GLOBAL.GTID_EXECUTED, @@GLOBAL.GTID_PURGED;

Suggested fix:
=== modified file 'sql/rpl_gtid_state.cc'
--- sql/rpl_gtid_state.cc	revid:sven.sandberg@oracle.com-20140924143530-f9esd9irj02s8jrm
+++ sql/rpl_gtid_state.cc	2014-10-08 15:56:35 +0000
@@ -149,27 +149,28 @@ void Gtid_state::update_on_commit(THD *t
     global_sid_lock->rdlock();
     if (!opt_bin_log || (thd->slave_thread && !opt_log_slave_updates))
     {
-      Gtid *gtid= &thd->owned_gtid;
-#ifndef DBUG_OFF
-      lock_sidno(gtid->sidno);
-      DBUG_ASSERT(!executed_gtids.contains_gtid(*gtid));
-      unlock_sidno(gtid->sidno);
-#endif
+      Gtid &gtid= thd->owned_gtid;
       /*
         If binlog is disabled, any session adds transaction owned GTID
-        into global executed_gtids.
+        into global executed_gtids and lost_gtids.
         If binlog is enabled and log_slave_updates is disabled, slave
         SQL thread or slave worker thread adds transaction owned GTID
         into global executed_gtids and gtids_only_in_table.
       */
-      lock_sidno(gtid->sidno);
+      lock_sidno(gtid.sidno);
+
+      DBUG_ASSERT(!executed_gtids.contains_gtid(gtid));
+
       DBUG_EXECUTE_IF(
         "rpl_gtid_update_on_commit_simulate_out_of_memory",
         DBUG_SET("+d,rpl_gtid_get_free_interval_simulate_out_of_memory"););
-      executed_gtids._add_gtid(*gtid);
+
+      executed_gtids._add_gtid(gtid);
+      lost_gtids._add_gtid(gtid);
       if (thd->slave_thread && opt_bin_log && !opt_log_slave_updates)
-        gtids_only_in_table._add_gtid(*gtid);
-      unlock_sidno(gtid->sidno);
+        gtids_only_in_table._add_gtid(gtid);
+
+      unlock_sidno(gtid.sidno);
     }
 
     update_gtids_impl(thd, true);
[1 Apr 2015 11:48] David Moss
The following was added to the 5.7.6 changelog:

When gtid_mode=ON and log-bin=OFF, committed transaction GTIDs are added to the mysql.gtid_executed table. In such a configuration, the committed transaction GTID was not being correctly added to gtid_purged until the next time the server was restarted. The fix ensures that committed transaction's GTIDs are added to gtid_purged at the time of commit.