diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index b353c61683..7cd0d5e49f 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -9068,8 +9068,56 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
      </varlistentry>
 
      </variablelist>
-   </sect1>
 
+    <sect2 id="runtime-config-CSN-base-snapshot">
+     <title>CSN Based Snapshot</title>
+
+      <para>
+       By default, The snapshots in <productname>PostgreSQL</productname> uses the
+       XID (TransactionID) to identify the status of the transaction, the in-progress
+       transactions, and the future transactions for all its visibility calculations.
+      </para>
+
+      <para>
+       <productname>PostgreSQL</productname> also provides the CSN (commit-sequence-number)
+        based mechanism to identify the past-transactions and the ones that are yet to
+        be started/committed.
+      </para>
+
+     <variablelist>
+      <varlistentry id="guc-enable-csn-snapshot" xreflabel="enable_csn_snapshot">
+       <term><varname>enable_csn_snapshot</varname> (<type>boolean</type>)
+        <indexterm>
+         <primary><varname>enable_csn_snapshot</varname> configuration parameter</primary>
+        </indexterm>
+       </term>
+       <listitem>
+
+        <para>
+        Enable/disable the CSN based transaction visibility tracking for the snapshot.
+        </para>
+
+        <para>
+        <productname>PostgreSQL</productname> uses the clock timestamp as a CSN,
+        so enabling the CSN based snapshots can be useful for implementing the global
+        snapshots and global transaction visibility.
+        </para>
+
+        <para>
+         when enabled <productname>PostgreSQL</productname> creates
+         <filename>pg_csn</filename> directory under <envar>PGDATA</envar> to keep
+         the track of CSN and XID mappings.
+        </para>
+
+        <para>
+         The default value is off.
+        </para>
+       </listitem>
+      </varlistentry>
+
+     </variablelist>
+    </sect2>
+   </sect1>
    <sect1 id="runtime-config-compatible">
     <title>Version and Platform Compatibility</title>
 
diff --git a/src/backend/access/transam/csn_log.c b/src/backend/access/transam/csn_log.c
index 9a42c5ba60..16c6856758 100644
--- a/src/backend/access/transam/csn_log.c
+++ b/src/backend/access/transam/csn_log.c
@@ -30,9 +30,28 @@
 #include "miscadmin.h"
 #include "pg_trace.h"
 #include "utils/snapmgr.h"
+#include "storage/shmem.h"
 
 bool enable_csn_snapshot;
 
+/*
+ * We use csnSnapshotActive to judge if csn snapshot enabled instead of by
+ * enable_csn_snapshot, this design is similar to 'track_commit_timestamp'.
+ *
+ * Because in process of replication if master change 'enable_csn_snapshot'
+ * in a database restart, standby should apply wal record for GUC changed,
+ * then it's difficult to notice all backends about that. So they can get
+ * the message by 'csnSnapshotActive' which in share buffer. It will not
+ * acquire a lock, so without performance issue.
+ *
+ */
+typedef struct CSNshapshotShared
+{
+	bool		csnSnapshotActive;
+} CSNshapshotShared;
+
+CSNshapshotShared *csnShared = NULL;
+
 /*
  * Defines for CSNLog page sizes.  A page is the same BLCKSZ as is used
  * everywhere else in Postgres.
@@ -94,9 +113,6 @@ CSNLogSetCSN(TransactionId xid, int nsubxids,
 	int			i = 0;
 	int			offset = 0;
 
-	/* Callers of CSNLogSetCSN() must check GUC params */
-	Assert(enable_csn_snapshot);
-
 	Assert(TransactionIdIsValid(xid));
 
 	pageno = TransactionIdToPage(xid);		/* get page of parent */
@@ -191,9 +207,6 @@ CSNLogGetCSNByXid(TransactionId xid)
 	int		slotno;
 	XidCSN	csn;
 
-	/* Callers of CSNLogGetCSNByXid() must check GUC params */
-	Assert(enable_csn_snapshot);
-
 	/* lock is acquired by SimpleLruReadPage_ReadOnly */
 	slotno = SimpleLruReadPage_ReadOnly(CsnlogCtl, pageno, xid);
 	csn = *(XidCSN *) (CsnlogCtl->shared->page_buffer[slotno] + entryno * sizeof(XLogRecPtr));
@@ -218,9 +231,6 @@ CSNLogShmemBuffers(void)
 Size
 CSNLogShmemSize(void)
 {
-	if (!enable_csn_snapshot)
-		return 0;
-
 	return SimpleLruShmemSize(CSNLogShmemBuffers(), 0);
 }
 
