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

PolarDB PostgreSQL版中"xmin"

PolarDB 2025-02-08
59

关于 PolarDB PostgreSQL 版

PolarDB PostgreSQL 版是一款阿里云自主研发的云原生关系型数据库产品,100% 兼容 PostgreSQL,高度兼容Oracle语法;采用基于 Shared-Storage 的存储计算分离架构,具有极致弹性、毫秒级延迟、HTAP 、Ganos全空间数据处理能力和高可靠、高可用、弹性扩展等企业级数据库特性。同时,PolarDB PostgreSQL 版具有大规模并行计算能力,可以应对 OLTP 与 OLAP 混合负载。

PolarDB PostgreSQL版中"xmin"

PolarDB PostgreSQL中存在各类xmin,有用于可见性、vacuum、prune page、page recyclable等等地方的判断。

extern PGDLLIMPORT TransactionId TransactionXmin;
extern PGDLLIMPORT TransactionId RecentXmin;
extern PGDLLIMPORT TransactionId RecentGlobalXmin;
extern PGDLLIMPORT TransactionId RecentGlobalDataXmin;

复制

"xmin"计算

TransactionXmin:

获取快照时获取当前的快照能看到的最小值;计算方式从polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid
 中获取,polar_oldest_active_xid
中维护当前的最老的活跃事务,事务提交或abort时都可能会修改polar_oldest_active_xid
,从而保证维护一个最老的活跃事务;

RecentXmin:

获取快照时获取当前的快照能看到的最小值;计算方式从polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid
 中获取。与TransactionXmin
不同的是,RecentXmin
获取快照时都会重新计算当前的最老的活跃事务。

RecentGlobalDataXmin:

typedef struct PGXACT
{

 TransactionId xid;   /* id of top-level transaction currently being
         * executed by this proc, if running and XID
         * is assigned; else InvalidTransactionId */


 TransactionId xmin;   /* minimal running XID as it was when we were
         * starting our xact, excluding LAZY VACUUM:
         * vacuum must not remove tuples deleted by
         * xid >= xmin ! */


 /* 
  * POLAR csn 
  * When transaction committing, record commit csn in PGXACT with CommitSeqNoLock hold.
  * For now, only used in GetRunningTransactionData to iterate ProcArray and filter out
  * committed xacts in active xacts list.
  * If committed, value is csn, else InvalidTransactionId.
  */

 CommitSeqNo polar_csn; 

    /* ... */
} PGXACT;

复制

PGXACT
中会记录自身的事务xid,以及它获取快照时能看到的最小xid
记录在xmin
。所以遍历所有的procarry
对应的pgxact
xid
xmin
、以及所有的replication slot的xmin
中的最小值作为RecentGlobalXmin

RecentGlobalXmin

RecentGlobalXmin
RecentGlobalDataXmin
基础上还考虑了replication slot catalog xmin;

所以它们之间的大小关系 **RecentGlobalXmin <= RecentGlobalDataXmin <= TransactionXmin**
;

使用

RecentGlobalXmin
GetOldestXmin()
使用区别绝大部分场景使用的是RecentGlobalXmin/RecentGlobalDataXmin
,因为GetOldestXmin
计算主要会遍历ProcArray
,会加ProcArrayLock
锁,所以如果每个需要oldestXmin位置都重新计算可能会带来性能影响。由于RecentGlobalXmin
是一个相对较老的值,但是获取一个相对较老的值来做判断并不会给正确性带来影响。所以,RecentGlobalXmin/RecentGlobalDataXmin
的使用地方替换成GetOldestXmin()
是不会有任何正确性问题,但是会带来性能问题。

GetOldestXmin()主要用在几处:

  • vacuum时会计算  oldestXmin = GetOldestXmin(rel, PROCARRAY_FLAGS_VACUUM)
    。同时利用 oldestXmin - freezemin
    差值作为本次vacuum的 FreeLimit。oldestXmin
    主要用于判断tuple是否满足vacuum的条件(利用HeapTupleSatisfiesVacuum
    函数判断,实现如下图)。
vac_mvcc.png
  • update datfrozenxid时会计算 newFrozenXid = GetOldestXmin(NULL, PROCARRAY_FLAGS_VACUUM)
    ;

其他场景基本都用RecentGlobalXmin/RecentGlobalDataXmin


文章转载自PolarDB,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论