深入理解MySQL 5.7 GTID系列(三):GTID的生成时机

摘要: 一、GTID生成类型这里首先使用源码的解释给出三种类型: AUTOMATIC_GROUP GTID_GROUP ANONYMOUS_GROUP 其中AUTOMATIC_GROUP通常用于主库开启GTID的情况,GTID_GROUP通常用于备库和使用了GTID_NEXT的情况下。

一、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(注意这里还没有调用FSYNC真正落盘),下面是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_committedint64 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();

其调用栈帧如下:

#0Gtid_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#10x0000000001803248inGtid_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#20x0000000001845703inMYSQL_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#30x0000000001846307inbinlog_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#40x0000000001860e57inbinlog_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#50x0000000001856d46inMYSQL_BIN_LOG::flush_thread_caches (this=0x2dffc80, thd=0x7fff2c000b70) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/binlog.cc:8470#60x0000000001856f77inMYSQL_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#70x0000000001858593inMYSQL_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 GTIDif(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的sidnolock_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 gnoif(automatic_gtid.gno !=-1)    acquire_ownership(thd, automatic_gtid);//此处将这个gtid 及上面的SIDNO:gno加入到owned_gtids中 并且赋予给线程 经过本步骤 可以显示elseret= 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) {constGtid_set::Interval *iv= ivit.get();//定义Interval指针指向 这个链表指针开头,如果在进行下次循环会获得NULLrpl_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 则指向了本区间最大的值+1ivit.next(); }

五、本节小结

学习完本节至少能够学习到:

1、GTID在主库什么时候时候生成。

2、LAST_COMMIT/SEQUENCE_NUMBER什么时候生成。

3、GTID的生成逻辑是怎么样的。

原文发布时间为:2018-01-13

本文作者:高鹏(重庆八怪)

本文来自云栖社区合作伙伴“老叶茶馆”,了解相关信息可以关注“老叶茶馆”微信公众号

如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:yqgroup@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容

原文链接

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 一、Gtid生成类型 这里首先使用源码的解释给出三种类型: AUTOMATIC_GROUP GTID_GROUP ...
    重庆八怪阅读 2,374评论 0 1
  • 袅袅炊烟笑嘻嘻 抚摸夕阳染红的天边 轻轻地 轻轻地 生怕触动敏感的经儿 达达的马蹄声声 窜入朴实动人的主妇心 欢快...
    抱一阅读 237评论 3 2
  • done 命令行下的mysql操作 导入sql脚本 todo 数据库开发作业练习 参考 Windows下使用DOS...
    周偉誠阅读 364评论 0 0
  • 让奔跑成为一种习惯, 不求减肥,不求速度, 遇到障碍我就跨过去,碰到小花我也开心。 没有踌躇,没有悲伤, 我在向着...
    麻花花阅读 302评论 0 0