我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Mysql 5.7中Gtid和Last_commt/sequnce_number的生成时机是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Mysql 5.7中Gtid和Last_commt/sequnce_number的生成时机是什么

本篇内容主要讲解“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的情况下。

源码中有详细解释如下:

 
  AUTOMATIC_GROUP= 0,
  
  GTID_GROUP,
  
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();
  }

到此,相信大家对“Mysql 5.7中Gtid和Last_commt/sequnce_number的生成时机是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Mysql 5.7中Gtid和Last_commt/sequnce_number的生成时机是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

目录