Description:
WAIT_FOR_EXECUTED_GTID_SET waits until a given set of GTIDs is included in @@GLOBAL.GTID_EXECUTED.
This works for transactions committed either from a normal client session or from a slave thread.
However, if transactions are added to GTID_EXECUTED through SET GTID_PURGED, then WAIT_FOR_EXECUTED_GTID_SET will not notice it.
The problem is a missing signal from the SET GTID_PURGED. So WAIT_FOR_EXECUTED_GTID_SET will wake up and notice the change once a transaction is committed from a client or from a slave thread.
This prevents an interesting use case for WAIT_FOR_EXECUTED_GTID_SET: If this was working, DBA could use WAIT_FOR_EXECUTED_GTID_SET to wait until a restore (e.g. from mysqldump) that ends with SET GTID_PURGED has completed.
How to repeat:
--source include/have_gtid.inc
--let $rpl_gtid_utils= 1
--source include/master-slave.inc
--send
eval
SELECT WAIT_FOR_EXECUTED_GTID_SET('$uuida:1-1000', 5);
--connection default
eval
SET GLOBAL GTID_PURGED = '$uuida:1-1000';
--connection master
# Note that this returns 1, meaning that
# WAIT_FOR_EXECUTED_GTID_SET timed out rather
# than completed successfully as it should.
reap;
exit;
Suggested fix:
(Untested)
=== modified file 'sql/rpl_gtid_state.cc'
--- sql/rpl_gtid_state.cc revid:balasubramanian.kandasamy@oracle.com-20140908112446-kv7pd0tui348ykbp
+++ sql/rpl_gtid_state.cc 2014-09-08 14:14:04 +0000
@@ -403,6 +403,7 @@ void Gtid_state::unlock_sidnos(const Gti
if (gs->contains_sidno(sidno))
unlock_sidno(sidno);
}
+#endif
void Gtid_state::broadcast_sidnos(const Gtid_set *gs)
@@ -413,7 +414,6 @@ void Gtid_state::broadcast_sidnos(const
if (gs->contains_sidno(sidno))
broadcast_sidno(sidno);
}
-#endif
enum_return_status Gtid_state::ensure_sidno()
=== modified file 'sql/sys_vars.h'
--- sql/sys_vars.h revid:balasubramanian.kandasamy@oracle.com-20140908112446-kv7pd0tui348ykbp
+++ sql/sys_vars.h 2014-09-08 14:13:53 +0000
@@ -2212,6 +2212,7 @@ public:
char *previous_gtid_executed= gtid_state->get_executed_gtids()->to_string();
char *previous_gtid_lost= gtid_state->get_lost_gtids()->to_string();
enum_return_status ret= gtid_state->add_lost_gtids(var->save_result.string_value.str);
+ global_sid_lock->broadcast_sidnos(gtid_state->get_lost_gtids());
char *current_gtid_executed= gtid_state->get_executed_gtids()->to_string();
char *current_gtid_lost= gtid_state->get_lost_gtids()->to_string();
global_sid_lock->unlock();