summaryrefslogtreecommitdiff
path: root/src/backend/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access')
-rw-r--r--src/backend/access/heap/heapam.c3
-rw-r--r--src/backend/access/heap/heapam_xlog.c1
-rw-r--r--src/backend/access/heap/vacuumlazy.c14
-rw-r--r--src/backend/access/transam/twophase.c61
-rw-r--r--src/backend/access/transam/xlog.c16
5 files changed, 87 insertions, 8 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index e3e7307ef5f..4c5ae205a7a 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2647,9 +2647,6 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
*/
if (all_frozen_set)
{
- Assert(PageIsAllVisible(page));
- Assert(visibilitymap_pin_ok(BufferGetBlockNumber(buffer), vmbuffer));
-
/*
* It's fine to use InvalidTransactionId here - this is only used
* when HEAP_INSERT_FROZEN is specified, which intentionally
diff --git a/src/backend/access/heap/heapam_xlog.c b/src/backend/access/heap/heapam_xlog.c
index 5d48f071f53..cf843277938 100644
--- a/src/backend/access/heap/heapam_xlog.c
+++ b/src/backend/access/heap/heapam_xlog.c
@@ -295,7 +295,6 @@ heap_xlog_visible(XLogReaderState *record)
LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
reln = CreateFakeRelcacheEntry(rlocator);
- visibilitymap_pin(reln, blkno, &vmbuffer);
visibilitymap_set(reln, blkno, InvalidBuffer, lsn, vmbuffer,
xlrec->snapshotConflictHorizon, vmbits);
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 932701d8420..981d9380a92 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -2121,8 +2121,11 @@ lazy_scan_prune(LVRelState *vacrel,
else if (all_visible_according_to_vm && !PageIsAllVisible(page) &&
visibilitymap_get_status(vacrel->rel, blkno, &vmbuffer) != 0)
{
- elog(WARNING, "page is not marked all-visible but visibility map bit is set in relation \"%s\" page %u",
- vacrel->relname, blkno);
+ ereport(WARNING,
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("page is not marked all-visible but visibility map bit is set in relation \"%s\" page %u",
+ vacrel->relname, blkno)));
+
visibilitymap_clear(vacrel->rel, blkno, vmbuffer,
VISIBILITYMAP_VALID_BITS);
}
@@ -2143,8 +2146,11 @@ lazy_scan_prune(LVRelState *vacrel,
*/
else if (presult.lpdead_items > 0 && PageIsAllVisible(page))
{
- elog(WARNING, "page containing LP_DEAD items is marked as all-visible in relation \"%s\" page %u",
- vacrel->relname, blkno);
+ ereport(WARNING,
+ (errcode(ERRCODE_DATA_CORRUPTED),
+ errmsg("page containing LP_DEAD items is marked as all-visible in relation \"%s\" page %u",
+ vacrel->relname, blkno)));
+
PageClearAllVisible(page);
MarkBufferDirty(buf);
visibilitymap_clear(vacrel->rel, blkno, vmbuffer,
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 7918176fc58..d8e2fce2c99 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -103,6 +103,7 @@
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
+#include "utils/injection_point.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
@@ -2332,12 +2333,17 @@ RecordTransactionCommitPrepared(TransactionId xid,
replorigin = (replorigin_session_origin != InvalidRepOriginId &&
replorigin_session_origin != DoNotReplicateId);
+ /* Load the injection point before entering the critical section */
+ INJECTION_POINT_LOAD("commit-after-delay-checkpoint");
+
START_CRIT_SECTION();
/* See notes in RecordTransactionCommit */
Assert((MyProc->delayChkptFlags & DELAY_CHKPT_IN_COMMIT) == 0);
MyProc->delayChkptFlags |= DELAY_CHKPT_IN_COMMIT;
+ INJECTION_POINT_CACHED("commit-after-delay-checkpoint", NULL);
+
/*
* Ensures the DELAY_CHKPT_IN_COMMIT flag write is globally visible before
* commit time is written.
@@ -2809,3 +2815,58 @@ LookupGXactBySubid(Oid subid)
return found;
}
+
+/*
+ * TwoPhaseGetXidByLockingProc
+ * Return the oldest transaction ID from prepared transactions that are
+ * currently in the commit critical section.
+ *
+ * This function only considers transactions in the currently connected
+ * database. If no matching transactions are found, it returns
+ * InvalidTransactionId.
+ */
+TransactionId
+TwoPhaseGetOldestXidInCommit(void)
+{
+ TransactionId oldestRunningXid = InvalidTransactionId;
+
+ LWLockAcquire(TwoPhaseStateLock, LW_SHARED);
+
+ for (int i = 0; i < TwoPhaseState->numPrepXacts; i++)
+ {
+ GlobalTransaction gxact = TwoPhaseState->prepXacts[i];
+ PGPROC *commitproc;
+ TransactionId xid;
+
+ if (!gxact->valid)
+ continue;
+
+ if (gxact->locking_backend == INVALID_PROC_NUMBER)
+ continue;
+
+ /*
+ * Get the backend that is handling the transaction. It's safe to
+ * access this backend while holding TwoPhaseStateLock, as the backend
+ * can only be destroyed after either removing or unlocking the
+ * current global transaction, both of which require an exclusive
+ * TwoPhaseStateLock.
+ */
+ commitproc = GetPGProcByNumber(gxact->locking_backend);
+
+ if (MyDatabaseId != commitproc->databaseId)
+ continue;
+
+ if ((commitproc->delayChkptFlags & DELAY_CHKPT_IN_COMMIT) == 0)
+ continue;
+
+ xid = XidFromFullTransactionId(gxact->fxid);
+
+ if (!TransactionIdIsValid(oldestRunningXid) ||
+ TransactionIdPrecedes(xid, oldestRunningXid))
+ oldestRunningXid = xid;
+ }
+
+ LWLockRelease(TwoPhaseStateLock);
+
+ return oldestRunningXid;
+}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7ffb2179151..0baf0ac6160 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -8385,6 +8385,14 @@ xlog_redo(XLogReaderState *record)
checkPoint.ThisTimeLineID, replayTLI)));
RecoveryRestartPoint(&checkPoint, record);
+
+ /*
+ * After replaying a checkpoint record, free all smgr objects.
+ * Otherwise we would never do so for dropped relations, as the
+ * startup does not process shared invalidation messages or call
+ * AtEOXact_SMgr().
+ */
+ smgrdestroyall();
}
else if (info == XLOG_CHECKPOINT_ONLINE)
{
@@ -8438,6 +8446,14 @@ xlog_redo(XLogReaderState *record)
checkPoint.ThisTimeLineID, replayTLI)));
RecoveryRestartPoint(&checkPoint, record);
+
+ /*
+ * After replaying a checkpoint record, free all smgr objects.
+ * Otherwise we would never do so for dropped relations, as the
+ * startup does not process shared invalidation messages or call
+ * AtEOXact_SMgr().
+ */
+ smgrdestroyall();
}
else if (info == XLOG_OVERWRITE_CONTRECORD)
{