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);