From e85662df44ff47acdf5d2d413339445d60a9c30c Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Thu, 14 Mar 2024 13:08:53 +0200 Subject: Fix false reports in pg_visibility Currently, pg_visibility computes its xid horizon using the GetOldestNonRemovableTransactionId(). The problem is that this horizon can sometimes go backward. That can lead to reporting false errors. In order to fix that, this commit implements a new function GetStrictOldestNonRemovableTransactionId(). This function computes the xid horizon, which would be guaranteed to be newer or equal to any xid horizon computed before. We have to do the following to achieve this. 1. Ignore processes xmin's, because they consider connection to other databases that were ignored before. 2. Ignore KnownAssignedXids, because they are not database-aware. At the same time, the primary could compute its horizons database-aware. 3. Ignore walsender xmin, because it could go backward if some replication connections don't use replication slots. As a result, we're using only currently running xids to compute the horizon. Surely these would significantly sacrifice accuracy. But we have to do so to avoid reporting false errors. Inspired by earlier patch by Daniel Shelepanov and the following discussion with Robert Haas and Tom Lane. Discussion: https://postgr.es/m/1649062270.289865713%40f403.i.mail.ru Reviewed-by: Alexander Lakhin, Dmitry Koval --- src/backend/storage/ipc/procarray.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/backend') diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 9eea1ed315a..b3cd248fb64 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -2688,6 +2688,7 @@ GetRunningTransactionData(void) RunningTransactions CurrentRunningXacts = &CurrentRunningXactsData; TransactionId latestCompletedXid; TransactionId oldestRunningXid; + TransactionId oldestDatabaseRunningXid; TransactionId *xids; int index; int count; @@ -2732,7 +2733,7 @@ GetRunningTransactionData(void) latestCompletedXid = XidFromFullTransactionId(TransamVariables->latestCompletedXid); - oldestRunningXid = + oldestDatabaseRunningXid = oldestRunningXid = XidFromFullTransactionId(TransamVariables->nextXid); /* @@ -2740,6 +2741,8 @@ GetRunningTransactionData(void) */ for (index = 0; index < arrayP->numProcs; index++) { + int pgprocno = arrayP->pgprocnos[index]; + PGPROC *proc = &allProcs[pgprocno]; TransactionId xid; /* Fetch xid just once - see GetNewTransactionId */ @@ -2760,6 +2763,13 @@ GetRunningTransactionData(void) if (TransactionIdPrecedes(xid, oldestRunningXid)) oldestRunningXid = xid; + /* + * Also, update the oldest running xid within the current database. + */ + if (proc->databaseId == MyDatabaseId && + TransactionIdPrecedes(xid, oldestRunningXid)) + oldestDatabaseRunningXid = xid; + if (ProcGlobal->subxidStates[index].overflowed) suboverflowed = true; @@ -2826,6 +2836,7 @@ GetRunningTransactionData(void) CurrentRunningXacts->subxid_overflow = suboverflowed; CurrentRunningXacts->nextXid = XidFromFullTransactionId(TransamVariables->nextXid); CurrentRunningXacts->oldestRunningXid = oldestRunningXid; + CurrentRunningXacts->oldestDatabaseRunningXid = oldestDatabaseRunningXid; CurrentRunningXacts->latestCompletedXid = latestCompletedXid; Assert(TransactionIdIsValid(CurrentRunningXacts->nextXid)); -- cgit v1.2.3