diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/transam/twophase.c | 9 | ||||
-rw-r--r-- | src/backend/storage/ipc/standby.c | 24 | ||||
-rw-r--r-- | src/backend/storage/lmgr/lock.c | 8 | ||||
-rw-r--r-- | src/backend/storage/lmgr/proc.c | 20 | ||||
-rw-r--r-- | src/backend/utils/adt/lockfuncs.c | 9 |
5 files changed, 67 insertions, 3 deletions
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index fc18b778324..70d22577cee 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -873,8 +873,15 @@ PGPROC * TwoPhaseGetDummyProc(TransactionId xid, bool lock_held) { GlobalTransaction gxact = TwoPhaseGetGXact(xid, lock_held); + PGPROC *dummy = &ProcGlobal->allProcs[gxact->pgprocno]; - return &ProcGlobal->allProcs[gxact->pgprocno]; + /* + * Initialize atomic variable in dummy proc so that GetLockStatusData() + * can read it later. + */ + pg_atomic_init_u64(&dummy->waitStart, 0); + + return dummy; } /************************************************************************/ diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 39a30c00f7a..5877a60715f 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -540,12 +540,34 @@ void ResolveRecoveryConflictWithLock(LOCKTAG locktag, bool logging_conflict) { TimestampTz ltime; + TimestampTz now; Assert(InHotStandby); ltime = GetStandbyLimitTime(); + now = GetCurrentTimestamp(); - if (GetCurrentTimestamp() >= ltime && ltime != 0) + /* + * Update waitStart if first time through after the startup process + * started waiting for the lock. It should not be updated every time + * ResolveRecoveryConflictWithLock() is called during the wait. + * + * Use the current time obtained for comparison with ltime as waitStart + * (i.e., the time when this process started waiting for the lock). Since + * getting the current time newly can cause overhead, we reuse the + * already-obtained time to avoid that overhead. + * + * Note that waitStart is updated without holding the lock table's + * partition lock, to avoid the overhead by additional lock acquisition. + * This can cause "waitstart" in pg_locks to become NULL for a very short + * period of time after the wait started even though "granted" is false. + * This is OK in practice because we can assume that users are likely to + * look at "waitstart" when waiting for the lock for a long time. + */ + if (pg_atomic_read_u64(&MyProc->waitStart) == 0) + pg_atomic_write_u64(&MyProc->waitStart, now); + + if (now >= ltime && ltime != 0) { /* * We're already behind, so clear a path as quickly as possible. diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 79c1cf9b8b4..108b4d90238 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -3619,6 +3619,12 @@ GetLockStatusData(void) instance->leaderPid = proc->pid; instance->fastpath = true; + /* + * Successfully taking fast path lock means there were no + * conflicting locks. + */ + instance->waitStart = 0; + el++; } @@ -3646,6 +3652,7 @@ GetLockStatusData(void) instance->pid = proc->pid; instance->leaderPid = proc->pid; instance->fastpath = true; + instance->waitStart = 0; el++; } @@ -3698,6 +3705,7 @@ GetLockStatusData(void) instance->pid = proc->pid; instance->leaderPid = proclock->groupLeader->pid; instance->fastpath = false; + instance->waitStart = (TimestampTz) pg_atomic_read_u64(&proc->waitStart); el++; } diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index c87ffc65491..0884909a220 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -402,6 +402,7 @@ InitProcess(void) MyProc->lwWaitMode = 0; MyProc->waitLock = NULL; MyProc->waitProcLock = NULL; + pg_atomic_init_u64(&MyProc->waitStart, 0); #ifdef USE_ASSERT_CHECKING { int i; @@ -580,6 +581,7 @@ InitAuxiliaryProcess(void) MyProc->lwWaitMode = 0; MyProc->waitLock = NULL; MyProc->waitProcLock = NULL; + pg_atomic_init_u64(&MyProc->waitStart, 0); #ifdef USE_ASSERT_CHECKING { int i; @@ -1262,6 +1264,23 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) } else enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout); + + /* + * Use the current time obtained for the deadlock timeout timer as + * waitStart (i.e., the time when this process started waiting for the + * lock). Since getting the current time newly can cause overhead, we + * reuse the already-obtained time to avoid that overhead. + * + * Note that waitStart is updated without holding the lock table's + * partition lock, to avoid the overhead by additional lock + * acquisition. This can cause "waitstart" in pg_locks to become NULL + * for a very short period of time after the wait started even though + * "granted" is false. This is OK in practice because we can assume + * that users are likely to look at "waitstart" when waiting for the + * lock for a long time. + */ + pg_atomic_write_u64(&MyProc->waitStart, + get_timeout_start_time(DEADLOCK_TIMEOUT)); } else if (log_recovery_conflict_waits) { @@ -1678,6 +1697,7 @@ ProcWakeup(PGPROC *proc, ProcWaitStatus waitStatus) proc->waitLock = NULL; proc->waitProcLock = NULL; proc->waitStatus = waitStatus; + pg_atomic_write_u64(&MyProc->waitStart, 0); /* And awaken it */ SetLatch(&proc->procLatch); diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index b1cf5b79a75..97f0265c12d 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -63,7 +63,7 @@ typedef struct } PG_Lock_Status; /* Number of columns in pg_locks output */ -#define NUM_LOCK_STATUS_COLUMNS 15 +#define NUM_LOCK_STATUS_COLUMNS 16 /* * VXIDGetDatum - Construct a text representation of a VXID @@ -142,6 +142,8 @@ pg_lock_status(PG_FUNCTION_ARGS) BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath", BOOLOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart", + TIMESTAMPTZOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); @@ -336,6 +338,10 @@ pg_lock_status(PG_FUNCTION_ARGS) values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode)); values[13] = BoolGetDatum(granted); values[14] = BoolGetDatum(instance->fastpath); + if (!granted && instance->waitStart != 0) + values[15] = TimestampTzGetDatum(instance->waitStart); + else + nulls[15] = true; tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); @@ -406,6 +412,7 @@ pg_lock_status(PG_FUNCTION_ARGS) values[12] = CStringGetTextDatum("SIReadLock"); values[13] = BoolGetDatum(true); values[14] = BoolGetDatum(false); + nulls[15] = true; tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); |