remove_VirtualXactLockTableInsert.v1.patch
application/octet-stream
Filename: remove_VirtualXactLockTableInsert.v1.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/access/transam/xact.c | 3 | 2 |
| src/backend/commands/indexcmds.c | 3 | 3 |
| src/backend/storage/ipc/procarray.c | 117 | 0 |
| src/backend/storage/ipc/standby.c | 2 | 2 |
| src/backend/storage/lmgr/lmgr.c | 0 | 64 |
| src/include/storage/lmgr.h | 0 | 5 |
| src/include/storage/procarray.h | 2 | 0 |
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 2ca1c14..0661b1c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -1694,9 +1694,10 @@ StartTransaction(void)
vxid.localTransactionId = GetNextLocalTransactionId();
/*
- * Lock the virtual transaction id before we announce it in the proc array
+ * Prior to 9.1 we used to create a lock table entry for the vxid, but
+ * that was only needed by a few operations, so its cheaper overall
+ * to avoid this and perform the waits another way.
*/
- VirtualXactLockTableInsert(vxid);
/*
* Advertise it in the proc array. We assume assignment of
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b91e4a4..b2531d1 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -481,7 +481,7 @@ DefineIndex(RangeVar *heapRelation,
while (VirtualTransactionIdIsValid(*old_lockholders))
{
- VirtualXactLockTableWait(*old_lockholders);
+ VirtualXactWait(*old_lockholders);
old_lockholders++;
}
@@ -567,7 +567,7 @@ DefineIndex(RangeVar *heapRelation,
while (VirtualTransactionIdIsValid(*old_lockholders))
{
- VirtualXactLockTableWait(*old_lockholders);
+ VirtualXactWait(*old_lockholders);
old_lockholders++;
}
@@ -664,7 +664,7 @@ DefineIndex(RangeVar *heapRelation,
}
if (VirtualTransactionIdIsValid(old_snapshots[i]))
- VirtualXactLockTableWait(old_snapshots[i]);
+ VirtualXactWait(old_snapshots[i]);
}
/*
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index e7593fa..9fef532 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -51,10 +51,12 @@
#include "access/xact.h"
#include "access/twophase.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "storage/procarray.h"
#include "storage/spin.h"
#include "storage/standby.h"
#include "utils/builtins.h"
+#include "utils/ps_status.h"
#include "utils/snapmgr.h"
@@ -1862,6 +1864,121 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
}
/*
+ * VirtualXactExists
+ *
+ * Does the VXID still exist? Could also be called ConditionalVirtualXactWait()
+ * but that doesn't describe this very well.
+ */
+bool
+VirtualXactExists(VirtualTransactionId vxid)
+{
+ ProcArrayStruct *arrayP = procArray;
+ int index;
+ bool found = false;
+
+ /* Fast exit, to avoid overhead if there's no work to be done. */
+ if (!VirtualTransactionIdIsValid(vxid))
+ return false;
+
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ VirtualTransactionId procvxid;
+ PGPROC *proc = arrayP->procs[index];
+
+ GET_VXID_FROM_PGPROC(procvxid, *proc);
+
+ if (procvxid.backendId == vxid.backendId &&
+ procvxid.localTransactionId == vxid.localTransactionId)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ LWLockRelease(ProcArrayLock);
+
+ return found;
+}
+
+/*
+ * VirtualXactWait
+ *
+ * Waits until the top-level transaction owning the VXID has ended.
+ * We don't use latches to allow us to have multiple waiters on a VXID.
+ */
+void
+VirtualXactWait(VirtualTransactionId vxid)
+{
+#define INITIAL_WAIT_US 1000
+ int wait_us = INITIAL_WAIT_US;
+ TimestampTz waitStart;
+ char *new_status;
+ bool reported = false;
+
+ /* Fast exit, to avoid a kernel call if there's no work to be done. */
+ if (!VirtualTransactionIdIsValid(vxid))
+ return;
+
+ waitStart = GetCurrentTimestamp();
+ new_status = NULL; /* we haven't changed the ps display */
+
+ /* wait until the virtual xid is gone */
+ while (VirtualXactExists(vxid))
+ {
+ if (!reported)
+ {
+ pgstat_report_waiting(true);
+ reported = true;
+ }
+
+ /*
+ * Report via ps if we have been waiting for more than 500 msec
+ * (should that be configurable?)
+ */
+ if (update_process_title && new_status == NULL &&
+ TimestampDifferenceExceeds(waitStart, GetCurrentTimestamp(),
+ 500))
+ {
+ const char *old_status;
+ int len;
+
+ old_status = get_ps_display(&len);
+ new_status = (char *) palloc(len + 8 + 1);
+ memcpy(new_status, old_status, len);
+ strcpy(new_status + len, " waiting");
+ set_ps_display(new_status, false);
+ new_status[len] = '\0'; /* truncate off " waiting" */
+
+ pgstat_report_waiting(true);
+ }
+
+ CHECK_FOR_INTERRUPTS();
+
+ pg_usleep(wait_us);
+
+ /*
+ * Progressively increase the sleep times, but not to more than 1s, since
+ * pg_usleep isn't interruptable on some platforms.
+ */
+ wait_us *= 2;
+ if (wait_us > 1000000)
+ wait_us = 1000000;
+ }
+
+ /* Reset ps display if we changed it */
+ if (new_status)
+ {
+ set_ps_display(new_status, false);
+ pfree(new_status);
+ }
+
+ if (reported)
+ pgstat_report_waiting(false);
+}
+
+/*
* CancelVirtualTransaction - used in recovery conflict processing
*
* Returns pid of the process signaled, or 0 if not found.
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 75b5ab4..52824f3 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -82,7 +82,7 @@ InitRecoveryTransactionEnvironment(void)
*/
vxid.backendId = MyBackendId;
vxid.localTransactionId = GetNextLocalTransactionId();
- VirtualXactLockTableInsert(vxid);
+ MyProc->lxid = vxid.localTransactionId;
standbyState = STANDBY_INITIALIZED;
}
@@ -201,7 +201,7 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
standbyWait_us = STANDBY_INITIAL_WAIT_US;
/* wait until the virtual xid is gone */
- while (!ConditionalVirtualXactLockTableWait(*waitlist))
+ while (VirtualXactExists(*waitlist))
{
/*
* Report via ps if we have been waiting for more than 500 msec
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 859b385..9d0994e 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -514,70 +514,6 @@ ConditionalXactLockTableWait(TransactionId xid)
return true;
}
-
-/*
- * VirtualXactLockTableInsert
- *
- * Insert a lock showing that the given virtual transaction ID is running ---
- * this is done at main transaction start when its VXID is assigned.
- * The lock can then be used to wait for the transaction to finish.
- */
-void
-VirtualXactLockTableInsert(VirtualTransactionId vxid)
-{
- LOCKTAG tag;
-
- Assert(VirtualTransactionIdIsValid(vxid));
-
- SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
-
- (void) LockAcquire(&tag, ExclusiveLock, false, false);
-}
-
-/*
- * VirtualXactLockTableWait
- *
- * Waits until the lock on the given VXID is released, which shows that
- * the top-level transaction owning the VXID has ended.
- */
-void
-VirtualXactLockTableWait(VirtualTransactionId vxid)
-{
- LOCKTAG tag;
-
- Assert(VirtualTransactionIdIsValid(vxid));
-
- SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
-
- (void) LockAcquire(&tag, ShareLock, false, false);
-
- LockRelease(&tag, ShareLock, false);
-}
-
-/*
- * ConditionalVirtualXactLockTableWait
- *
- * As above, but only lock if we can get the lock without blocking.
- * Returns TRUE if the lock was acquired.
- */
-bool
-ConditionalVirtualXactLockTableWait(VirtualTransactionId vxid)
-{
- LOCKTAG tag;
-
- Assert(VirtualTransactionIdIsValid(vxid));
-
- SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
-
- if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
- return false;
-
- LockRelease(&tag, ShareLock, false);
-
- return true;
-}
-
-
/*
* LockDatabaseObject
*
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index bd44d92..340f6a3 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -56,11 +56,6 @@ extern void XactLockTableDelete(TransactionId xid);
extern void XactLockTableWait(TransactionId xid);
extern bool ConditionalXactLockTableWait(TransactionId xid);
-/* Lock a VXID (used to wait for a transaction to finish) */
-extern void VirtualXactLockTableInsert(VirtualTransactionId vxid);
-extern void VirtualXactLockTableWait(VirtualTransactionId vxid);
-extern bool ConditionalVirtualXactLockTableWait(VirtualTransactionId vxid);
-
/* Lock a general object (other than a relation) of the current database */
extern void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode);
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index 3c20fc4..ce3b562 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -58,6 +58,8 @@ extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin,
bool excludeXmin0, bool allDbs, int excludeVacuum,
int *nvxids);
extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid);
+extern bool VirtualXactExists(VirtualTransactionId vxid);
+extern void VirtualXactWait(VirtualTransactionId vxid);
extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode);
extern bool MinimumActiveBackends(int min);