Mysql 5.7 Gtid內部學習(三) 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->end; //iv->end 則指向了本區間最大的值+1 ivit.next(); }
五、本節小結
學習完本節至少能夠學習到:
- 1、Gtid在主庫什麼時候時候生成。
- 2、Last_commit/seqence_number什麼時候生成。
- 3、Gtid的生成邏輯是怎麼樣的。
如果有原始碼閱讀能力的同學可以按照這個框架繼續深入學習。
作者微信:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2148836/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Mysql 5.7 Gtid內部學習(五) mysql.gtid_executed表及其他變數更改時機MySql變數
- Mysql 5.7 Gtid內部學習(二) Gtid相關內部資料結構MySql資料結構
- Mysql 5.7 Gtid內部學習(一) 導讀MySql
- Mysql 5.7 Gtid內部學習(四) mysql.gtid_executed表Previous gtid Event的改變MySql
- Mysql 5.7 Gtid內部學習(六) Mysql啟動初始化Gtid模組MySql
- Mysql 5.7 Gtid內部學習(八) Gtid帶來的運維改變MySql運維
- Mysql 5.7 Gtid內部學習(十) 實際案例(二)MySql
- Mysql 5.7 Gtid內部學習(九) 實際案例(一)MySql
- Mysql 5.7 Gtid內部學習(七) 總結binlog_gtid_simple_recovery引數帶來的影響MySql
- mysql 5.7 GTID主從配置MySql
- MySQL5.7GTID淺析MySql
- MYSQL5.7-GTID概要翻譯MySql
- MySQL5.7GTID運維實戰MySql運維
- MySQL 5.7 用mysqldump搭建gtid主從MySql
- MySQL 5.7 用xtrabackup搭建gtid主從MySql
- MySQL 5.7基於GTID的主從複製MySql
- 第2節:mysql.gtid_executed表/gtid_executed變數/gtid_purged變數的更改時機MySql變數
- MySQL 5.7 基於GTID搭建主從複製MySql
- MySQL 5.7 使用GTID方式搭建複製環境MySql
- MYSQL5.7 MASTER-SLAVE 線上關閉和啟動GTIDMySqlAST
- MySQL 基礎知識梳理學習(四)—-GTIDMySql
- 深入理解MySQL5.7GTID系列(七)binlog_gtid_simple_recovery引數的影響總結MySql
- mysql replication之GTIDMySql
- MySQL GTID複製MySql
- 【MySQL】UUID與GTID以及如何根據GTID找尋filename和positionMySqlUI
- MySQL運維之binlog_gtid_simple_recovery(GTID)MySql運維
- MySQL GTID生命週期MySql
- MYSQL_GTID詳解MySql
- MySQL 5.6 建立GTID主從複製 (GTID-based Replication)MySql
- MySQL 5.6 GTID 原理以及使用MySql
- MySQL 5.7傳統複製到GTID線上切換(一主一從)MySql
- Mysql基於GTID的複製模式MySql模式
- MySQL 5.6 複製:GTID 的優點和限制(第一部分)MySql
- 基於GTID搭建主從MySQLMySql
- mysql GTID 主從複製概述MySql
- MySQl報錯之@@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_MODE = ONMySql
- mysql5.7 GTID 主從複製模式-增加新的slave1(好文章!!)MySql模式
- GTID環境下mysqldump set-gtid-purged取值MySql