• ADADADADAD

    Innodb undo结构是什么[ mysql数据库 ]

    mysql数据库 时间:2024-11-26 22:12:59

    作者:文/会员上传

    简介:

    一、大体结构rollback segments(128)undo segments(1024)undo log (header insert/modify 分开的) <-> undo pageundo recordundo record作为undo segments的第一个undo pag

    以下为本文的正文内容,内容仅供参考!本站为公益性网站,复制本文以及下载DOC文档全部免费。

    一、大体结构

    rollback segments(128)

    undo segments(1024)

    undo log (header insert/modify 分开的) <-> undo page

    undo record
    undo record

    作为undo segments的第一个undo page可以存放多个事物的undo log,因为如果这个块的undo 记录没有填满3/4则会进入 rollback segment的cache list,那么下次可以继续使用,但是如果第一个块不足以装下事物的undo 记录,那么很显然需要分配新的undo page,这种情况下一个undo page就只能包含一个事物的undo记录了。
    事物每次需要分配rollback segments然后分配undo segments然后初始化好undo log header,insert和update/delete需要分配不同的undo segments,一个undo segments往往对应了一个undo log,undo log可以包含多个undo record(因为从debug来看undo log header的初始化只做了一次),对于操作的每行都会留下一个undo record作为mvcc构建历史版本的基础。
    undo生成的基本单位是undo record,每行记录都会包含一个undo record,而rollback ptr指向的是undo record的偏移量,对于每行的记录都会去判断其可见性,如果需要构建前版本则通过本指针进行构建包含:

      第1位是否是insert 第2到8位是undo segment id 第9到40位为page no 第41位到56位为 offset

      每一个undo log包含一个trx_undo_t结构体
      每一个rollback segments包含一个trx_rseg_t结构体

      二、物理结构

        undo page header 每一个undo page都包含

        /**Transactionundologpageheaderoffsets*//*@{*/#defineTRX_UNDO_PAGE_TYPE0/*!<TRX_UNDO_INSERTorTRX_UNDO_UPDATE*/#defineTRX_UNDO_PAGE_START2/*!<ByteoffsetwheretheundologrecordsfortheLATESTtransactionstartonthispage(rememberthatinanupdateundolog,thefirstpagecancontainseveralundologs)*/#defineTRX_UNDO_PAGE_FREE4/*!<Oneachpageoftheundologthisfieldcontainsthebyteoffsetofthefirstfreebyteonthepage*/#defineTRX_UNDO_PAGE_NODE6/*!<Thefilelistnodeinthechainofundologpages*/

          undo semgent header 第一个page 才会用 undo segment header信息

          #defineTRX_UNDO_STATE0/*!<TRX_UNDO_ACTIVE,...*/#ifndefUNIV_INNOCHECKSUM#defineTRX_UNDO_LAST_LOG2/*!<Offsetofthelastundologheaderonthesegmentheaderpage,0ifnone*/#defineTRX_UNDO_FSEG_HEADER4/*!<Headerforthefilesegmentwhichtheundologsegmentoccupies*/#defineTRX_UNDO_PAGE_LIST(4+FSEG_HEADER_SIZE)/*!<Basenodeforthelistofpagesintheundologsegment;definedonlyontheundologsegment'sfirstpage*/

            每一个undo log

              undo log header

              undo log record 相应的undo实际内容

              undo log record 相应的undo实际内容

              undo log header 包含

              #defineTRX_UNDO_TRX_ID0/*!<Transactionid*/#defineTRX_UNDO_TRX_NO8/*!<Transactionnumberofthetransaction;definedonlyifthelogisinahistorylist*/#defineTRX_UNDO_DEL_MARKS16/*!<Definedonlyinanupdateundolog:TRUEifthetransactionmayhavedonedeletemarkingsofrecords,andthuspurgeisnecessary*/#defineTRX_UNDO_LOG_START18/*!<Offsetofthefirstundologrecordofthislogontheheaderpage;purgemayremoveundologrecordfromthelogstart,andthereforethisisnotnecessarilythesameasthislogheaderendoffset*/#defineTRX_UNDO_XID_EXISTS20/*!<TRUEifundologheaderincludesX/OpenXAtransactionidentificationXID*/#defineTRX_UNDO_DICT_TRANS21/*!<TRUEifthetransactionisatablecreate,indexcreate,ordroptransaction:inrecoverythetransactioncannotberolledbackintheusualway:a'rollback'rathermeansdroppingthecreatedordroppedtable,ifitstillexists*/#defineTRX_UNDO_TABLE_ID22/*!<IdofthetableiftheprecedingfieldisTRUE*/#defineTRX_UNDO_NEXT_LOG30/*!<Offsetofthenextundologheaderonthispage,0ifnone*/#defineTRX_UNDO_PREV_LOG32/*!<Offsetofthepreviousundologheaderonthispage,0ifnone*/#defineTRX_UNDO_HISTORY_NODE34/*!<Ifthelogisputtothehistorylist,thefilelistnodeishere*/
              三、分配步骤和写入

                第一步为 分配rollback segments

                #0get_next_redo_rseg(max_undo_logs=128,n_tablespaces=4)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/trx/trx0trx.cc:1138#10x0000000001c0bce8intrx_assign_rseg_low(max_undo_logs=128,n_tablespaces=4,rseg_type=TRX_RSEG_TYPE_REDO)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/trx/trx0trx.cc:1314#20x0000000001c1097dintrx_set_rw_mode(trx=0x7fffd7804080)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/trx/trx0trx.cc:3352#30x0000000001a64013inlock_table(flags=0,table=0x7ffeac012ae0,mode=LOCK_IX,thr=0x7ffe7c92ef48)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/lock/lock0lock.cc:4139#40x0000000001b7950einrow_search_mvcc(buf=0x7ffe7c92e350"\377",mode=PAGE_CUR_GE,prebuilt=0x7ffe7c92e7d0,match_mode=1,direction=0)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/row/row0sel.cc:5100#50x00000000019d5443inha_innobase::index_read(this=0x7ffe7c92de10,buf=0x7ffe7c92e350"\377",key_ptr=0x7ffe7cd57590"\004",key_len=4,find_flag=HA_READ_KEY_EXACT)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/handler/ha_innodb.cc:9536#60x0000000000f9345ainhandler::index_read_map(this=0x7ffe7c92de10,buf=0x7ffe7c92e350"\377",key=0x7ffe7cd57590"\004",keypart_map=1,find_flag=HA_READ_KEY_EXACT)at/root/mysqlc/percona-server-locks-detail-5.7.22/sql/handler.h:2942#70x0000000000f83e44inhandler::ha_index_read_map(this=0x7ffe7c92de10,buf=0x7ffe7c92e350"\377",key=0x7ffe7cd57590"\004",keypart_map=1,find_flag=HA_READ_KEY_EXACT)at/root/mysqlc/percona-server-locks-detail-5.7.22/sql/handler.cc:3248

                第二步 对于主键每行更改操作都会调用trx_undo_report_row_operation 他会分配undo segments 并且会负责写入undo record

                #0trx_undo_report_row_operation(flags=0,op_type=2,thr=0x7ffe7c932828,index=0x7ffea4016590,clust_entry=0x7ffe7c932cc0,update=0x0,cmpl_info=0,rec=0x7fffb580d369"",offsets=0x7fffec0f3e00,roll_ptr=0x7fffec0f3688)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/trx/trx0rec.cc:1866#10x0000000001c5795binbtr_cur_del_mark_set_clust_rec(flags=0,block=0x7fffb4ccaae0,rec=0x7fffb580d369"",index=0x7ffea4016590,offsets=0x7fffec0f3e00,thr=0x7ffe7c932828,entry=0x7ffe7c932cc0,mtr=0x7fffec0f38f0)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/btr/btr0cur.cc:4894#20x0000000001b9f218inrow_upd_del_mark_clust_rec(flags=0,node=0x7ffe7c932550,index=0x7ffea4016590,offsets=0x7fffec0f3e00,thr=0x7ffe7c932828,referenced=0,mtr=0x7fffec0f38f0)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/row/row0upd.cc:2778#30x0000000001b9f765inrow_upd_clust_step(node=0x7ffe7c932550,thr=0x7ffe7c932828)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/row/row0upd.cc:2923#40x0000000001b9fc74inrow_upd(node=0x7ffe7c932550,thr=0x7ffe7c932828)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/row/row0upd.cc:3042#50x0000000001ba0155inrow_upd_step(thr=0x7ffe7c932828)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/row/row0upd.cc:3188#60x0000000001b3d3a0inrow_update_for_mysql_using_upd_graph(mysql_rec=0x7ffe7c9318d0"\375\001",prebuilt=0x7ffe7c931d50)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/row/row0mysql.cc:3040#70x0000000001b3d6a1inrow_update_for_mysql(mysql_rec=0x7ffe7c9318d0"\375\001",prebuilt=0x7ffe7c931d50)at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/row/row0mysql.cc:3131#80x00000000019d47c3inha_innobase::delete_row(this=0x7ffe7c931390,record=0x7ffe7c9318d0"\375\001")at/root/mysqlc/percona-server-locks-detail-5.7.22/storage/innobase/handler/ha_innodb.cc:9141

                大概流程

                switch(op_type){caseTRX_UNDO_INSERT_OP:undo=undo_ptr->insert_undo;//如果是insert则使用insert_undo类型为trx_undo_t指针if(undo==NULL){//如果已经分配了就不用分配了err=trx_undo_assign_undo(//分配undosegment同时初始化undologheadertrx,undo_ptr,TRX_UNDO_INSERT);undo=undo_ptr->insert_undo;...}break;default:ut_ad(op_type==TRX_UNDO_MODIFY_OP);//断言undo=undo_ptr->update_undo;if(undo==NULL){err=trx_undo_assign_undo(trx,undo_ptr,TRX_UNDO_UPDATE);//分配undosegment同时初始化undologheaderundo=undo_ptr->update_undo;...}...caseTRX_UNDO_INSERT_OP://注意是每行都会操作offset=trx_undo_page_report_insert(//写入insertundologrecordundo_page,trx,index,clust_entry,&mtr);break;default:ut_ad(op_type==TRX_UNDO_MODIFY_OP);//写入deleteupdateundologrecordoffset=trx_undo_page_report_modify(undo_page,trx,index,rec,offsets,update,cmpl_info,clust_entry,&mtr);}...*roll_ptr=trx_undo_build_roll_ptr(//构建rollbackptr主键中每行都有这个用于MVCC构建回滚版本op_type==TRX_UNDO_INSERT_OP,undo_ptr->rseg->id,page_no,offset);
                四、分解undo log record

                我将undo log record的写入到了错误日志,下面进行简单的分解。
                表结构如下:

                mysql>showcreatetablet1;+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+|Table|CreateTable|+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+|t1|CREATETABLE`t1`(`id1`int(11)NOTNULL,`id2`int(11)DEFAULTNULL,PRIMARYKEY(`id1`),KEY`id2`(`id2`))ENGINE=InnoDBDEFAULTCHARSET=utf8|+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+1rowinset(0.00sec)

                  insert 的undo记录,具体构造在trx_undo_page_report_insert中
                  语句

                  mysql>insertintot1values(28,28);QueryOK,1rowaffected(0.00sec)

                  输出如下:

                  trx_undo_assign_undo:assignundospace:RSEGSLOT:34,RSEGSPACEID:2PAGENO:3UNDOSLOT:0,UNDOSPACEID:2UNDOLOGHEADERPAGENO:27,UNDOLOGHEADEROFFSET:86,UNDOLOGLASTPAGE:27trx_undo_page_report_insert:undologrecordTABLE_NAME:test/t1TRX_ID:12591,UODORECORDLEN:10len10;hex011e0b0032048000001c;

                  011e0b0032048000001c就是undo record的实际记录解析如下:

                  011cpage内部本undorecord结束的位置0b类型为#defineTRX_UNDO_INSERT_REC11(0X0b)00undono,提交才会有32table_id可以查询INNODB_SYS_TABLES对照04字段长度4个字节8000001c我插入的记录主键28(0X1c)

                    update 的undo记录,具体构造在trx_undo_page_report_modify中
                    语句:

                    mysql>updatet1setid2=1000whereid1=14;QueryOK,1rowaffected(5min40.91sec)Rowsmatched:1Changed:1Warnings:0

                    输出如下:

                    trx_undo_assign_undo:assignundospace:RSEGSLOT:41,RSEGSPACEID:1PAGENO:5UNDOSLOT:1,UNDOSPACEID:1UNDOLOGHEADERPAGENO:37,UNDOLOGHEADEROFFSET:1389,UNDOLOGLASTPAGE:37trx_undo_page_report_modify:undologrecordTABLE_NAME:test/t1TRX_ID:12604,UODORECORDLEN:47len47;hex06560c0032000000003136e0260000002c052e048000000e010304800003e7000e00048000000e0304800003e70627;

                    06560c0032000000003136e0260000002c052e048000000e010304800003e7000e00048000000e030480
                    就是undo record的记录
                    大体解析如下:

                    0656:page内部本undorecord结束的位置0c:类型为#defineTRX_UNDO_UPD_EXIST_REC12(0X0c)00:undono,提交才会有32:table_id可以查询INNODB_SYS_TABLES对照00:0000003136e0:事物ID260000002c052e:undo回滚指针04:主键长度8000000e:主键值0103:位置04:被修改值的长度800003e7:值为999(0x3e7)000e:接下来字符的长度,记录原始值?00:位置04:长度8000000e:主键值03:位置04:长度800003e7:值为999(0x3e7)0627:page内部本undorecord开始的位置,0X0656-0X0627就是长度
    Innodb undo结构是什么.docx

    将本文的Word文档下载到电脑

    推荐度:

    下载
    热门标签: innodbundo