加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_丽江站长网 (http://www.0888zz.com/)- 科技、建站、数据工具、云上网络、机器学习!
当前位置: 首页 > 服务器 > 安全 > 正文

《MySQL运维内参》节选

发布时间:2021-01-13 02:02:29 所属栏目:安全 来源:网络整理
导读:副标题#e# 《《MySQL运维内参》节

回滚段的管理,也是有一个入口位置用来存储回滚段的管理信息的,在InnoDB中,是用第6个页面(5号)来管理的,这个页面是专门用来存储事务相关的信息的,我们先看看其页面格式:

/** Transaction system header */

/*————————————————————- @{ */

#define TRX_SYS_TRX_ID_STORE? ? 0 ? /*!< the maximum trx id or trx

? ? ? ? ? ? ? ? ? ? number modulo

? ? ? ? ? ? ? ? ? ? TRX_SYS_TRX_ID_UPDATE_MARGIN

? ? ? ? ? ? ? ? ? ? written to a file page by any

? ? ? ? ? ? ? ? ? ? transaction; the assignment of

? ? ? ? ? ? ? ? ? ? transaction ids continues from

? ? ? ? ? ? ? ? ? ? this number rounded up by

? ? ? ? ? ? ? ? ? ? TRX_SYS_TRX_ID_UPDATE_MARGIN

? ? ? ? ? ? ? ? ? ? plus

? ? ? ? ? ? ? ? ? ? TRX_SYS_TRX_ID_UPDATE_MARGIN

? ? ? ? ? ? ? ? ? ? when the database is

? ? ? ? ? ? ? ? ? ? started */

#define TRX_SYS_FSEG_HEADER 8 ? /*!< segment header for the

? ? ? ? ? ? ? ? ? ? tablespace segment the trx

? ? ? ? ? ? ? ? ? ? system is created into */

#define TRX_SYS_RSEGS ? ? ? (8 + FSEG_HEADER_SIZE)

? ? ? ? ? ? ? ? ? ? /*!< the start of the array of

? ? ? ? ? ? ? ? ? ? rollback segment specification

? ? ? ? ? ? ? ? ? ? slots */

上面定义的是第6号页面中存储的信息及其对应的位置,每一项的详细意义如下:

  1. TRX_SYS_TRX_ID_STORE:用来存储事务号,在每次新启动一个事务时,都会去检查当前最大事务号是不是达到了TRX_SYS_TRX_ID_WRITE_MARGIN(256)的倍数,如果达到了,就会将最大的事务号写入到这个位置,在下次启动时,将这个值取出来,再加上一个步长(TRX_SYS_TRX_ID_WRITE_MARGIN),来保证事务号的唯一性,其实就是一个经典的取号器的实现原理.
  2. TRX_SYS_FSEG_HEADER:用来存储事务段信息.
  3. TRX_SYS_RSEGS:这是一个数组,InnoDB有128个回滚段,那这个数组的长度就是128,每一个元素占用8个字节,对应的一个回滚段存储的内容包括回滚段首页面的表空间ID号及页面号.

而针对每一个回滚段,即上面数组中的一个元素,也有其自己的存储格式,代码中的宏定义如下:

#define TRX_RSEG_MAX_SIZE ? 0 ? /* Maximum allowed size for rollback

? ? ? ? ? ? ? ? ? ? segment in pages */

#define TRX_RSEG_HISTORY_SIZE ? 4 ? /* Number of file pages occupied

? ? ? ? ? ? ? ? ? ? by the logs in the history list */

#define TRX_RSEG_HISTORY? ? 8 ? /* The update undo logs for committed

? ? ? ? ? ? ? ? ? ? transactions */

#define TRX_RSEG_FSEG_HEADER? ? (8 + FLST_BASE_NODE_SIZE)

? ? ? ? ? ? ? ? ? ? /* Header for the file segment where

? ? ? ? ? ? ? ? ? ? this page is placed */

#define TRX_RSEG_UNDO_SLOTS (8 + FLST_BASE_NODE_SIZE + FSEG_HEADER_SIZE)

? ? ? ? ? ? ? ? ? ? /* Undo log segment slots */

上面这些信息的存储,是从页面偏移38的位置开始的,在这个位置之前,存储的是文件管理的信息(讲参考索引管理相关章节),从38开始,存储了上面5个信息,它们的意义分别如下:

  1. TRX_RSEG_MAX_SIZE:回滚段管理页面的总数量,即所有undo段页面之和,一般为ULINT_MAX,即无上限.
  2. TRX_RSEG_HISTORY_SIZE:这个表来表示当前InnoDB中,在History List中有多少页面,即需要做PURGE的回滚段页面个数.
  3. TRX_RSEG_HISTORY:这个用来存储History List的链表首地址,事务提交之后,其对应的回滚段如果还不能PURGE,那都会加入到这个链表中.
  4. TRX_RSEG_FSEG_HEADER:这个用来存储回滚段的Inode位置信息,通过这个地址,就可以找到这个段的详细信息.
  5. TRX_RSEG_UNDO_SLOTS:这个位置所存储的是一个数组,长度为1024,每一个元素是一个页面号,初始化为FIL_NULL,即空页面.

这5个信息,存储了一个回滚段的信息,最后一个位置的数组,就是用来真正存储回滚段的位置,我们后面会讲到这128*1024个槽是如何使用的.

根据上面的讲述,我们现在已经知道所有回滚段的存储架构了,如下图所示:

现在就可以知道,InnoDB中支持的回滚段总共有128*1024=131072个,TRX_RSEG_UNDO_SLOTS数组的每个元素指向一个页面,这个页面对应一个段,页面号就是段首页的页面号.

在每一个事务开始的时候,都会分配一个rseg,就是从长度为128的数组中,根据最近使用的情况,找到一个临近位置的rseg,在这个事务的生命周期内,被分配的rseg就会被这个事务所使用.

在事务执行过程中,会产生两种回滚日志,一种是INSERT的UNDO记录,一种是UPDATE的UNDO记录,可能有人会问DELETE哪去了?其实是包含在UPDATE的回滚记录中的,因为InnoDB把UNDO分为两类,一类就是新增,也就是INSERT,一类就是修改,就是UPDATE,分类的依据就是事务提交后要不要做PURGE操作,因为INSERT是不需要PURGE的,只要事务提交了,那这个回滚记录就可以丢掉了,而对于更新和删除操作而言,如果事务提交了,还需要为MVCC服务,那就需要将这些日志放到History List中去,等待去做PURGE,以及MVCC的多版本查询等,所以分为两类.

所以,一个事务被分配了一个rseg之后,通常情况下,如果一个事务中既有插入,又有更新(或删除),那这个事务就会对应两个UNDO段,即在一个rseg的1024个槽中,要使用两个槽来存储这个事务的回滚段,一个是插入段,一个是更新段.

在事务要存储回滚记录的时候,事务就要从1024个槽中,根据相应的更新类型(插入或者更新)找到空闲的槽来作为自己的UNDO段.如果已经申请过相同类型的UNDO段,就直接使用,否则就需要新创建一个段,并将段首页号写入到这个rseg的长度为1024的数组的对应位置(空闲位置)中去,这样就将具体的回滚段与整个架构联系起来了.

如果在1024个槽中找不到空闲的位置,那这个事务就会被回滚掉,报出错误为:“Too many active concurrent transactions”,错误号为1637的异常.当然这种情况一般不会见到,如果能把这个用完,估计数据库已经根本动不了了.

上面讲述了整个回滚段存储架构及与事务的相关性,具体到一个事务所使用的某个回滚段的管理,就存储在了回滚段首页中,管理信息包括三部分,分别是Undo page header、Undo segment header及Undo log header.下面分别介绍:

Undo page header:

/** Transaction undo log page header offsets */

#define TRX_UNDO_PAGE_TYPE? 0 ? /*!< TRX_UNDO_INSERT or

? ? ? ? ? ? ? ? ? ? TRX_UNDO_UPDATE */

#define TRX_UNDO_PAGE_START 2 ? /*!< Byte offset where the undo log

? ? ? ? ? ? ? ? ? ? records for the LATEST transaction

? ? ? ? ? ? ? ? ? ? start on this page (remember that

? ? ? ? ? ? ? ? ? ? in an update undo log,the first page

? ? ? ? ? ? ? ? ? ? can contain several undo logs) */

#define TRX_UNDO_PAGE_FREE? 4 ? /*!< On each page of the undo log this

? ? ? ? ? ? ? ? ? ? field contains the byte offset of the

? ? ? ? ? ? ? ? ? ? first free byte on the page */

#define TRX_UNDO_PAGE_NODE? 6 ? /*!< The file list node in the chain

? ? ? ? ? ? ? ? ? ? of undo log pages */

  1. TRX_UNDO_PAGE_TYPE:这个我们在上面已经解释过了,就包括两个值,分别是TRX_UNDO_INSERT和TRX_UNDO_UPDATE.
  2. TRX_UNDO_PAGE_START:用来表示当前页面中,从什么位置开始存储了UNDO日志.
  3. TRX_UNDO_PAGE_FREE:与上面的START相对,这个用来表示当前页面中,UNDO日志的结束位置,也表示从这个位置开始,可以继续追加UNDO日志,直到页面存储满为止.
  4. TRX_UNDO_PAGE_NODE:一个UNDO段中所有的页面,通过一个双向链表来管理,这个位置存储的就是双向链表的指针.

Undo segment header:

/** Undo log segment header */

#define TRX_UNDO_STATE? ? ? 0 ? /*!< TRX_UNDO_ACTIVE,… */

#define TRX_UNDO_LAST_LOG ? 2 ? /*!< Offset of the last undo log header

? ? ? ? ? ? ? ? ? ? on the segment header page,0 if

? ? ? ? ? ? ? ? ? ? none */

#define TRX_UNDO_FSEG_HEADER? ? 4 ? /*!< Header for the file segment which

? ? ? ? ? ? ? ? ? ? the undo log segment occupies */

#define TRX_UNDO_PAGE_LIST? (4 + FSEG_HEADER_SIZE)

? ? ? ? ? ? ? ? ? ? /*!< Base node for the list of pages in

? ? ? ? ? ? ? ? ? ? the undo log segment; defined only on

? ? ? ? ? ? ? ? ? ? the undo log segment’s first page */

  1. TRX_UNDO_STATE:用来存储当前UNDO段的状态,状态包括TRX_UNDO_ACTIVE,TRX_UNDO_CACHED、TRX_UNDO_TO_FREE、TRX_UNDO_TO_PURGE、TRX_UNDO_PREPARED五种.
  2. TRX_UNDO_LAST_LOG:用来存储最后一个UNDO日志的偏移位置,用来在一个UNDO段中,找到最后一个UNDO日志.
  3. TRX_UNDO_FSEG_HEADER:这个位置,就是用来存储当前UNDO段的Inode信息的,通过这个信息可以知道本UNDO段的详细信息.
  4. TRX_UNDO_PAGE_LIST:段内所有的页面都是通过链表连接起来的,这个位置是链表的首地址,用来管理这个链表,上面已经介绍的TRX_UNDO_PAGE_NODE则是每个节点的双链指针.

Undo log header:

/** The undo log header. There can be several undo log headers on the first

page of an update undo log segment. */

#define TRX_UNDO_TRX_ID ? ? 0 ? /*!< Transaction id */

#define TRX_UNDO_TRX_NO ? ? 8 ? /*!< Transaction number of the

? ? ? ? ? ? ? ? ? ? transaction; defined only if the log

? ? ? ? ? ? ? ? ? ? is in a history list */

#define TRX_UNDO_DEL_MARKS? 16? /*!< Defined only in an update undo

? ? ? ? ? ? ? ? ? ? log: TRUE if the transaction may have

? ? ? ? ? ? ? ? ? ? done delete markings of records,and

? ? ? ? ? ? ? ? ? ? thus purge is necessary */

#define TRX_UNDO_LOG_START? 18? /*!< Offset of the first undo log record

? ? ? ? ? ? ? ? ? ? of this log on the header page; purge

? ? ? ? ? ? ? ? ? ? may remove undo log record from the

? ? ? ? ? ? ? ? ? ? log start,and therefore this is not

? ? ? ? ? ? ? ? ? ? necessarily the same as this log

? ? ? ? ? ? ? ? ? ? header end offset */

#define TRX_UNDO_XID_EXISTS 20? /*!< TRUE if undo log header includes

? ? ? ? ? ? ? ? ? ? X/Open XA transaction identification

? ? ? ? ? ? ? ? ? ? XID */

#define TRX_UNDO_DICT_TRANS 21? /*!< TRUE if the transaction is a table

? ? ? ? ? ? ? ? ? ? create,index create,or drop

? ? ? ? ? ? ? ? ? ? transaction: in recovery

? ? ? ? ? ? ? ? ? ? the transaction cannot be rolled back

? ? ? ? ? ? ? ? ? ? in the usual way: a ‘rollback’ rather

? ? ? ? ? ? ? ? ? ? means dropping the created or dropped

? ? ? ? ? ? ? ? ? ? table,if it still exists */

#define TRX_UNDO_TABLE_ID ? 22? /*!< Id of the table if the preceding

? ? ? ? ? ? ? ? ? ? field is TRUE */

#define TRX_UNDO_NEXT_LOG ? 30? /*!< Offset of the next undo log header

? ? ? ? ? ? ? ? ? ? on this page,0 if none */

#define TRX_UNDO_PREV_LOG ? 32? /*!< Offset of the previous undo log

? ? ? ? ? ? ? ? ? ? header on this page,0 if none */

#define TRX_UNDO_HISTORY_NODE ? 34? /*!< If the log is put to the history

? ? ? ? ? ? ? ? ? ? list,the file list node is here */

这是一个针对UNDO日志的头信息,一个事务写入一次UNDO日志就会创建一个UNDO日志单元,都会对应一个这样的UNDO日志头信息,用来管理这个日志信息的状态,存储一些相关的信息以备恢复时使用,多个UNDO日志之间,通过双向链表连接起来(通过我们即将介绍的TRX_UNDO_NEXT_LOG及TRX_UNDO_PREV_LOG来管理).

  1. TRX_UNDO_TRX_ID:用来存储当前UNDO日志对应的事务的事务ID号.
  2. TRX_UNDO_TRX_NO:事务序列号,在恢复时使用,这个序列号就是我们前面讲的TRX_SYS_TRX_ID_STORE位置存储的ID值.这个与上面的ID的区别是,NO用来在回滚时保持顺序使用,而ID是在事务运行时使用的.
  3. TRX_UNDO_DEL_MARKS:用来表示当前UNDO日志中有没有通过打标志删除过记录的操作,并决定是不是要做PURGE操作.
  4. TRX_UNDO_LOG_START:用来存储当前页面中,第一个UNDO日志的开始位置.
  5. TRX_UNDO_XID_EXISTS:用来标志当前日志中有没有包含Xid事务.
  6. TRX_UNDO_DICT_TRANS:用来标志当前日志对应的事务是不是DDL的,用来在回滚时判断如何操作.
  7. TRX_UNDO_TABLE_ID:与上面一个相关,如果上面标志是真的,则这个标志的是DDL的表ID.
  8. TRX_UNDO_NEXT_LOG:用来链接当前UNDO段中所有的UNDO日志,这个是指向下一个UNDO日志.
  9. TRX_UNDO_PREV_LOG:与上一个对应,这个用来指向上一个UNDO日志,从而构成双向链表.
  10. TRX_UNDO_HISTORY_NODE:用来存储在History List中的双向链表指针.而这个链表的首地址,是在之前我们所介绍的TRX_RSEG_HISTORY位置,可以回到前面去查看相关信息.

到现在为止,关于具体一个UNDO段中每个页面及页面内容是如何管理的已经清楚了,当一个事务需要写入UNDO日志时,就可以直接从对应的UNDO段中找到一个页面及对应的追加日志的偏移位置,然后将对应的UNDO日志写入即可.

(还是昨天那个球,线下讨论了关于会源码的作用,有很多人认为,一提到某人会源码,就觉得一般是用来装一下的,并且实际上没有几家公司强大到放心地让你写源码去,所以觉得这不是一个名副其实的技能.我认为实则不然,会源码,99%的机会不是用来写源码的,而是阅读其实际方法及原理,尽可能的做到知MySQL,或者在出现问题之后,是一个很好的用来解决问题的方法,要知道,我不只一次碰到手册上面所述内容是错误的,并且有很多问题网上也是没有的,那可想而知,如果你会阅读源码了,这样的问题可以立刻迎刃而解)

篇外续

日志这篇,以这样的角度及思维模式来讲述真的是没有见过的,并且到今天已经是连载第七篇,

可以很确定的告诉大家,还有几篇明天继续发.

(编辑:应用网_丽江站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读