• Postgresql源码(59)事务ID取值和判断规律总结


    xid取值规律

    xid是uint32类型的,GetNewTransactionId函数中xid在ShmemVariableCache->nextXid中取值,但是ShmemVariableCache->nextXid是long int类型的。

    unsigned int : 0           ~  4294967295 ( 0     ~ 2^32-1 )
    int          : -2147483648 ~  2147483647 ( -2^31 ~ 2^31-1 )
    long int     : -9223372036854775808 ~ 9223372036854775807 ( -2^63 ~ 2^63-1 )
    
    
    GetNewTransactionId
      FullTransactionId full_xid;
      TransactionId xid;
      full_xid = ShmemVariableCache->nextXid;
      xid = XidFromFullTransactionId(full_xid);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    所以xid的取值会从0到4294967295在归零再次到4294967295不停循环。而ShmemVariableCache->nextXid是一直上涨的,因为ShmemVariableCache->nextXid的范围是( -2^63 ~ 2^63-1 )。

    注意ShmemVariableCache->nextXid到正数最大值9223372036854775807后在加一会溢出到负数最小值-9223372036854775808,这时强转到uint32时为0,正好又是一轮循环。

    取值规律见下面实例:

    ShmemVariableCache->nextXid
    nextXid: 0 1 2 3 ... 4294967295 4294967296 4294967297 4294967298 ... 9223372036854775807
    xid    : 0 1 2 3 ... 4294967295 0          1          2          ... 4294967295    
    
    
    ShmemVariableCache->nextXid
    nextXid: 9223372036854775807 -9223372036854775808 -9223372036854775807 ... 0
    xid    : 4294967295          0                    1                        0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    ShmemVariableCache->nextXid自加使用FullTransactionIdAdvance函数

    • 该函数从0开始增加nextXid的值,第一个if保证nextXid可以正常返回0、1、2的值
    • 在后面nextXid增加到4294967296时,会走while循环把4294967296、4294967297、4294967298的值跳过,因为这三个值转换为uint32后会变成0、1、2,正常事务ID不使用这三个值。
    • 在后面nextXid继续增加每次碰到上述情况,都会走while跳过这三个数。
    static inline void
    FullTransactionIdAdvance(FullTransactionId *dest)
    {
    	dest->value++;
    
    	/* see FullTransactionIdAdvance() */
    	if (FullTransactionIdPrecedes(*dest, FirstNormalFullTransactionId))
    		return;
    
    	while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId)
    		dest->value++;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    xid大小判断规律

    已TransactionIdFollows函数为例,入参是两个uint32(0 ~ 2^32-1)。

    但是做减法的时候结果保存到diff是int32(-2^31 ~ 2^31-1)。

    typedef uint32 TransactionId;
    
    /*
     * TransactionIdPrecedes --- is id1 logically < id2?
     */
    bool
    TransactionIdPrecedes(TransactionId id1, TransactionId id2)
    {
    	/*
    	 * If either ID is a permanent XID then we can just do unsigned
    	 * comparison.  If both are normal, do a modulo-2^32 comparison.
    	 */
    	int32		diff;
    
    	if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
    		return (id1 < id2);
    
    	diff = (int32) (id1 - id2);
    	return (diff < 0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 注意(id1 - id2)不管怎么减结果都是正数,因为这是两个uint32在减。这个正数结果代表这两个值的距离。

    当前距离-5

    id1 = 4294967290u
    id2 = 4294967295u
    id1 - id2 = 4294967291u
    diff = (int32)(id1 - id2) = -5
    
    • 1
    • 2
    • 3
    • 4

    id2继续增长,但是id2是uint32最大值就是4294967295u了,继续增长后溢出

    id1 = 4294967290u
    id2 = 10u
    id1 - id2 = 4294967280u
    diff = (int32)(id1 - id2) = -16
    
    • 1
    • 2
    • 3
    • 4

    可以看到溢出后,结果仍然是负数,TransactionIdPrecedes函数的计算是正确的id1 logically < id2

    **但是如果id1和id2距离过大,超过231后,例如id2从刚才的10继续增长到2147483647**,id2领先id1的距离已经超过了231:

    id1 = 4294967290u
    id2 = 2147483647u
    id1 - id2 = 2147483643u
    diff = (int32)(id1 - id2) = 2147483643
    
    • 1
    • 2
    • 3
    • 4

    结果diff又翻转了一次变成了正数,虽然id1逻辑上应该<id2,但是这时TransactionIdPrecedes的结果已经是false了。

    显然TransactionIdPrecedes函数计算错误。

    总结

    所以在PG现有的xid分配机制上,为了保证xid回卷后还能正确的对比大小,两个xid的距离不能超过2^31。

    方便记忆:事务ID可以回卷,但最老的到最新的距离不能超过20亿,否则会发生第二次符号翻转,事务ID计算结果全部都会出错。

  • 相关阅读:
    React redux、react-redux的基本使用(笔记)
    [附源码]Python计算机毕业设计SSM家政服务系统(程序+LW)
    Word修订内容批量标红
    35 | 如何准备测试数据?
    Java泛型详解,史上最全图文详解!
    手部关键点识别易语言代码
    python 文创产品商城推荐网上购物系统设计与实现vue
    免费开箱即用微鳄OA办公系统
    SpringCloud Alibaba - Sentinel
    TX Text Control .NET for Windows Forms 32 Crk
  • 原文地址:https://blog.csdn.net/jackgo73/article/details/125623256