@@ -230,37 +240,25 @@ CSNLogShmemSize(void)
 void
 CSNLogShmemInit(void)
 {
-	if (!enable_csn_snapshot)
-		return;
+	bool		found;
+
 
 	CsnlogCtl->PagePrecedes = CSNLogPagePrecedes;
 	SimpleLruInit(CsnlogCtl, "CSNLog Ctl", CSNLogShmemBuffers(), 0,
 				  CSNLogControlLock, "pg_csn", LWTRANCHE_CSN_LOG_BUFFERS);
+
+	csnShared = ShmemInitStruct("CSNlog shared",
+									 sizeof(CSNshapshotShared),
+									 &found);
 }
 
 /*
- * This func must be called ONCE on system install.  It creates the initial
- * CSNLog segment.  The pg_csn directory is assumed to have been
- * created by initdb, and CSNLogShmemInit must have been called already.
+ * See ActivateCSNlog
  */
 void
 BootStrapCSNLog(void)
 {
-	int			slotno;
-
-	if (!enable_csn_snapshot)
-		return;
-
-	LWLockAcquire(CSNLogControlLock, LW_EXCLUSIVE);
-
-	/* Create and zero the first page of the commit log */
-	slotno = ZeroCSNLogPage(0, false);
-
-	/* Make sure it's written out */
-	SimpleLruWritePage(CsnlogCtl, slotno);
-	Assert(!CsnlogCtl->shared->page_dirty[slotno]);
-
-	LWLockRelease(CSNLogControlLock);
+	return;
 }
 
 /*
@@ -288,13 +286,94 @@ ZeroTruncateCSNLogPage(int pageno, bool write_xlog)
 	SimpleLruTruncate(CsnlogCtl, pageno);
 }
 
+void
+ActivateCSNlog(void)
+{
+	int				startPage;
+	TransactionId	nextXid = InvalidTransactionId;
+
+	if (csnShared->csnSnapshotActive)
+		return;
+
+
+	nextXid = XidFromFullTransactionId(ShmemVariableCache->nextFullXid);
+	startPage = TransactionIdToPage(nextXid);
+
+	/* Create the current segment file, if necessary */
+	if (!SimpleLruDoesPhysicalPageExist(CsnlogCtl, startPage))
+	{
+		int			slotno;
+		LWLockAcquire(CSNLogControlLock, LW_EXCLUSIVE);
+		slotno = ZeroCSNLogPage(startPage, false);
+		SimpleLruWritePage(CsnlogCtl, slotno);
+		LWLockRelease(CSNLogControlLock);
+	}
+	csnShared->csnSnapshotActive = true;
+}
+
+bool
+get_csnlog_status(void)
+{
+	if(!csnShared)
+	{
+		/* Should not arrived */
+		elog(ERROR, "We do not have csnShared point");
+	}
+	return csnShared->csnSnapshotActive;
+}
+
+void
+DeactivateCSNlog(void)
+{
+	csnShared->csnSnapshotActive = false;
+	LWLockAcquire(CSNLogControlLock, LW_EXCLUSIVE);
+	(void) SlruScanDirectory(CsnlogCtl, SlruScanDirCbDeleteAll, NULL);
+	LWLockRelease(CSNLogControlLock);
+}
+
+void
+StartupCSN(void)
+{
+	ActivateCSNlog();
+}
+
+void
+CompleteCSNInitialization(void)
+{
+	/*
+	 * If the feature is not enabled, turn it off for good.  This also removes
+	 * any leftover data.
+	 *
+	 * Conversely, we activate the module if the feature is enabled.  This is
+	 * necessary for primary and standby as the activation depends on the
+	 * control file contents at the beginning of recovery or when a
+	 * XLOG_PARAMETER_CHANGE is replayed.
+	 */
+	if (!get_csnlog_status())
+		DeactivateCSNlog();
+	else
+		ActivateCSNlog();
+}
+
+void
+CSNlogParameterChange(bool newvalue, bool oldvalue)
+{
+	if (newvalue)
+	{
+		if (!csnShared->csnSnapshotActive)
+			ActivateCSNlog();
+	}
+	else if (csnShared->csnSnapshotActive)
+		DeactivateCSNlog();
+}
+
 /*
  * This must be called ONCE during postmaster or standalone-backend shutdown
  */
 void
 ShutdownCSNLog(void)
 {
-	if (!enable_csn_snapshot)
+	if (!get_csnlog_status())
 		return;
 
 	/*
@@ -314,7 +393,7 @@ ShutdownCSNLog(void)
 void
 CheckPointCSNLog(void)
 {
-	if (!enable_csn_snapshot)
+	if (!get_csnlog_status())
 		return;
 
 	/*
@@ -342,7 +421,7 @@ ExtendCSNLog(TransactionId newestXact)
 {
 	int			pageno;
 
-	if (!enable_csn_snapshot)
+	if (!get_csnlog_status())
 		return;
 
 	/*
@@ -373,9 +452,9 @@ ExtendCSNLog(TransactionId newestXact)
 void
 TruncateCSNLog(TransactionId oldestXact)
 {
-	int			cutoffPage;
+	int				cutoffPage;
 
-	if (!enable_csn_snapshot)
+	if (!get_csnlog_status())
 		return;
 
 	/*
@@ -388,7 +467,6 @@ TruncateCSNLog(TransactionId oldestXact)
 	 */
 	TransactionIdRetreat(oldestXact);
 	cutoffPage = TransactionIdToPage(oldestXact);
-
 	ZeroTruncateCSNLogPage(cutoffPage, true);
 }
 
