溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Mysql 5.7中Gtid和Last_commt/sequnce_number的生成時機是什么

發(fā)布時間:2021-11-12 14:41:42 來源:億速云 閱讀:110 作者:iii 欄目:MySQL數(shù)據(jù)庫

本篇內(nèi)容主要講解“Mysql 5.7中Gtid和Last_commt/sequnce_number的生成時機是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“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的時候調(diào)用MYSQL_BIN_LOG::ordered_commit執(zhí)行到flush 階段產(chǎn)生Gtid event的時候才生成,生成后會將這個Gtid 加入到Gtid_state的Owned_gtids中,實際上這個過程不僅要生成Gtid還會生成sequence_number和last_commit并且會構(gòu)造Gtid_event寫入到binlog cache最后將binlog cache寫入到binlog file,下面是binlog_cache_data::flush函數(shù)的片段:

if (!error)
      if ((error= mysql_bin_log.write_gtid(thd, this, &writer))) //生成Gtid和Last_commt/sequnce_number構(gòu)造好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則需要自動生成調(diào)用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();

其調(diào)用棧幀如下:

#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是依靠什么邏輯生成的。我們需要查看函數(shù)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);//此處對并發(fā)生成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中 并且賦予給線程 經(jīng)過本步驟 可以顯示
    else
      ret= RETURN_STATUS_REPORTED_ERROR;

    unlock_sidno(automatic_gtid.sidno);//分配完成其他線程可以分配
  }
  else //如果是OFF_PERMISSIVE或者OFF狀態(tài)如何處理 這里不做討論了
  {
    // 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指針指向 這個鏈表指針開頭,如果在進行下次循環(huán)會獲得NULL
    rpl_gno next_interval_start= iv != NULL ? iv->start : MAX_GNO; //正常情況下不會為NULL因此 next_interval_start 等于第一個interval的start,當然如果初始化會為NULL,
                                                                   //如果Interval->next =NULL 則標示沒有區(qū)間了。
    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已經(jīng)被其他線程占用則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 則指向了本區(qū)間最大的值+1
    ivit.next();
  }

到此,相信大家對“Mysql 5.7中Gtid和Last_commt/sequnce_number的生成時機是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI