- mysql.
gtid_executed:GTID的持久化介质,GTID模块初始化时,会读取这个表,作为gtid_executed 变量的初始值
gtid_executed 变量:表示数据库执行了哪些GTID
,This is the same as the value of theExecuted_Gtid_Set
column in the output ofSHOW MASTER STATUS
andSHOW SLAVE STATUS
.- gtid_purged变量:包含了mysql执行过的且没有在binlog文件存在的事务。
gtid_purged是
gtid_executed的一个子集。
The set of GTIDs in the
gtid_purged
system variable contains the GTIDs of all the transactions that have been committed on the server, but do not exist in any binary log file on the server.gtid_purged
is a subset ofgtid_executed
.
gtid_purged写入的策略:
- GTIDs of replicated transactions that were committed with binary logging disabled on the replica. 从库禁用binlog情况下,从库执行的已提交的事务时的GTID
-
GTIDs of transactions that were written to a binary log file that has now been purged.在binlog文件在被清理时,已经写入binlog文件的GTID
- GTIDs that were added explicitly to the set by the statement
SET @@GLOBAL.gtid_purged
. 手工设置了参数
例如:An example use case for this action is when you are restoring a backup of one or more databases on a server, but you do not have the relevant binary logs containing the transactions on the server,In MySQL 5.7, you can only change the value of
gtid_purged
whengtid_executed
(and thereforegtid_purged
) is empty
我们在通过备份搭建从库时,我们需要手工设置set gtid_purged
=‘’,前提是清空gtid_executed
。
变量gtid_executed
and gtid_purged在mysql启动的时候被初始化。
前提是binlog打开,gtid打开的情况下讨论。
一,主库修改时机
1,mysql.gtid_executed什么时间被修改?
mysql重启或者binlog 切换时,它不是实时更新的。
相关函数(文件rpl_gtid.h):Gtid_state::save_gtids_of_last_binlog_into_table()
int save_gtids_of_last_binlog_into_table(bool on_rotation);
/**
Fetch gtids from gtid_executed table and store them into
gtid_executed set.
@retval
0 OK
@retval
1 The table was not found.
@retval
-1 Error
*/
2,变量gtid_executed什么时间被修改?
在order commit的flush阶段生成GTID,在commit阶段才记入gtid_executed变量,是实时更新的。
源码:
void Gtid_state::update_gtids_impl_own_gtid_set(THD *thd, bool is_commit)
{
#ifdef HAVE_GTID_NEXT_LIST
rpl_sidno prev_sidno= 0;
Gtid_set::Gtid_iterator git(&thd->owned_gtid_set);
Gtid g= git.get();
while (g.sidno != 0)
{
if (g.sidno != prev_sidno)
sid_locks.lock(g.sidno);
owned_gtids.remove_gtid(g);
git.next();
g= git.get();
if (is_commit)
executed_gtids._add_gtid(g);
}
if (is_commit && !thd->owned_gtid_set.is_empty())
thd->rpl_thd_ctx.session_gtids_ctx().
notify_after_gtid_executed_update(thd);
thd->variables.gtid_next.set_undefined();
thd->owned_gtid.dbug_print(NULL,
"set owned_gtid (clear; old was gtid_set) "
"in update_gtids_impl");
thd->clear_owned_gtids();
#else
DBUG_ASSERT(0);
#endif
}
3,gtid_purged什么时间被修改的?
在清理binlog的时候进行修改,如purge或者过期时间到了,需要将丢失的GTID SETS 计入这个变量中,不是实时更新的。
对应源码函数(binlog.cc文件):MYSQL_BIN_LOGS::purge_logs
int MYSQL_BIN_LOG::purge_logs(const char *to_log,
bool included,
bool need_lock_index,
bool need_update_threads,
ulonglong *decrease_log_space,
bool auto_purge)
{...
// Update gtid_state->lost_gtids
if (!is_relay_log)
{
global_sid_lock->wrlock();
error= init_gtid_sets(NULL,
const_cast<Gtid_set *>(gtid_state->get_lost_gtids()),
opt_master_verify_checksum,
false/*false=don't need lock*/,
NULL/*trx_parser*/, NULL/*gtid_partial_trx*/);
global_sid_lock->unlock();
if (error)
goto err;
}
二,从库修改时机
前提是binlog,log_state_update开启
此时mysql.gtid_executed和 gtid_purge不需要实时更新,可以通过binlog文件进行保存,修改时机也是主库一样的
三,其他情况下
1,reset master
此时mysql.gtid_executed,变量gtid_executed和gtid_purge都会被清空,对应函数如下:
reset master 源码对应如下:
bool reset_master(THD* thd)
{
bool ret= false;
/*
RESET MASTER command should ignore 'read-only' and 'super_read_only'
options so that it can update 'mysql.gtid_executed' replication repository
table.
Please note that skip_readonly_check flag should be set even when binary log
is not enabled, as RESET MASTER command will clear 'gtid_executed' table.
*/
...
{
global_sid_lock->wrlock();
ret= (gtid_state->clear(thd) != 0); //执行gtid清理操作
global_sid_lock->unlock();
}
清理函数
int Gtid_state::clear(THD *thd)
{
DBUG_ENTER("Gtid_state::clear()");
int ret= 0;
// the wrlock implies that no other thread can hold any of the mutexes
sid_lock->assert_some_wrlock();
lost_gtids.clear(); //清理gtid_purged
executed_gtids.clear(); //清理gtid_executed
gtids_only_in_table.clear(); //清理mysql.gtid_executed
previous_gtids_logged.clear();
/* Reset gtid_executed table. */
if ((ret= gtid_table_persistor->reset(thd)) == 1)
{
/*
Gtid table is not ready to be used, so failed to
open it. Ignore the error.
*/
thd->clear_error();
ret= 0;
}
next_free_gno= 1;
DBUG_RETURN(ret);
}