@@ -447,7 +525,6 @@ WriteXidCsnXlogRec(TransactionId xid, int nsubxids,
 					 TransactionId *subxids, XidCSN csn)
 {
 	xl_xidcsn_set 	xlrec;
-	XLogRecPtr		recptr;
 
 	xlrec.xtop = xid;
 	xlrec.nsubxacts = nsubxids;
@@ -456,8 +533,7 @@ WriteXidCsnXlogRec(TransactionId xid, int nsubxids,
 	XLogBeginInsert();
 	XLogRegisterData((char *) &xlrec, MinSizeOfXidCSNSet);
 	XLogRegisterData((char *) subxids, nsubxids * sizeof(TransactionId));
-	recptr = XLogInsert(RM_CSNLOG_ID, XLOG_CSN_SETXIDCSN);
-	XLogFlush(recptr);
+	XLogInsert(RM_CSNLOG_ID, XLOG_CSN_SETXIDCSN);
 }
 
 /*
@@ -477,12 +553,9 @@ WriteZeroCSNPageXlogRec(int pageno)
 static void
 WriteTruncateCSNXlogRec(int pageno)
 {
-	XLogRecPtr	recptr;
-	return;
 	XLogBeginInsert();
 	XLogRegisterData((char *) (&pageno), sizeof(int));
-	recptr = XLogInsert(RM_CSNLOG_ID, XLOG_CSN_TRUNCATE);
-	XLogFlush(recptr);
+	XLogInsert(RM_CSNLOG_ID, XLOG_CSN_TRUNCATE);
 }
 
 
diff --git a/src/backend/access/transam/csn_snapshot.c b/src/backend/access/transam/csn_snapshot.c
index 99e4a2f1ed..cedce60a6f 100644
--- a/src/backend/access/transam/csn_snapshot.c
+++ b/src/backend/access/transam/csn_snapshot.c
@@ -62,10 +62,7 @@ CSNSnapshotShmemSize(void)
 {
 	Size	size = 0;
 
-	if (enable_csn_snapshot)
-	{
-		size += MAXALIGN(sizeof(CSNSnapshotState));
-	}
+	size += MAXALIGN(sizeof(CSNSnapshotState));
 
 	return size;
 }
@@ -76,17 +73,15 @@ CSNSnapshotShmemInit()
 {
 	bool found;
 
-	if (enable_csn_snapshot)
+	csnState = ShmemInitStruct("csnState",
+							sizeof(CSNSnapshotState),
+							&found);
+	if (!found)
 	{
-		csnState = ShmemInitStruct("csnState",
-								sizeof(CSNSnapshotState),
-								&found);
-		if (!found)
-		{
-			csnState->last_max_csn = 0;
-			csnState->last_csn_log_wal = 0;
-			SpinLockInit(&csnState->lock);
-		}
+		csnState->last_max_csn = 0;
+		csnState->last_csn_log_wal = 0;
+		csnState->xmin_for_csn = InvalidTransactionId;
+		SpinLockInit(&csnState->lock);
 	}
 }
 
@@ -104,7 +99,7 @@ GenerateCSN(bool locked)
 	instr_time	current_time;
 	SnapshotCSN	csn;
 
-	Assert(enable_csn_snapshot);
+	Assert(get_csnlog_status());
 
 	/*
 	 * TODO: create some macro that add small random shift to current time.
@@ -140,7 +135,7 @@ TransactionIdGetXidCSN(TransactionId xid)
 {
 	XidCSN 			 xid_csn;
 
-	Assert(enable_csn_snapshot);
+	Assert(get_csnlog_status());
 
 	/* Handle permanent TransactionId's for which we don't have mapping */
 	if (!TransactionIdIsNormal(xid))
@@ -168,12 +163,20 @@ TransactionIdGetXidCSN(TransactionId xid)
 		SpinLockRelease(&csnState->lock);
 	}
 
