暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL多版本的可见性判断

前言

阅读之前,您可能需要了解MVCC和事务快照相关文章。

文章目录

一、tuple行头信息简介

二、PostgreSQL事务状态

三、tuple可见性判断规则

四、归纳总结

一、tuple行头信息简介

tuple行头简述

前面的文章中,介绍过pg中通过事务id来标记一个数据行的版本,即之前我们提及的t_xmin、t_xmax。

tuple头部信息记录着数据行的t_xmin、t_xmax、t_cid、t_xvac等信息。在可见性判断里面比较重要的是:

t_xmin:表示tuple的插入事务id。

t_xmax:表示tuple的被删除或被锁住的事务id。

    typedef struct HeapTupleFields
    {
    TransactionId t_xmin; /* inserting xact ID */
    TransactionId t_xmax; /* deleting or locking xact ID */
    union
    {
    CommandId t_cid; /* inserting or deleting command ID, or both */
    TransactionId t_xvac; /* old-style VACUUM FULL xact ID */
    } t_field3;
    } HeapTupleFields;
    详见:postgresql-12.2\src\include\access\htup_details.h

    二、Postgresql事务状态

    1.事务状态和可见性判断关系

    当我们在事务中发起一个SQL语句查询数据的时候,表记录tuple某个版本对当前事务是否可见,是在特定的事务快照下,通过读取tuple的xid事务状态信息来进行判断的。

    2.事务提交日志clog

    PostgreSQL 中定义的事务状态有四种:

    1).处理中:in progress

    2).已提交:committed

    3).异常终止:aborted

    4).子事务已提交:sub committed

    以上事务状态会持久化到 $PGDATA/pg_xact目录下clog文件。同时,为了减少对clog的IO请求,会cache部分事务状态到shared_buffers中,并且在tuple的t_infomask字段标记相关的事务状态。

      /*
      * Possible transaction statuses --- note that all-zeroes is the initial
      * state.
      *
      * A "subcommitted" transaction is a committed subtransaction whose parent
      * hasn't committed or aborted yet.
      */
      typedef int XidStatus;

      #define TRANSACTION_STATUS_IN_PROGRESS 0x00
      #define TRANSACTION_STATUS_COMMITTED 0x01
      #define TRANSACTION_STATUS_ABORTED 0x02
      #define TRANSACTION_STATUS_SUB_COMMITTED 0x03
      详见:postgresql-12.2\src\include\access\clog.h

      3.tuple中的t_infomask

      通过获取xid在t_infomask的标记信息,可以不用访问clog信息就可以判断tuple版本对当前事务是否可见。

      t_infomask有以下与可见性相关的标志位:

        #define HEAP_XMIN_COMMITTED    0x0100  /* t_xmin committed */
        #define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */
        #define HEAP_XMIN_FROZEN (HEAP_XMIN_COMMITTED|HEAP_XMIN_INVALID)
        #define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */
        #define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */
        #define HEAP_XMAX_IS_MULTI 0x1000 /* t_xmax is a MultiXactId */
        详见:postgresql-12.2\src\include\access\htup_details.h

        比如标记HEAP_XMIN_COMMITTED为真,并且HEAP_XMAX_INVALID为假,则说明这行是新插入的行,是可见的,这时就不需要到clog中查询xmin的事务状态和xmax的事务状态了。

        但如果HEAP_XMIN_COMMITTED没有设置,此时xmin对应的事务是否已提交是不知道的,这种情况仍然需要到clog中去判断xmin的状态,对于HEAP_XMAX_COMMITTED同样如此。

        三、可见性判断规则

        1.通过事务快照判断

        首先,在判断tuple可见性的时候,需要给定一个xid,语句检索数据的时候会自动获取tuple的t_xmin、t_xmax;

        然后,判断该xid和快照xmin:xmax:xip_list之间的关系,最主要目的是判断该xid是否还在in progress状态。

        关于transaction snapshot中xmin和xmax,我们可以参考源码对SnapshotData结构体中xmin和xmax的定义:

          typedef struct SnapshotData
          {
          ...
          TransactionId xmin; /* all XID < xmin are visible to me */
          TransactionId xmax; /* all XID >= xmax are invisible to me */
          ...
          }
          详见:\postgresql-12.2\postgresql-12.2\src\include\utils\snapshot.h

          的来说:

          1)小于snapshot中的xmin:该tuple属已结束事务,对当前事务可见。

          2)大于等于snapshot中的xmax:该tuple属未来事务,对当前事务不可见。

          3)如果在snapshot的xip_list之中,即[xmin,xmax)之间:则进一步查看xid的事务状态来判断tuple是否可见。

          2.通过可见性规则判断

          结合前面介绍的4种事务状态,如果不考虑sub committed的情况,大致的判断逻辑像下面这个样子:

            /* t_xmin status = ABORTED */
            Rule 1: IF t_xmin status is 'ABORTED' THEN
            RETURN 'Invisible'
            END IF

            /* t_xmin status = IN_PROGRESS */
            IF t_xmin status is 'IN_PROGRESS' THEN
            IF t_xmin = current_txid THEN
            Rule 2: IF t_xmax = INVALID THEN
            RETURN 'Visible'
            Rule 3: ELSE /* this tuple has been deleted or updated by the current transaction itself. */
            RETURN 'Invisible'
            END IF
            Rule 4: ELSE /* t_xmin ≠ current_txid */
            RETURN 'Invisible'
            END IF
            END IF


            /* t_xmin status = COMMITTED */
            IF t_xmin status is 'COMMITTED' THEN
            Rule 5: IF t_xmin is active in the obtained transaction snapshot THEN
            RETURN 'Invisible'
            Rule 6: ELSE IF t_xmax = INVALID OR status of t_xmax is 'ABORTED' THEN
            RETURN 'Visible'
            ELSE IF t_xmax status is 'IN_PROGRESS' THEN
            Rule 7: IF t_xmax = current_txid THEN
            RETURN 'Invisible'
            Rule 8: ELSE /* t_xmax ≠ current_txid */
            RETURN 'Visible'
            END IF
            ELSE IF t_xmax status is 'COMMITTED' THEN
            Rule 9: IF t_xmax is active in the obtained transaction snapshot THEN
            RETURN 'Visible'
            Rule 10: ELSE
            RETURN 'Invisible'
            END IF
            END IF
            END IF
            更多参考详见:http://www.interdb.jp/pg/pgsql05.html

            四、归纳总结

            如果对Oracle熟悉(Read committed),上面的判断逻辑应该比较容易理解,其实我们可以简单概括为:

            1.别人事务的增删改,如果事务未提交,增删改的行记录最新状态在当前事务会话中无法读取。

            2.自己当前事务的增删改,即使未提交,增删改的行记录最新状态在自己的当前事务内,当然能读取。

            3.无论是别人事务还是自己当前事务发起的增删改,如果事务异常中断,则所有会话都无法读取。

            结合之前判断逻辑,这里顺便借鉴Hironobu SUZUKI整理的规则供学习参考。其中“∧”表示“and”,“∨”表示“or”:

              Rule 1: If Status(t_xmin) = ABORTED => Invisible 
              Rule 2: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin = current_txid ∧ t_xmax = INVAILD => Visible
              Rule 3: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin = current_txid ∧ t_xmax ≠ INVAILD => Invisible
              Rule 4: If Status(t_xmin) = IN_PROGRESS ∧ t_xmin ≠ current_txid => Invisible
              Rule 5: If Status(t_xmin) = COMMITTED ∧ Snapshot(t_xmin) = active => Invisible
              Rule 6: If Status(t_xmin) = COMMITTED ∧ (t_xmax = INVALID ∨ Status(t_xmax) = ABORTED) => Visible
              Rule 7: If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = IN_PROGRESS ∧ t_xmax = current_txid => Invisible
              Rule 8: If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = IN_PROGRESS ∧ t_xmax ≠ current_txid => Visible
              Rule 9: If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = COMMITTED ∧ Snapshot(t_xmax) = active => Visible
              Rule 10: If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = COMMITTED ∧ Snapshot(t_xmax) ≠ active => Invisible

              参考资料

              1.http://www.interdb.jp/pg/pgsql05.html

              2.https://www.postgresql.org/docs/12/index.html


              I Love PG

              关于我们

              中国开源软件推进联盟PostgreSQL分会(简称:PG分会)于2017年成立,由国内多家PG生态企业所共同发起,业务上接受工信部产业发展研究院指导。PG分会致力于构建PG产业生态,推动PG产学研用发展,是国内一家PG行业协会组织。



              欢迎投稿

              做你的舞台,show出自己的才华 。

              投稿邮箱:partner@postgresqlchina.com

                                             

                                               ——愿能安放你不羁的灵魂


              技术文章精彩回顾




              PostgreSQL学习的九层宝塔
              PostgreSQL职业发展与学习攻略
              搞懂PostgreSQL数据库透明数据加密之加密算法介绍
              一文读懂PostgreSQL-12分区表
              一文搞懂PostgreSQL物化视图
              PostgreSQL源码学习之:RegularLock
              Postgresql源码学习之词法和语法分析
              2019,年度数据库舍 PostgreSQL 其谁?
              Postgres是最好的开源软件
              PostgreSQL是世界上最好的数据库
              从Oracle迁移到PostgreSQL的十大理由
              PG活动精彩回顾



              创建PG全球生态!PostgresConf.CN2019大会盛大召开
              首站起航!2019“让PG‘象’前行”上海站成功举行
              走进蓉城丨2019“让PG‘象’前行”成都站成功举行
              中国PG象牙塔计划发布,首批合作高校授牌仪式在天津举行
              群英论道聚北京,共话PostgreSQL
              相聚巴厘岛| PG Conf.Asia 2019  DAY0、DAY1简报
              相知巴厘岛| PG Conf.Asia 2019 DAY2简报
              独家|硅谷Postgres大会简报
              PostgreSQL线上沙龙第一期精彩回顾
              PostgreSQL线上沙龙第二期精彩回顾
              PostgreSQL线上沙龙第三期精彩回顾
              PostgreSQL线上沙龙第四期精彩回顾
              PostgreSQL线上沙龙第五期精彩回顾

              PG培训认证精彩回顾




              关于中国PostgreSQL培训认证,你想知道的都在这里!
              首批中国PGCA培训圆满结束,首批认证考试将于10月18日和20日举行!
              中国首批PGCA认证考试圆满结束,203位考生成功获得认证!
              中国第二批PGCA认证考试圆满结束,115位考生喜获认证!
              请查收:中国首批PGCA证书!
              重要通知:三方共建,中国PostgreSQL认证权威升级!
              一场考试迎新年 | 12月28日,首次PGCE中级认证考试开考!
              近500人参与!首次PGCE中级、第三批次PGCA初级认证考试落幕!
              通知:PostgreSQL技术能力电子证书上线!

              最后修改时间:2020-04-28 08:13:16
              文章转载自开源软件联盟PostgreSQL分会,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论