概述
PostgreSQL由于其多版本特性,经常需要去比较两个事务的新旧。
那么该如何比较两个事务的新旧关系呢?你可能会说通过XID(事务ID)不就可以了,没错!例如一个事务ID是1000000,另一个事务ID是1000001,那么显然是1000000的事务更旧。
但是通过事务ID去判断远不止这么简单,我们都知道pg中的事务ID是用32位无符号数来表示的,也就是说如果不引入特殊的处理,当PostgreSQL的XID 到达40亿,会造成溢出,从而新的XID 为0。
而按照PostgreSQL的MVCC 机制实现,之前的事务就可以看到这个新事务创建的元组,而新事务不能看到之前事务创建的元组,这违反了事务的可见性。这种现象称为XID 的回卷问题。
因此我们比较XID还必须要考虑到回卷的情况。
首先我们需要知道在PG中0,1,2这三个XID的特殊含义:
- InvalidTransactionId = 0:表示是无效的事务ID
- BootstrapTransactionId = 1:表示系统表初使化时的事务ID,比任务普通的事务ID都旧。
- FrozenTransactionId = 2:冻结的事务ID,比任务普通的事务ID都旧。
我们看看PG中是如何比较的:
上面的代码中if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))表示当两个XID中有一个不是普通的XID时,那么比较结果直接返回id1 < id2,因为特殊的XID和普通的XID相比,一定是特殊的XID更旧。
而对于都是普通的XID的情况,pg中使用(int32) (id1 - id2),将比较结果转为32位整数。这样做是什么意思呢?
打个比方,如果发生了XID 回卷后,即使id1=4294967290比id2=5(回卷后的XID)大,但因为相减后diff大于2^31,结果值转成int32后会变成一个负数,从而让判断逻辑与事务回卷前都是一样的: (int32)(id1 - id2) < 0。
从而我们可以得出结论:
1. 特殊的事务ID一定比普通的事务ID更旧;
2. 对于都是普通事务ID的情况,PostgreSQL中是使用2^31取模的方法来进行事务的比较。
参考:
src/backend/access/transam/transam.c
最后
以上就是悲凉画笔为你收集整理的PostgreSQL如何判断事务新旧的全部内容,希望文章能够帮你解决PostgreSQL如何判断事务新旧所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复