-	if ( FrozenTransactionId != xmin_for_csn ||
+	if (FrozenTransactionId == xmin_for_csn ||
 					TransactionIdPrecedes(xmin_for_csn, TransactionXmin))
 	{
 		xmin_for_csn = TransactionXmin;
 	}
 
+	/*
+	 * For the xid with 'xid >= TransactionXmin and xid < xmin_for_csn',
+	 * it defined as unclear csn which follow xid-snapshot result.
+	 */
+	if(!TransactionIdPrecedes(xid, TransactionXmin) &&
+							TransactionIdPrecedes(xid, xmin_for_csn))
+		return UnclearCSN;
+
 	/*
 	 * For xids which less then TransactionXmin CSNLog can be already
 	 * trimmed but we know that such transaction is definetly not concurrently
@@ -222,7 +225,7 @@ XidInvisibleInCSNSnapshot(TransactionId xid, Snapshot snapshot)
 {
 	XidCSN csn;
 
-	Assert(enable_csn_snapshot);
+	Assert(get_csnlog_status());
 
 	csn = TransactionIdGetXidCSN(xid);
 
@@ -238,6 +241,14 @@ XidInvisibleInCSNSnapshot(TransactionId xid, Snapshot snapshot)
 		/* It is bootstrap or frozen transaction */
 		return false;
 	}
