diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index 556b7fcba38..a1fd1d92d63 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -566,11 +566,18 @@ SnapBuildInitialSnapshot(SnapBuild *builder) { Snapshot snap; TransactionId xid; + TransactionId safeXid; TransactionId *newxip; int newxcnt = 0; - Assert(!FirstSnapshotSet); Assert(XactIsoLevel == XACT_REPEATABLE_READ); + Assert(builder->building_full_snapshot); + + /* don't allow older snapshots */ + InvalidateCatalogSnapshot(); /* about to overwrite MyProc->xmin */ + if (HaveRegisteredOrActiveSnapshot()) + elog(ERROR, "cannot build an initial slot snapshot when snapshots exist"); + Assert(!HistoricSnapshotActive()); if (builder->state != SNAPBUILD_CONSISTENT) elog(ERROR, "cannot build an initial slot snapshot before reaching a consistent state"); @@ -588,18 +595,18 @@ SnapBuildInitialSnapshot(SnapBuild *builder) * We know that snap->xmin is alive, enforced by the logical xmin * mechanism. Due to that we can do this without locks, we're only * changing our own value. + * + * Building an initial snapshot is expensive and an unenforced xmin + * horizon would have bad consequences, therefore always double-check that + * the horizon is enforced. */ -#ifdef USE_ASSERT_CHECKING - { - TransactionId safeXid; + LWLockAcquire(ProcArrayLock, LW_SHARED); + safeXid = GetOldestSafeDecodingTransactionId(false); + LWLockRelease(ProcArrayLock); - LWLockAcquire(ProcArrayLock, LW_SHARED); - safeXid = GetOldestSafeDecodingTransactionId(false); - LWLockRelease(ProcArrayLock); - - Assert(TransactionIdPrecedesOrEquals(safeXid, snap->xmin)); - } -#endif + if (TransactionIdFollows(safeXid, snap->xmin)) + elog(ERROR, "cannot build an initial slot snapshot as oldest safe xid %u follows snapshot's xmin %u", + safeXid, snap->xmin); MyProc->xmin = snap->xmin; diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index a81ef6a2014..c11bb3716f4 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -1099,6 +1099,11 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd) /*- translator: %s is a CREATE_REPLICATION_SLOT statement */ (errmsg("%s must be called in REPEATABLE READ isolation mode transaction", "CREATE_REPLICATION_SLOT ... (SNAPSHOT 'use')"))); + if (!XactReadOnly) + ereport(ERROR, + /*- translator: %s is a CREATE_REPLICATION_SLOT statement */ + (errmsg("%s must be called in a read only transaction", + "CREATE_REPLICATION_SLOT ... (SNAPSHOT 'use')"))); if (FirstSnapshotSet) ereport(ERROR,