共计 6421 个字符,预计需要花费 17 分钟才能阅读完成。
本篇内容主要讲解“Mysql 5.7 中 Gtid 和 Last_commt/sequnce_number 的生成时机是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“Mysql 5.7 中 Gtid 和 Last_commt/sequnce_number 的生成时机是什么”吧!
一、Gtid 生成类型
这里首先使用源码的解释给出三种类型:
AUTOMATIC_GROUP
GTID_GROUP
ANONYMOUS_GROUP
其中 AUTOMATIC_GROUP 通常用于主库开启 Gtid 的情况,GTID_GROUP 通常用于备库和使用了 GTID_NEXT 的情况下。
源码中有详细解释如下:
/**
Specifies that the GTID has not been generated yet; it will be
generated on commit. It will depend on the GTID_MODE: if
GTID_MODE =OFF_PERMISSIVE, then the transaction will be anonymous;
if GTID_MODE =ON_PERMISSIVE, then the transaction will be assigned
a new GTID.
This is the default value: thd- variables.gtid_next has this state
when GTID_NEXT= AUTOMATIC .
It is important that AUTOMATIC_GROUP==0 so that the default value
for thd- variables- gtid_next.type is AUTOMATIC_GROUP.
*/
AUTOMATIC_GROUP= 0,
/**
Specifies that the transaction has been assigned a GTID (UUID:NUMBER).
thd- variables.gtid_next has this state when GTID_NEXT= UUID:NUMBER .
This is the state of GTID-transactions replicated to the slave.
*/
GTID_GROUP,
/**
Specifies that the transaction is anonymous, i.e., it does not
have a GTID and will never be assigned one.
thd- variables.gtid_next has this state when GTID_NEXT= ANONYMOUS .
This is the state of any transaction generated on a pre-GTID
server, or on a server with GTID_MODE==OFF.
*/
ANONYMOUS_GROUP
二、Gtid 和 Last_commt/sequnce_number 的生成时机
Gtid 其实是在 commit 的时候调用 MYSQL_BIN_LOG::ordered_commit 执行到 flush 阶段产生 Gtid event 的时候才生成,生成后会将这个 Gtid 加入到 Gtid_state 的 Owned_gtids 中,实际上这个过程不仅要生成 Gtid 还会生成 sequence_number 和 last_commit 并且会构造 Gtid_event 写入到 binlog cache 最后将 binlog cache 写入到 binlog file,下面是 binlog_cache_data::flush 函数的片段:
if (!error)
if ((error= mysql_bin_log.write_gtid(thd, this, writer))) // 生成 Gtid 和 Last_commt/sequnce_number 构造好 Gtid event 并且写入到到 binlog cache 中
thd- commit_error= THD::CE_FLUSH_ERROR;
if (!error)
error= mysql_bin_log.write_cache(thd, this, writer); // 将 binlog cache 写入到文件
下面是 mysql_bin_log.write_gtid 中生成 Gtid 和 Last_commt/sequnce_number 的代码片段:
if (thd- variables.gtid_next.type == AUTOMATIC_GROUP)// 如果过是非指定的 Gtid 则需要自动生成调用 generate_automatic_gtid 生成
{
if (gtid_state- generate_automatic_gtid(thd,
thd- get_transaction()- get_rpl_transaction_ctx()- get_sidno(),
thd- get_transaction()- get_rpl_transaction_ctx()- get_gno())
!= RETURN_STATUS_OK)
DBUG_RETURN(true);
}
.....
// 下面生成 sequence_number 和 last_committed
int64 relative_sequence_number= trn_ctx- sequence_number - clock.get_offset();
int64 relative_last_committed=
trn_ctx- last_committed = clock.get_offset() ?
SEQ_UNINIT : trn_ctx- last_committed - clock.get_offset();
其调用栈帧如下:
#0 Gtid_state::get_automatic_gno (this=0x2ff8bb0, sidno=1) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:564
#1 0x0000000001803248 in Gtid_state::generate_automatic_gtid (this=0x2ff8bb0, thd=0x7fff2c000b70, specified_sidno=0, specified_gno=0)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/rpl_gtid_state.cc:628
#2 0x0000000001845703 in MYSQL_BIN_LOG::write_gtid (this=0x2dffc80, thd=0x7fff2c000b70, cache_data=0x7fff2c021178, writer=0x7ffff0358810)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:1167
#3 0x0000000001846307 in binlog_cache_data::flush (this=0x7fff2c021178, thd=0x7fff2c000b70, bytes_written=0x7ffff03588b8, wrote_xid=0x7ffff0358917)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:1454
#4 0x0000000001860e57 in binlog_cache_mngr::flush (this=0x7fff2c020ff0, thd=0x7fff2c000b70, bytes_written=0x7ffff0358918, wrote_xid=0x7ffff0358917)
at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:768
#5 0x0000000001856d46 in MYSQL_BIN_LOG::flush_thread_caches (this=0x2dffc80, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8470
#6 0x0000000001856f77 in MYSQL_BIN_LOG::process_flush_stage_queue (this=0x2dffc80, total_bytes_var=0x7ffff0358a88, rotate_var=0x7ffff0358a87,
out_queue_var=0x7ffff0358a78) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8532
#7 0x0000000001858593 in MYSQL_BIN_LOG::ordered_commit (this=0x2dffc80, thd=0x7fff2c000b70, all=false, skip_commit=false)
接下来我们就需要具体研究下一个 Gtid 是依靠什么逻辑生成的。我们需要查看函数 Gtid_state::generate_automatic_gtid 和 Gtid_state::get_automatic_gno 逻辑,他们用于生成一个 Gtid。
三、Gtid_state::generate_automatic_gtid 逻辑
// If GTID_MODE = ON_PERMISSIVE or ON, generate a new GTID
if (get_gtid_mode(GTID_MODE_LOCK_SID) = GTID_MODE_ON_PERMISSIVE)// 如果 GTID_MODE 是 ON_PERMISSIVE 和 ON 则生成 GTID
{ Gtid automatic_gtid= { specified_sidno, specified_gno };
if (automatic_gtid.sidno == 0)// 如果是备库则 sidno 0,如果是主库 sidno==0,因为主库的 Gtid 这个时候才生成,但是备库则是使用 GTID_GROUP 指定生成
automatic_gtid.sidno= get_server_sidno();// 此处返回本 server 的 sidno
lock_sidno(automatic_gtid.sidno);// 此处对并发生成 GNO 的多个线程进行控制
if (automatic_gtid.gno == 0)// 如果是备库则 gno 0,如果是主库 gno == 0,因为主库的 Gtid 这个时候才生成,但是备库则是使用 GTID_GROUP 指定生成
automatic_gtid.gno= get_automatic_gno(automatic_gtid.sidno);// 此处返回最后指定 sidno 的 end gno
if (automatic_gtid.gno != -1)
acquire_ownership(thd, automatic_gtid);// 此处将这个 gtid 及上面的 SIDNO:gno 加入到 owned_gtids 中 并且赋予给线程 经过本步骤 可以显示
else
ret= RETURN_STATUS_REPORTED_ERROR;
unlock_sidno(automatic_gtid.sidno);// 分配完成其他线程可以分配
}
else // 如果是 OFF_PERMISSIVE 或者 OFF 状态如何处理 这里不做讨论了
{
// If GTID_MODE = OFF or OFF_PERMISSIVE, just mark this thread as
// using an anonymous transaction.
thd- owned_gtid.sidno= THD::OWNED_SIDNO_ANONYMOUS;
thd- owned_gtid.gno= 0;
acquire_anonymous_ownership();
thd- owned_gtid.dbug_print(NULL,
set owned_gtid (anonymous) in generate_automatic_gtid
}
sid_lock- unlock();// 释放读写锁
接下来看看 gno 的生成逻辑 Gtid_state::get_automatic_gno。
四、Gtid_state::generate_automatic_gtid 逻辑
while (true)
{ const Gtid_set::Interval *iv= ivit.get(); // 定义 Interval 指针指向 这个链表指针开头, 如果在进行下次循环会获得 NULL
rpl_gno next_interval_start= iv != NULL ? iv- start : MAX_GNO; // 正常情况下不会为 NULL 因此 next_interval_start 等于第一个 interval 的 start,当然如果初始化会为 NULL, // 如果 Interval- next =NULL 则标示没有区间了。 while (next_candidate.gno next_interval_start
DBUG_EVALUATE_IF(simulate_gno_exhausted , false, true)) // 这里 next_candidate.gno 正常不会小于 next_interval_start ,如果 Interval- next =NULL 或者初始化
//next_interval_start 会被制为 MAX_GNO 那么条件成立
//DBUG_RETURN(next_candidate.gno); 返回了这个 gno 则 GTID 生成
{ if (owned_gtids.get_owner(next_candidate) == 0) // 如果本 GTID 已经被其他线程占用则 next_candidate.gno++; 返回这个 gno。 DBUG_RETURN(next_candidate.gno);
next_candidate.gno++;
}
if (iv == NULL ||
DBUG_EVALUATE_IF(simulate_gno_exhausted , true, false))
{ my_error(ER_GNO_EXHAUSTED, MYF(0));
DBUG_RETURN(-1);
}
next_candidate.gno= iv- //iv- end 则指向了本区间最大的值 +1
ivit.next();
}
到此,相信大家对“Mysql 5.7 中 Gtid 和 Last_commt/sequnce_number 的生成时机是什么”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!