+	else if(CSNIsUnclear(csn))
+	{
+		/*
+		 * Some xid can not figure out csn because of snapshot switch,
+		 * and we can follow xid-base result.
+		 */
+		return true;
+	}
 	else
 	{
 		/* It is aborted or in-progress */
@@ -277,7 +288,7 @@ void
 CSNSnapshotAbort(PGPROC *proc, TransactionId xid,
 					int nsubxids, TransactionId *subxids)
 {
-	if (!enable_csn_snapshot)
+	if (!get_csnlog_status())
 		return;
 
 	CSNLogSetCSN(xid, nsubxids, subxids, AbortedXidCSN, true);
@@ -310,7 +321,7 @@ CSNSnapshotPrecommit(PGPROC *proc, TransactionId xid,
 	XidCSN oldassignedXidCsn = InProgressXidCSN;
 	bool in_progress;
 
-	if (!enable_csn_snapshot)
+	if (!get_csnlog_status())
 		return;
 
 	/* Set InDoubt status if it is local transaction */
@@ -348,7 +359,7 @@ CSNSnapshotCommit(PGPROC *proc, TransactionId xid,
 {
 	volatile XidCSN assigned_xid_csn;
 
-	if (!enable_csn_snapshot)
+	if (!get_csnlog_status())
 		return;
 
 	if (!TransactionIdIsValid(xid))
@@ -391,10 +402,42 @@ get_last_log_wal_csn(void)
 }
 
 /*
- * 'xmin_for_csn' for when turn xid-snapshot to csn-snapshot
+ * Rely on different value of enable and same we have different action.
  */
 void
-set_xmin_for_csn(void)
+prepare_csn_env(bool enable, bool same, TransactionId *xmin_for_csn_in_control)
 {
-	csnState->xmin_for_csn = XidFromFullTransactionId(ShmemVariableCache->nextFullXid);
+	TransactionId		nextxid = InvalidTransactionId;
+
+	if(enable)
+	{
+		if(same)
+		{
+			/*
+			 * Database startup with no enable_csn_snapshot change and value is true,
+			 * it can just transmit xmin_for_csn from pg_control to csnState->xmin_for_csn.
+			 */
+			csnState->xmin_for_csn = *xmin_for_csn_in_control;
+		}
+		else
+		{
+			/*
+			 * Last time database is xid-base snapshot, and now startup as csn-base snapshot,
+			 * we should redifine a xmin_for_csn, and store it in both pg_control and
+			 * csnState->xmin_for_csn.
+			 */
+			nextxid = XidFromFullTransactionId(ShmemVariableCache->nextFullXid);
+			csnState->xmin_for_csn = nextxid;
+			*xmin_for_csn_in_control = nextxid;
+			/* produce the csnlog segment we want now and seek to current page */
+			ActivateCSNlog();
+		}
+	}
+	else
+	{
+		/* Try to drop all csnlog seg */
+		DeactivateCSNlog();
+		/* Clear xmin_for_csn in pg_control because we are xid-base snaposhot now. */
+		*xmin_for_csn_in_control = InvalidTransactionId;
+	}
 }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index dc2e9ae874..32f1e614b4 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -79,6 +79,7 @@
 #include "utils/relmapper.h"
 #include "utils/snapmgr.h"
 #include "utils/timestamp.h"
+#include "access/csn_log.h"
 
 extern uint32 bootstrap_data_checksum_version;
 
@@ -4609,6 +4610,7 @@ InitControlFile(uint64 sysidentifier)
 	ControlFile->track_commit_timestamp = track_commit_timestamp;
 	ControlFile->enable_csn_snapshot = enable_csn_snapshot;
 	ControlFile->data_checksum_version = bootstrap_data_checksum_version;
+	ControlFile->xmin_for_csn = InvalidTransactionId;
 }
 
 static void
@@ -6805,6 +6807,9 @@ StartupXLOG(void)
 	if (ControlFile->track_commit_timestamp)
 		StartupCommitTs();
 
+	if(ControlFile->enable_csn_snapshot)
+		StartupCSN();
+
 	/*
 	 * Recover knowledge about replay progress of known replication partners.
 	 */
@@ -7921,6 +7926,7 @@ StartupXLOG(void)
 	 * commit timestamp.
 	 */
 	CompleteCommitTsInitialization();
+	CompleteCSNInitialization();
 
 	/*
 	 * All done with end-of-recovery actions.
@@ -9727,6 +9733,9 @@ XLogRestorePoint(const char *rpName)
 static void
 XLogReportParameters(void)
 {
+	TransactionId	xmin_for_csn = InvalidTransactionId;
+
+	xmin_for_csn = ControlFile->xmin_for_csn;
 	if (wal_level != ControlFile->wal_level ||
 		wal_log_hints != ControlFile->wal_log_hints ||
 		MaxConnections != ControlFile->MaxConnections ||
@@ -9766,11 +9775,12 @@ XLogReportParameters(void)
 			XLogFlush(recptr);
 		}
 
+		prepare_csn_env(enable_csn_snapshot,
+				enable_csn_snapshot == ControlFile->enable_csn_snapshot,
+				&xmin_for_csn);
 		LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
 
-		if (enable_csn_snapshot != ControlFile->enable_csn_snapshot)
-			set_xmin_for_csn();
-
+		ControlFile->xmin_for_csn = xmin_for_csn;
 		ControlFile->MaxConnections = MaxConnections;
 		ControlFile->max_worker_processes = max_worker_processes;
 		ControlFile->max_wal_senders = max_wal_senders;
@@ -9784,6 +9794,16 @@ XLogReportParameters(void)
 
 		LWLockRelease(ControlFileLock);
 	}
+	else
+	{
+		/*
+		 * When no GUC change, but for xmin_for_csn it should transmit the xmin_for_csn
+		 * from pg_control to csnState->xmin_for_csn. Or it will cause issue when prepare
+		 * transaction exixts and with 'xid-snapshot start  ->  csn-snapshot start  ->
+		 * csn-snapshot start' sequence.
+		 */
+		prepare_csn_env(enable_csn_snapshot, true, &xmin_for_csn);
+	}
 }
 
 /*
@@ -10212,6 +10232,8 @@ xlog_redo(XLogReaderState *record)
 		CommitTsParameterChange(xlrec.track_commit_timestamp,
 								ControlFile->track_commit_timestamp);
 		ControlFile->track_commit_timestamp = xlrec.track_commit_timestamp;
+		CSNlogParameterChange(xlrec.enable_csn_snapshot,
+								ControlFile->enable_csn_snapshot);
 		ControlFile->enable_csn_snapshot = xlrec.enable_csn_snapshot;
 
 		UpdateControlFile();
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 9283021c7b..e326b431c2 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -1734,7 +1734,7 @@ GetSnapshotData(Snapshot snapshot)
 	 * Take XidCSN under ProcArrayLock so the snapshot stays
 	 * synchronized.
 	 */
-	if (!snapshot->takenDuringRecovery && enable_csn_snapshot)
+	if (!snapshot->takenDuringRecovery && get_csnlog_status())
 		xid_csn = GenerateCSN(false);
 
 	LWLockRelease(ProcArrayLock);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1e9bcc7aee..4527dda0ee 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -1160,7 +1160,7 @@ static struct config_bool ConfigureNamesBool[] =
 			gettext_noop("Used to achieve REPEATEBLE READ isolation level for postgres_fdw transactions.")
 		},
 		&enable_csn_snapshot,
