From 98fa70754a8c68cdfb20f27bd7f6e6e3e5f8ed92 Mon Sep 17 00:00:00 2001
From: Maxim Orlov <orlovmg@gmail.com>
Date: Wed, 11 Jan 2023 18:07:10 +0300
Subject: [PATCH] [PGPRO-7624] use atomic old_snapshot_threshold

Using spinlock to access old_snapshot_threshold lead to the bottleneck on
replica, since GetOldSnapshotThresholdTimestamp is called too often. So, switch
to an atomic values.

tags: commitfest_hotfix
---
 src/backend/utils/time/snapmgr.c | 31 +++++++++++++++++--------------
 src/include/utils/old_snapshot.h |  5 +++--
 2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 7d11ae34781..0902e29f224 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -230,8 +230,8 @@ SnapMgrInit(void)
 		oldSnapshotControl->latest_xmin = InvalidTransactionId;
 		oldSnapshotControl->next_map_update = 0;
 		SpinLockInit(&oldSnapshotControl->mutex_threshold);
-		oldSnapshotControl->threshold_timestamp = 0;
-		oldSnapshotControl->threshold_xid = InvalidTransactionId;
+		pg_atomic_init_u64(&oldSnapshotControl->threshold_timestamp, 0);
+		pg_atomic_init_u32(&oldSnapshotControl->threshold_xid, InvalidTransactionId);
 		oldSnapshotControl->head_offset = 0;
 		oldSnapshotControl->head_timestamp = 0;
 		oldSnapshotControl->count_used = 0;
@@ -1706,9 +1706,7 @@ GetOldSnapshotThresholdTimestamp(void)
 {
 	TimestampTz threshold_timestamp;
 
-	SpinLockAcquire(&oldSnapshotControl->mutex_threshold);
-	threshold_timestamp = oldSnapshotControl->threshold_timestamp;
-	SpinLockRelease(&oldSnapshotControl->mutex_threshold);
+	threshold_timestamp = pg_atomic_read_u64(&oldSnapshotControl->threshold_timestamp);
 
 	return threshold_timestamp;
 }
@@ -1716,11 +1714,18 @@ GetOldSnapshotThresholdTimestamp(void)
 void
 SetOldSnapshotThresholdTimestamp(TimestampTz ts, TransactionId xlimit)
 {
+	TimestampTz threshold_timestamp;
+	TransactionId threshold_xid;
+
 	SpinLockAcquire(&oldSnapshotControl->mutex_threshold);
-	Assert(oldSnapshotControl->threshold_timestamp <= ts);
-	Assert(TransactionIdPrecedesOrEquals(oldSnapshotControl->threshold_xid, xlimit));
-	oldSnapshotControl->threshold_timestamp = ts;
-	oldSnapshotControl->threshold_xid = xlimit;
+	threshold_timestamp = pg_atomic_read_u64(&oldSnapshotControl->threshold_timestamp);
+	threshold_xid = pg_atomic_read_u32(&oldSnapshotControl->threshold_xid);
+
+	Assert(threshold_timestamp <= ts);
+	Assert(TransactionIdPrecedesOrEquals(threshold_xid, xlimit));
+
+	pg_atomic_write_u64(&oldSnapshotControl->threshold_timestamp, ts);
+	pg_atomic_write_u32(&oldSnapshotControl->threshold_xid, xlimit);
 	SpinLockRelease(&oldSnapshotControl->mutex_threshold);
 }
 
@@ -1739,9 +1744,7 @@ SnapshotTooOldMagicForTest(void)
 
 	ts -= 5 * USECS_PER_SEC;
 
-	SpinLockAcquire(&oldSnapshotControl->mutex_threshold);
-	oldSnapshotControl->threshold_timestamp = ts;
-	SpinLockRelease(&oldSnapshotControl->mutex_threshold);
+	pg_atomic_write_u64(&oldSnapshotControl->threshold_timestamp, ts);
 }
 
 /*
@@ -1846,8 +1849,8 @@ TransactionIdLimitedForOldSnapshots(TransactionId recentXmin,
 
 		/* Check for fast exit without LW locking. */
 		SpinLockAcquire(&oldSnapshotControl->mutex_threshold);
-		threshold_timestamp = oldSnapshotControl->threshold_timestamp;
-		threshold_xid = oldSnapshotControl->threshold_xid;
+		threshold_timestamp = pg_atomic_read_u64(&oldSnapshotControl->threshold_timestamp);
+		threshold_xid = pg_atomic_read_u32(&oldSnapshotControl->threshold_xid);
 		SpinLockRelease(&oldSnapshotControl->mutex_threshold);
 
 		if (ts == threshold_timestamp)
diff --git a/src/include/utils/old_snapshot.h b/src/include/utils/old_snapshot.h
index f1978a28e1c..3dd31d721c7 100644
--- a/src/include/utils/old_snapshot.h
+++ b/src/include/utils/old_snapshot.h
@@ -16,6 +16,7 @@
 #define OLD_SNAPSHOT_H
 
 #include "datatype/timestamp.h"
+#include "port/atomics.h"
 #include "storage/s_lock.h"
 
 /*
@@ -33,8 +34,8 @@ typedef struct OldSnapshotControlData
 	TransactionId latest_xmin;	/* latest snapshot xmin */
 	TimestampTz next_map_update;	/* latest snapshot valid up to */
 	slock_t		mutex_threshold;	/* protect threshold fields */
-	TimestampTz threshold_timestamp;	/* earlier snapshot is old */
-	TransactionId threshold_xid;	/* earlier xid may be gone */
+	pg_atomic_uint64 threshold_timestamp;	/* earlier snapshot is old */
+	pg_atomic_uint32 threshold_xid;	/* earlier xid may be gone */
 
 	/*
 	 * Keep one xid per minute for old snapshot error handling.
-- 
2.34.1

