PostgreSQL 源码解读(254)- PG 14(Improving connection scalability)#6

PostgreSQL 14在MVCC上面有所增强,以保证在大批量客户端连接场景下性能不会出现显著下降(详细可参见参考资料中的链接)。本节介绍了提交记录“Don’t compute global horizons while building snapshots.”中walreceiver.c、vacuum.c、analyze.c、xlog.c、nbtxlog.c的修改以及涉及的相关数据结构。

一、数据结构

N/A

二、源码解读

walreceiver.c

--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -1181,22 +1181,7 @@ XLogWalRcvSendHSFeedback(bool immed)
    /*
        XLogWalRcvSendHSFeedback : 发送备节点反馈消息外加当前时间给主节点
        修改:
            改用GetReplicationHorizons获取xmin&catalog_xmin
    */
     */
    if (hot_standby_feedback)
    {
-       TransactionId slot_xmin;
-
-       /*
-        * Usually GetOldestXmin() would include both global replication slot
-        * xmin and catalog_xmin in its calculations, but we want to derive
-        * separate values for each of those. So we ask for an xmin that
-        * excludes the catalog_xmin.
-        */
-       xmin = GetOldestXmin(NULL,
-                            PROCARRAY_FLAGS_DEFAULT | PROCARRAY_SLOTS_XMIN);
-
-       ProcArrayGetReplicationSlotXmin(&slot_xmin, &catalog_xmin);
-
-       if (TransactionIdIsValid(slot_xmin) &&
-           TransactionIdPrecedes(slot_xmin, xmin))
-           xmin = slot_xmin;
+       GetReplicationHorizons(&xmin, &catalog_xmin);
    }
    else
    {

vacuum.c

--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -955,8 +955,25 @@ vacuum_set_xid_limits(Relation rel,
    /*
        vacuum_set_xid_limits : 计算oldestXmin并冻结截断点
        修改:
            1.oldestXmin值改为通过GetOldestNonRemovableTransactionId
            2.新增如启用快照过旧特性,则设置设置时间&xmin
    */
     * working on a particular table at any time, and that each vacuum is
     * always an independent transaction.
     */
-   *oldestXmin =
-       TransactionIdLimitedForOldSnapshots(GetOldestXmin(rel, PROCARRAY_FLAGS_VACUUM), rel);
+   *oldestXmin = GetOldestNonRemovableTransactionId(rel);
+
+   if (OldSnapshotThresholdActive())
+   {
+       TransactionId limit_xmin;
+       TimestampTz limit_ts;
+
+       if (TransactionIdLimitedForOldSnapshots(*oldestXmin, rel, &limit_xmin, &limit_ts))
+       {
+           /*
+            * TODO: We should only set the threshold if we are pruning on the
+            * basis of the increased limits. Not as crucial here as it is for
+            * opportunistic pruning (which often happens at a much higher
+            * frequency), but would still be a significant improvement.
+            */
+           SetOldSnapshotThresholdTimestamp(limit_ts, limit_xmin);
+           *oldestXmin = limit_xmin;
+       }
+   }
    Assert(TransactionIdIsNormal(*oldestXmin));
@@ -1345,12 +1362,13 @@ vac_update_datfrozenxid(void)
    /*
        vac_update_datfrozenxid : 更新pg_database.datfrozenxid
        修改:
            1.改用GetOldestNonRemovableTransactionId计算最新的冻结ID
            2.修正注释
    */
    bool        dirty = false;
    /*
-    * Initialize the "min" calculation with GetOldestXmin, which is a
-    * reasonable approximation to the minimum relfrozenxid for not-yet-
-    * committed pg_class entries for new tables; see AddNewRelationTuple().
-    * So we cannot produce a wrong minimum by starting with this.
+    * Initialize the "min" calculation with
+    * GetOldestNonRemovableTransactionId(), which is a reasonable
+    * approximation to the minimum relfrozenxid for not-yet-committed
+    * pg_class entries for new tables; see AddNewRelationTuple().  So we
+    * cannot produce a wrong minimum by starting with this.
     */
-   newFrozenXid = GetOldestXmin(NULL, PROCARRAY_FLAGS_VACUUM);
+   newFrozenXid = GetOldestNonRemovableTransactionId(NULL);
    /*
     * Similarly, initialize the MultiXact "min" with the value that would be
@@ -1681,8 +1699,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
    StartTransactionCommand();
    /*
-    * Functions in indexes may want a snapshot set.  Also, setting a snapshot
-    * ensures that RecentGlobalXmin is kept truly recent.
+    * Need to acquire a snapshot to prevent pg_subtrans from being truncated,
+    * cutoff xids in local memory wrapping around, and to have updated xmin
+    * horizons.
     */
    PushActiveSnapshot(GetTransactionSnapshot());
@@ -1705,8 +1724,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
         *
         * Note: these flags remain set until CommitTransaction or
         * AbortTransaction.  We don't want to clear them until we reset
-        * MyPgXact->xid/xmin, else OldestXmin might appear to go backwards,
-        * which is probably Not Good.
+        * MyPgXact->xid/xmin, otherwise GetOldestNonRemovableTransactionId()
+        * might appear to go backwards, which is probably Not Good.
         */
        LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
        MyPgXact->vacuumFlags |= PROC_IN_VACUUM;

analyze.c

--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -1045,7 +1045,7 @@ acquire_sample_rows(Relation onerel, int elevel,
    /*
        acquire_sample_rows : 获取样本行
        修改 : GetOldestXmin函数改为GetOldestNonRemovableTransactionId
    */
    totalblocks = RelationGetNumberOfBlocks(onerel);
    /* Need a cutoff xmin for HeapTupleSatisfiesVacuum */
-   OldestXmin = GetOldestXmin(onerel, PROCARRAY_FLAGS_VACUUM);
+   OldestXmin = GetOldestNonRemovableTransactionId(onerel);
    /* Prepare for sampling block numbers */
    nblocks = BlockSampler_Init(&bs, totalblocks, targrows, random());

xlog.c

--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -9096,7 +9096,7 @@ CreateCheckPoint(int flags)
    /*
        CreateCheckPoint : 创建检查点
        修改:
            GetOldestXmin->GetOldestTransactionIdConsideredRunning
            该函数返回最旧的事务id,该id是被其他正在运行的backend视为仍为活动事务的id
    */
     * StartupSUBTRANS hasn't been called yet.
     */
    if (!RecoveryInProgress())
-       TruncateSUBTRANS(GetOldestXmin(NULL, PROCARRAY_FLAGS_DEFAULT));
+       TruncateSUBTRANS(GetOldestTransactionIdConsideredRunning());
    /* Real work is done, but log and update stats before releasing lock. */
    LogCheckpointEnd(false);
@@ -9456,7 +9456,7 @@ CreateRestartPoint(int flags)
     * this because StartupSUBTRANS hasn't been called yet.
     */
    if (EnableHotStandby)
-       TruncateSUBTRANS(GetOldestXmin(NULL, PROCARRAY_FLAGS_DEFAULT));
+       TruncateSUBTRANS(GetOldestTransactionIdConsideredRunning());
    /* Real work is done, but log and update before releasing lock. */
    LogCheckpointEnd(true);

nbtxlog.c

--- a/src/backend/access/nbtree/nbtxlog.c
+++ b/src/backend/access/nbtree/nbtxlog.c
@@ -948,11 +948,11 @@ btree_xlog_reuse_page(XLogReaderState *record)
    /*
        这里只是简单的改了注释而已
    */
     * Btree reuse_page records exist to provide a conflict point when we
     * reuse pages in the index via the FSM.  That's all they do though.
     *
-    * latestRemovedXid was the page's btpo.xact.  The btpo.xact <
-    * RecentGlobalXmin test in _bt_page_recyclable() conceptually mirrors the
-    * pgxact->xmin > limitXmin test in GetConflictingVirtualXIDs().
-    * Consequently, one XID value achieves the same exclusion effect on
-    * primary and standby.
+    * latestRemovedXid was the page's btpo.xact.  The
+    * GlobalVisCheckRemovableXid test in _bt_page_recyclable() conceptually
+    * mirrors the pgxact->xmin > limitXmin test in
+    * GetConflictingVirtualXIDs().  Consequently, one XID value achieves the
+    * same exclusion effect on primary and standby.
     */
    if (InHotStandby)
    {

三、跟踪分析

N/A

四、参考资料

1. Improving connection scalability: GetSnapshotData()
2. snapshot scalability: Don’t compute global horizons while building snapshots.

请使用浏览器的分享功能分享到微信等