-		true, /* XXX: set true to simplify tesing. XXX2: Seems that RESOURCES_MEM isn't the best catagory */
+		false,
 		NULL, NULL, NULL
 	},
 	{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index e430e33c7b..8b02ec8200 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -296,6 +296,8 @@
 				# (change requires restart)
 #track_commit_timestamp = off	# collect timestamp of transaction commit
 				# (change requires restart)
+#enable_csn_snapshot = off	# enable csn base snapshot
+				# (change requires restart)
 
 # - Primary Server -
 
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 5fa195b913..2a31366930 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -52,6 +52,7 @@
 #include "access/transam.h"
 #include "access/xact.h"
 #include "access/xlog.h"
+#include "access/csn_log.h"
 #include "catalog/catalog.h"
 #include "lib/pairingheap.h"
 #include "miscadmin.h"
@@ -2244,7 +2245,7 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
 
 	in_snapshot = XidInLocalMVCCSnapshot(xid, snapshot);
 
-	if (!enable_csn_snapshot)
+	if (!get_csnlog_status())
 	{
 		Assert(XidCSNIsFrozen(snapshot->snapshot_csn));
 		return in_snapshot;
diff --git a/src/include/access/csn_log.h b/src/include/access/csn_log.h
index d7feca0b38..5d508caef5 100644
--- a/src/include/access/csn_log.h
+++ b/src/include/access/csn_log.h
@@ -67,6 +67,13 @@ extern void WriteAssignCSNXlogRec(XidCSN xidcsn);
 extern void set_last_max_csn(XidCSN xidcsn);
 extern void set_last_log_wal_csn(XidCSN xidcsn);
 extern XidCSN get_last_log_wal_csn(void);
-extern void set_xmin_for_csn(void);
+extern void prepare_csn_env(bool enable, bool same, TransactionId *xmin_for_csn_in_control);
+extern void CatchCSNLog(void);
+extern void ActivateCSNlog(void);
+extern void DeactivateCSNlog(void);
+extern void StartupCSN(void);
+extern void CompleteCSNInitialization(void);
+extern void CSNlogParameterChange(bool newvalue, bool oldvalue);
+extern bool get_csnlog_status(void);
 
 #endif   /* CSNLOG_H */
\ No newline at end of file
diff --git a/src/include/access/csn_snapshot.h b/src/include/access/csn_snapshot.h
index 1894586204..a768f054f5 100644
--- a/src/include/access/csn_snapshot.h
+++ b/src/include/access/csn_snapshot.h
@@ -24,17 +24,19 @@
  */
 typedef pg_atomic_uint64 CSN_atomic;
 
-#define InProgressXidCSN	 	UINT64CONST(0x0)
-#define AbortedXidCSN	 		UINT64CONST(0x1)
+#define InProgressXidCSN		UINT64CONST(0x0)
+#define AbortedXidCSN			UINT64CONST(0x1)
 #define FrozenXidCSN		 	UINT64CONST(0x2)
-#define InDoubtXidCSN	 		UINT64CONST(0x3)
-#define FirstNormalXidCSN 		UINT64CONST(0x4)
+#define InDoubtXidCSN			UINT64CONST(0x3)
+#define UnclearCSN				UINT64CONST(0x4)
+#define FirstNormalXidCSN		UINT64CONST(0x5)
 
-#define XidCSNIsInProgress(csn)	((csn) == InProgressXidCSN)
+#define XidCSNIsInProgress(csn)		((csn) == InProgressXidCSN)
 #define XidCSNIsAborted(csn)		((csn) == AbortedXidCSN)
-#define XidCSNIsFrozen(csn)		((csn) == FrozenXidCSN)
+#define XidCSNIsFrozen(csn)			((csn) == FrozenXidCSN)
 #define XidCSNIsInDoubt(csn)		((csn) == InDoubtXidCSN)
-#define XidCSNIsNormal(csn)		((csn) >= FirstNormalXidCSN)
+#define CSNIsUnclear(csn)			((csn) == UnclearCSN)
+#define XidCSNIsNormal(csn)			((csn) >= FirstNormalXidCSN)
 
 
 
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 9e5d4b0fc0..3ff7371a92 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -183,6 +183,12 @@ typedef struct ControlFileData
 	bool		track_commit_timestamp;
 	bool		enable_csn_snapshot;
 
+	/*
+	 * Used to record a xmin when database startup with a snapshot-switch to csn snapshot,
+	 * and will hold the value until it switch to xid-snapshot.
+	 */
+	TransactionId xmin_for_csn;
+
 	/*
 	 * This data is used to check for hardware-architecture compatibility of
 	 * the database and the backend executable.  We need not check endianness
diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 29de73c060..86e114e934 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -7,6 +7,7 @@ include $(top_builddir)/src/Makefile.global
 SUBDIRS = \
 		  brin \
 		  commit_ts \
+		  csnsnapshot \
 		  dummy_index_am \
 		  dummy_seclabel \
 		  snapshot_too_old \
diff --git a/src/test/modules/csnsnapshot/Makefile b/src/test/modules/csnsnapshot/Makefile
new file mode 100644
index 0000000000..45c4221cd0
--- /dev/null
+++ b/src/test/modules/csnsnapshot/Makefile
@@ -0,0 +1,18 @@
+# src/test/modules/csnsnapshot/Makefile
+
+REGRESS = csnsnapshot
+REGRESS_OPTS = --temp-config=$(top_srcdir)/src/test/modules/csnsnapshot/csn_snapshot.conf
+NO_INSTALLCHECK = 1
+
+TAP_TESTS = 1
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/csnsnapshot
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/csnsnapshot/csn_snapshot.conf b/src/test/modules/csnsnapshot/csn_snapshot.conf
new file mode 100644
index 0000000000..e9d3c35756
--- /dev/null
+++ b/src/test/modules/csnsnapshot/csn_snapshot.conf
@@ -0,0 +1 @@
+track_commit_timestamp = on
diff --git a/src/test/modules/csnsnapshot/expected/csnsnapshot.out b/src/test/modules/csnsnapshot/expected/csnsnapshot.out
new file mode 100644
index 0000000000..ac28e417b6
--- /dev/null
+++ b/src/test/modules/csnsnapshot/expected/csnsnapshot.out
@@ -0,0 +1 @@
+create table t1(i int, j int, k varchar);
diff --git a/src/test/modules/csnsnapshot/sql/csnsnapshot.sql b/src/test/modules/csnsnapshot/sql/csnsnapshot.sql
new file mode 100644
index 0000000000..91539b8c30
--- /dev/null
+++ b/src/test/modules/csnsnapshot/sql/csnsnapshot.sql
@@ -0,0 +1 @@
+create table t1(i int, j int, k varchar);
\ No newline at end of file
diff --git a/src/test/modules/csnsnapshot/t/001_base.pl b/src/test/modules/csnsnapshot/t/001_base.pl
new file mode 100644
index 0000000000..1c91f4d9f7
--- /dev/null
+++ b/src/test/modules/csnsnapshot/t/001_base.pl
@@ -0,0 +1,102 @@
+# Single-node test: value can be set, and is still present after recovery
+
+use strict;
+use warnings;
+
+use TestLib;
+use Test::More tests => 5;
+use PostgresNode;
+
+my $node = get_new_node('csntest');
+$node->init;
+$node->append_conf('postgresql.conf', qq{
+					enable_csn_snapshot = on
+					csn_snapshot_defer_time = 10
+					max_prepared_transactions = 10
+					});
+$node->start;
+
+my $test_1 = 1;
+
+# Create a table
+$node->safe_psql('postgres', 'create table t1(i int, j int)');
+
+# insert test record
+$node->safe_psql('postgres', 'insert into t1 values(1,1)');
+# export csn snapshot
+my $test_snapshot = $node->safe_psql('postgres', 'select pg_csn_snapshot_export()');
+# insert test record
+$node->safe_psql('postgres', 'insert into t1 values(2,1)');
+
+my $count1 = $node->safe_psql('postgres', "select count(*) from t1");
+is($count1, '2', 'Get right number in nomal query');
+my $count2 = $node->safe_psql('postgres', "
+			begin transaction isolation level repeatable read;
+			select pg_csn_snapshot_import($test_snapshot);
+			select count(*) from t1;
+			commit;"
+			);
+
+is($count2, '
+1', 'Get right number in csn import query');
+
+#prepare transaction test
+$node->safe_psql('postgres', "
+						begin;
+						insert into t1 values(3,1);
+						insert into t1 values(3,2);
+						prepare	transaction 'pt3';
+						");
+$node->safe_psql('postgres', "
+						begin;
+						insert into t1 values(4,1);
+						insert into t1 values(4,2);
+						prepare	transaction 'pt4';
+						");
+$node->safe_psql('postgres', "
+						begin;
+						insert into t1 values(5,1);
+						insert into t1 values(5,2);
+						prepare	transaction 'pt5';
+						");
+$node->safe_psql('postgres', "
+						begin;
+						insert into t1 values(6,1);
+						insert into t1 values(6,2);
+						prepare	transaction 'pt6';
+						");
+$node->safe_psql('postgres', "commit prepared 'pt4';");
+
+# restart with enable_csn_snapshot off
+$node->append_conf('postgresql.conf', "enable_csn_snapshot = off");
+$node->restart;
+$node->safe_psql('postgres', "
+						insert into t1 values(7,1);
+						insert into t1 values(7,2);
+						");
+$node->safe_psql('postgres', "commit prepared 'pt3';");
+$count1 = $node->safe_psql('postgres', "select count(*) from t1");
+is($count1, '8', 'Get right number in nomal query');
+
+
+# restart with enable_csn_snapshot on
+$node->append_conf('postgresql.conf', "enable_csn_snapshot = on");
+$node->restart;
+$node->safe_psql('postgres', "
+						insert into t1 values(8,1);
+						insert into t1 values(8,2);
+						");
+$node->safe_psql('postgres', "commit prepared 'pt5';");
+$count1 = $node->safe_psql('postgres', "select count(*) from t1");
+is($count1, '12', 'Get right number in nomal query');
+
+# restart with enable_csn_snapshot off
+$node->append_conf('postgresql.conf', "enable_csn_snapshot = on");
+$node->restart;
+$node->safe_psql('postgres', "
+						insert into t1 values(9,1);
+						insert into t1 values(9,2);
+						");
+$node->safe_psql('postgres', "commit prepared 'pt6';");
+$count1 = $node->safe_psql('postgres', "select count(*) from t1");
+is($count1, '16', 'Get right number in nomal query');
diff --git a/src/test/modules/csnsnapshot/t/002_standby.pl b/src/test/modules/csnsnapshot/t/002_standby.pl
new file mode 100644
index 0000000000..b7c4ea93b2
--- /dev/null
+++ b/src/test/modules/csnsnapshot/t/002_standby.pl
@@ -0,0 +1,66 @@
+# Test simple scenario involving a standby
+
+use strict;
+use warnings;
+
+use TestLib;
+use Test::More tests => 6;
+use PostgresNode;
+
+my $bkplabel = 'backup';
+my $master   = get_new_node('master');
+$master->init(allows_streaming => 1);
+
+$master->append_conf(
+	'postgresql.conf', qq{
+	enable_csn_snapshot = on
+	max_wal_senders = 5
+	});
+$master->start;
+$master->backup($bkplabel);
+
+my $standby = get_new_node('standby');
+$standby->init_from_backup($master, $bkplabel, has_streaming => 1);
+$standby->start;
+
+$master->safe_psql('postgres', "create table t1(i int, j int)");
+
+my $guc_on_master = $master->safe_psql('postgres', 'show enable_csn_snapshot');
+is($guc_on_master, 'on', "GUC on master");
+
+my $guc_on_standby = $standby->safe_psql('postgres', 'show enable_csn_snapshot');
+is($guc_on_standby, 'on', "GUC on standby");
+
+$master->append_conf('postgresql.conf', 'enable_csn_snapshot = off');
+$master->restart;
+
+$guc_on_master = $master->safe_psql('postgres', 'show enable_csn_snapshot');
+is($guc_on_master, 'off', "GUC off master");
+
+$guc_on_standby = $standby->safe_psql('postgres', 'show enable_csn_snapshot');
+is($guc_on_standby, 'on', "GUC on standby");
+
+# We consume a large number of transaction,for skip page
+for my $i (1 .. 4096) #4096
+{
+	$master->safe_psql('postgres', "insert into t1 values(1,$i)");
+}
+$master->safe_psql('postgres', "select pg_sleep(2)");
+$master->append_conf('postgresql.conf', 'enable_csn_snapshot = on');
+$master->restart;
+
+my $count_standby = $standby->safe_psql('postgres', 'select count(*) from t1');
+is($count_standby, '4096', "Ok for siwtch xid-base > csn-base"); #4096
+
+# We consume a large number of transaction,for skip page
+for my $i (1 .. 4096) #4096
+{
+	$master->safe_psql('postgres', "insert into t1 values(1,$i)");
+}
+$master->safe_psql('postgres', "select pg_sleep(2)");
+
+$master->append_conf('postgresql.conf', 'enable_csn_snapshot = off');
+$master->restart;
+
+$count_standby = $standby->safe_psql('postgres', 'select count(*) from t1');
+is($count_standby, '8192', "Ok for siwtch csn-base > xid-base"); #8192
\ No newline at end of file
diff --git a/src/test/regress/expected/sysviews.out b/src/test/regress/expected/sysviews.out
index da2e5aa38b..cc169a1999 100644
--- a/src/test/regress/expected/sysviews.out
+++ b/src/test/regress/expected/sysviews.out
@@ -73,7 +73,7 @@ select name, setting from pg_settings where name like 'enable%';
               name              | setting 
 --------------------------------+---------
  enable_bitmapscan              | on
- enable_csn_snapshot            | on
+ enable_csn_snapshot            | off
  enable_gathermerge             | on
  enable_hashagg                 | on
  enable_hashjoin                | on
