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.