diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c new file mode 100644 index 9a758bd..bded11e *** a/src/backend/storage/lmgr/proc.c --- b/src/backend/storage/lmgr/proc.c *************** int StatementTimeout = 0; *** 60,65 **** --- 60,66 ---- int LockTimeout = 0; int IdleInTransactionSessionTimeout = 0; bool log_lock_waits = false; + bool notice_lock_waits = false; /* Pointer to this process's PGPROC and PGXACT structs, if any */ PGPROC *MyProc = NULL; *************** ProcSleep(LOCALLOCK *locallock, LockMeth *** 1307,1313 **** * If awoken after the deadlock check interrupt has run, and * log_lock_waits is on, then report about the wait. */ ! if (log_lock_waits && deadlock_state != DS_NOT_YET_CHECKED) { StringInfoData buf, lock_waiters_sbuf, --- 1308,1314 ---- * If awoken after the deadlock check interrupt has run, and * log_lock_waits is on, then report about the wait. */ ! if ((log_lock_waits || notice_lock_waits) && deadlock_state != DS_NOT_YET_CHECKED) { StringInfoData buf, lock_waiters_sbuf, *************** ProcSleep(LOCALLOCK *locallock, LockMeth *** 1389,1448 **** LWLockRelease(partitionLock); ! if (deadlock_state == DS_SOFT_DEADLOCK) ! ereport(LOG, ! (errmsg("process %d avoided deadlock for %s on %s by rearranging queue order after %ld.%03d ms", ! MyProcPid, modename, buf.data, msecs, usecs), ! (errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.", ! "Processes holding the lock: %s. Wait queue: %s.", ! lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data)))); ! else if (deadlock_state == DS_HARD_DEADLOCK) ! { ! /* ! * This message is a bit redundant with the error that will be ! * reported subsequently, but in some cases the error report ! * might not make it to the log (eg, if it's caught by an ! * exception handler), and we want to ensure all long-wait ! * events get logged. ! */ ! ereport(LOG, ! (errmsg("process %d detected deadlock while waiting for %s on %s after %ld.%03d ms", ! MyProcPid, modename, buf.data, msecs, usecs), ! (errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.", ! "Processes holding the lock: %s. Wait queue: %s.", ! lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data)))); ! } ! ! if (myWaitStatus == STATUS_WAITING) ! ereport(LOG, (errmsg("process %d still waiting for %s on %s after %ld.%03d ms", ! MyProcPid, modename, buf.data, msecs, usecs), ! (errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.", ! "Processes holding the lock: %s. Wait queue: %s.", ! lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data)))); ! else if (myWaitStatus == STATUS_OK) ! ereport(LOG, (errmsg("process %d acquired %s on %s after %ld.%03d ms", MyProcPid, modename, buf.data, msecs, usecs))); ! else { ! Assert(myWaitStatus == STATUS_ERROR); ! /* ! * Currently, the deadlock checker always kicks its own ! * process, which means that we'll only see STATUS_ERROR when ! * deadlock_state == DS_HARD_DEADLOCK, and there's no need to ! * print redundant messages. But for completeness and ! * future-proofing, print a message if it looks like someone ! * else kicked us off the lock. ! */ ! if (deadlock_state != DS_HARD_DEADLOCK) ereport(LOG, ! (errmsg("process %d failed to acquire %s on %s after %ld.%03d ms", ! MyProcPid, modename, buf.data, msecs, usecs), (errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.", ! "Processes holding the lock: %s. Wait queue: %s.", lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data)))); } /* --- 1390,1462 ---- LWLockRelease(partitionLock); ! if (notice_lock_waits && myWaitStatus == STATUS_WAITING) ! ereport(NOTICE, (errmsg("process %d still waiting for %s on %s after %ld.%03d ms", ! MyProcPid, modename, buf.data, msecs, usecs))); ! ! if (notice_lock_waits && myWaitStatus == STATUS_OK) ! ereport(NOTICE, (errmsg("process %d acquired %s on %s after %ld.%03d ms", MyProcPid, modename, buf.data, msecs, usecs))); ! ! if (log_lock_waits) { ! if (deadlock_state == DS_SOFT_DEADLOCK) ! ereport(LOG, ! (errmsg("process %d avoided deadlock for %s on %s by rearranging queue order after %ld.%03d ms", ! MyProcPid, modename, buf.data, msecs, usecs), ! (errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.", ! "Processes holding the lock: %s. Wait queue: %s.", ! lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data)))); ! else if (deadlock_state == DS_HARD_DEADLOCK) ! { ! /* ! * This message is a bit redundant with the error that will be ! * reported subsequently, but in some cases the error report ! * might not make it to the log (eg, if it's caught by an ! * exception handler), and we want to ensure all long-wait ! * events get logged. ! */ ! ereport(LOG, ! (errmsg("process %d detected deadlock while waiting for %s on %s after %ld.%03d ms", ! MyProcPid, modename, buf.data, msecs, usecs), ! (errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.", ! "Processes holding the lock: %s. Wait queue: %s.", ! lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data)))); ! } ! if (myWaitStatus == STATUS_WAITING) ereport(LOG, ! (errmsg("process %d still waiting for %s on %s after %ld.%03d ms", ! MyProcPid, modename, buf.data, msecs, usecs), (errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.", ! "Processes holding the lock: %s. Wait queue: %s.", lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data)))); + else if (myWaitStatus == STATUS_OK) + ereport(LOG, + (errmsg("process %d acquired %s on %s after %ld.%03d ms", + MyProcPid, modename, buf.data, msecs, usecs))); + else + { + Assert(myWaitStatus == STATUS_ERROR); + + /* + * Currently, the deadlock checker always kicks its own + * process, which means that we'll only see STATUS_ERROR when + * deadlock_state == DS_HARD_DEADLOCK, and there's no need to + * print redundant messages. But for completeness and + * future-proofing, print a message if it looks like someone + * else kicked us off the lock. + */ + if (deadlock_state != DS_HARD_DEADLOCK) + ereport(LOG, + (errmsg("process %d failed to acquire %s on %s after %ld.%03d ms", + MyProcPid, modename, buf.data, msecs, usecs), + (errdetail_log_plural("Process holding the lock: %s. Wait queue: %s.", + "Processes holding the lock: %s. Wait queue: %s.", + lockHoldersNum, lock_holders_sbuf.data, lock_waiters_sbuf.data)))); + } } /* diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c new file mode 100644 index 9c93df0..fc453b0 *** a/src/backend/utils/misc/guc.c --- b/src/backend/utils/misc/guc.c *************** static struct config_bool ConfigureNames *** 1289,1294 **** --- 1289,1304 ---- }, { + {"notice_lock_waits", PGC_USERSET, LOGGING_WHAT, + gettext_noop("Issues NOTICES for long lock waits."), + NULL + }, + ¬ice_lock_waits, + false, + NULL, NULL, NULL + }, + + { {"log_hostname", PGC_SIGHUP, LOGGING_WHAT, gettext_noop("Logs the host name in the connection logs."), gettext_noop("By default, connection logs only show the IP address " diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h new file mode 100644 index 775c66a..9e06ffc *** a/src/include/storage/proc.h --- b/src/include/storage/proc.h *************** extern int StatementTimeout; *** 260,265 **** --- 260,266 ---- extern int LockTimeout; extern int IdleInTransactionSessionTimeout; extern bool log_lock_waits; + extern bool notice_lock_waits; /*