diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index 43c7fc9..9f4efc3 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -496,7 +496,7 @@ pgfdw_get_result(PGconn *conn, const char *query) wc = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_SOCKET_READABLE, PQsocket(conn), - -1L); + -1L, LATCH_EXTENSION); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 2b2f7e3..f7f3a59 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -679,6 +679,16 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser buffer in question. + + + Latch: The server process is waiting for a latch. + Latch is an inter-process facility using boolean variables letting + a process sleep until it is set. Latches support several type of + operations, like postmaster death handling, timeout and socket + activity lookup, and are a useful replacement for sleep + where signal handling matters. + + @@ -1081,6 +1091,131 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser BufferPin Waiting to acquire a pin on a buffer. + + Latch + ArchiverMain + Waiting in main loop of the archiver process. + + + AutoVacuumMain + Waiting in main loop of autovacuum launcher process. + + + BaseBackupThrottle + Waiting during base backup when throttling activity. + + + BgWorkerStartup + Waiting for background worker to start up. + + + BgWorkerShutdown + Waiting for background worker to shut down. + + + BgWriterMain + Waiting in main loop of background writer process background worker. + + + BgWriterHibernate + Waiting in background writer process, hibernating. + + + CheckpointerMain + Waiting in main loop of checkpointer process. + + + ExecuteGather + Waiting for activity from child process when executing Gather node. + + + Extension + Waiting in the code path of an extension, should be used by custom plugins and modules + + + MessageQueuePutMessage + Waiting to put new message in shared message queue. + + + MessageQueueSend + Waiting to send bytes in shared message queue. + + + MessageQueueReceive + Waiting to receive bytes in shared message queue. + + + MessageQueueInternal + Waiting for other process to be attached in shared message queue. + + + ParallelFinish + Waiting for parallel workers to finish computing. + + + PGSleep + Waiting in process that called pg_sleep. + + + PGStatMain + Waiting in main loop of the statistics collector process. + + + ProcSleep + Waiting for a specific lock. + + + ProcSignal + Waiting for signal from another backend. + + + RecoveryApplyDelay + Waiting to apply WAL at recovery because it is delayed. + + + RecoveryWALStream + Waiting for WAL from a stram at recovery. + + + RecoveryWALAll + Waiting for WAL from any kind of source (local, archive or stream) at recovery. + + + SSLOpenServer + Waiting for SSL while attempting connection. + + + SyncRep + Waiting for WAL commit during synchronous replication. + + + SysLoggerMain + Waiting in main loop of syslogger process. + + + WALWriterMain + Waiting in main loop of WAL writer process. + + + WALReceiverWaitStart + Waiting for startup process to send initial data for streaming replication. + + + WALReceiverMain + Waiting in main loop of WAL receiver process. + + + WALSenderMain + Waiting in main loop of WAL sender process. + + + WALSenderWaitForWAL + Waiting for WAL to be flushed in WAL sender process. + + + WALSenderWriteData + Waiting for any activity when processing replies from WAL receiver in WAL sender process. + diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index 934dba8..13805da 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -534,7 +534,8 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt) if (!anyone_alive) break; - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, -1); + WaitLatch(&MyProc->procLatch, WL_LATCH_SET, -1, + LATCH_PARALLEL_WAIT_FINISH); ResetLatch(&MyProc->procLatch); } diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b473f19..a1afff9 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -5758,7 +5758,8 @@ recoveryApplyDelay(XLogReaderState *record) WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - secs * 1000L + microsecs / 1000); + secs * 1000L + microsecs / 1000, + LATCH_RECOVERY_APPLY_DELAY); } return true; } @@ -11296,7 +11297,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - wait_time); + wait_time, LATCH_RECOVERY_WAL_STREAM); ResetLatch(&XLogCtl->recoveryWakeupLatch); now = GetCurrentTimestamp(); } @@ -11459,7 +11460,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, */ WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - 5000L); + 5000L, LATCH_RECOVERY_WAL_ALL); ResetLatch(&XLogCtl->recoveryWakeupLatch); break; } diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 3834ed6..98fa579 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -381,7 +381,7 @@ gather_readnext(GatherState *gatherstate) return NULL; /* Nothing to do except wait for developments. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, LATCH_EXECUTE_GATHER); CHECK_FOR_INTERRUPTS(); ResetLatch(MyLatch); } diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index 95cceee..257c013 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -418,7 +418,8 @@ aloop: else waitfor = WL_SOCKET_WRITEABLE; - WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0); + WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0, + LATCH_SSL_OPEN_SERVER); goto aloop; case SSL_ERROR_SYSCALL: if (r < 0) diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c index 350210b..fa0cad1 100644 --- a/src/backend/libpq/pqmq.c +++ b/src/backend/libpq/pqmq.c @@ -171,7 +171,7 @@ mq_putmessage(char msgtype, const char *s, size_t len) if (result != SHM_MQ_WOULD_BLOCK) break; - WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); + WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0, LATCH_MQ_PUT_MESSAGE); CHECK_FOR_INTERRUPTS(); ResetLatch(&MyProc->procLatch); } diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 6bdaac5..218f53b 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -598,7 +598,8 @@ AutoVacLauncherMain(int argc, char *argv[]) */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L)); + (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L), + LATCH_AUTOVACUUM_MAIN); ResetLatch(MyLatch); diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 382edad..a605225 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -969,7 +969,8 @@ WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp) break; rc = WaitLatch(MyLatch, - WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); + WL_LATCH_SET | WL_POSTMASTER_DEATH, 0, + LATCH_BGWORKER_STARTUP); if (rc & WL_POSTMASTER_DEATH) { @@ -1008,7 +1009,8 @@ WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle) return status; rc = WaitLatch(&MyProc->procLatch, - WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); + WL_LATCH_SET | WL_POSTMASTER_DEATH, 0, + LATCH_BGWORKER_SHUTDOWN); if (rc & WL_POSTMASTER_DEATH) return BGWH_POSTMASTER_DIED; diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 00f03d8..c3b5427 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -347,7 +347,8 @@ BackgroundWriterMain(void) */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - BgWriterDelay /* ms */ ); + BgWriterDelay /* ms */, + LATCH_BGWRITER_MAIN); /* * If no latch event and BgBufferSync says nothing's happening, extend @@ -374,7 +375,8 @@ BackgroundWriterMain(void) /* Sleep ... */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - BgWriterDelay * HIBERNATE_FACTOR); + BgWriterDelay * HIBERNATE_FACTOR, + LATCH_BGWRITER_HIBERNATE); /* Reset the notification request in case we timed out */ StrategyNotifyBgWriter(-1); } diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index 8d4b353..f617f86 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -558,7 +558,8 @@ CheckpointerMain(void) rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - cur_timeout * 1000L /* convert to ms */ ); + cur_timeout * 1000L /* convert to ms */, + LATCH_CHECKPOINTER_MAIN); /* * Emergency bailout if postmaster has died. This is to avoid the diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 1aa6466..3815a3c 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -390,7 +390,7 @@ pgarch_MainLoop(void) rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - timeout * 1000L); + timeout * 1000L, LATCH_ARCHIVER_MAIN); if (rc & WL_TIMEOUT) wakened = true; } diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 41f4374..bd9a58b 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -3150,6 +3150,9 @@ pgstat_get_wait_event_type(uint32 wait_event_info) case WAIT_BUFFER_PIN: event_type = "BufferPin"; break; + case WAIT_LATCH: + event_type = "Latch"; + break; default: event_type = "???"; break; @@ -3191,6 +3194,9 @@ pgstat_get_wait_event(uint32 wait_event_info) case WAIT_BUFFER_PIN: event_name = "BufferPin"; break; + case WAIT_LATCH: + event_name = GetLatchIdentifier(eventId); + break; default: event_name = "unknown wait event"; break; @@ -3681,7 +3687,7 @@ PgstatCollectorMain(int argc, char *argv[]) wr = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE, pgStatSock, - -1L); + -1L, LATCH_PGSTAT_MAIN); #else /* @@ -3697,7 +3703,8 @@ PgstatCollectorMain(int argc, char *argv[]) wr = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE | WL_TIMEOUT, pgStatSock, - 2 * 1000L /* msec */ ); + 2 * 1000L /* msec */, + LATCH_PGSTAT_MAIN); #endif /* diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index e7e488a..2aedd32 100644 --- a/src/backend/postmaster/syslogger.c +++ b/src/backend/postmaster/syslogger.c @@ -424,7 +424,8 @@ SysLoggerMain(int argc, char *argv[]) rc = WaitLatchOrSocket(MyLatch, WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags, syslogPipe[0], - cur_timeout); + cur_timeout, + LATCH_SYSLOGGER_MAIN); if (rc & WL_SOCKET_READABLE) { @@ -475,7 +476,8 @@ SysLoggerMain(int argc, char *argv[]) (void) WaitLatch(MyLatch, WL_LATCH_SET | cur_flags, - cur_timeout); + cur_timeout, + LATCH_SYSLOGGER_MAIN); EnterCriticalSection(&sysloggerSection); #endif /* WIN32 */ diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 228190a..4b0a074 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -292,7 +292,8 @@ WalWriterMain(void) rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - cur_timeout); + cur_timeout, + LATCH_WALWRITER_MAIN); /* * Emergency bailout if postmaster has died. This is to avoid the diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index 1008873..d7dfc27 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -1286,7 +1286,8 @@ throttle(size_t increment) */ wait_result = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - (long) (sleep / 1000)); + (long) (sleep / 1000), + LATCH_BASEBACKUP_THROTTLE); if (wait_result & WL_LATCH_SET) CHECK_FOR_INTERRUPTS(); diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 959ca78..aab6a7b 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -265,7 +265,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit) * Wait on latch. Any condition that should wake us up will set the * latch, so no need for timeout. */ - WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1); + WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1, + LATCH_SYNC_REP); } /* diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 6fd5952..b5ac1bb 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -466,7 +466,8 @@ WalReceiverMain(void) WL_POSTMASTER_DEATH | WL_SOCKET_READABLE | WL_TIMEOUT | WL_LATCH_SET, wait_fd, - NAPTIME_PER_CYCLE); + NAPTIME_PER_CYCLE, + LATCH_WAL_RECEIVER_MAIN); if (rc & WL_LATCH_SET) { ResetLatch(&walrcv->latch); @@ -665,7 +666,8 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI) } SpinLockRelease(&walrcv->mutex); - WaitLatch(&walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); + WaitLatch(&walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0, + LATCH_WAL_RECEIVER_WAIT_START); } if (update_process_title) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index 926a247..8094b3ce 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -1146,7 +1146,8 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, /* Sleep until something happens or we time out */ WaitLatchOrSocket(MyLatch, wakeEvents, - MyProcPort->sock, sleeptime); + MyProcPort->sock, sleeptime, + LATCH_WAL_SENDER_WRITE_DATA); } /* reactivate latch so WalSndLoop knows to continue */ @@ -1272,7 +1273,8 @@ WalSndWaitForWal(XLogRecPtr loc) /* Sleep until something happens or we time out */ WaitLatchOrSocket(MyLatch, wakeEvents, - MyProcPort->sock, sleeptime); + MyProcPort->sock, sleeptime, + LATCH_WAL_SENDER_WAIT_WAL); } /* reactivate latch so WalSndLoop knows to continue */ @@ -1923,7 +1925,8 @@ WalSndLoop(WalSndSendDataCallback send_data) /* Sleep until something happens or we time out */ WaitLatchOrSocket(MyLatch, wakeEvents, - MyProcPort->sock, sleeptime); + MyProcPort->sock, sleeptime, + LATCH_WAL_SENDER_LOOP); } } return; diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c index 3fbe0e5..434a0fd 100644 --- a/src/backend/storage/ipc/latch.c +++ b/src/backend/storage/ipc/latch.c @@ -55,6 +55,7 @@ #endif #include "miscadmin.h" +#include "pgstat.h" #include "portability/instr_time.h" #include "postmaster/postmaster.h" #include "storage/barrier.h" @@ -297,9 +298,11 @@ DisownLatch(volatile Latch *latch) * we return all of them in one call, but we will return at least one. */ int -WaitLatch(volatile Latch *latch, int wakeEvents, long timeout) +WaitLatch(volatile Latch *latch, int wakeEvents, long timeout, + LatchIdentifier eventId) { - return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout); + return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout, + eventId); } /* @@ -316,13 +319,15 @@ WaitLatch(volatile Latch *latch, int wakeEvents, long timeout) */ int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, - long timeout) + long timeout, LatchIdentifier eventId) { int ret = 0; int rc; WaitEvent event; WaitEventSet *set = CreateWaitEventSet(CurrentMemoryContext, 3); + pgstat_report_wait_start(WAIT_LATCH, (uint16) eventId); + if (wakeEvents & WL_TIMEOUT) Assert(timeout >= 0); else @@ -356,6 +361,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, WL_SOCKET_WRITEABLE); } + pgstat_report_wait_end(); FreeWaitEventSet(set); return ret; @@ -1485,6 +1491,119 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout, } #endif + +/* + * Return an identifier for a Latch depending on an event for statistics + * collector. + */ +const char * +GetLatchIdentifier(uint16 eventId) +{ + const char *res; + + switch (eventId) + { + case LATCH_ARCHIVER_MAIN: + res = "ArchiverMain"; + break; + case LATCH_AUTOVACUUM_MAIN: + res = "AutoVacuumMain"; + break; + case LATCH_BASEBACKUP_THROTTLE: + res = "BaseBackupThrottle"; + break; + case LATCH_BGWORKER_STARTUP: + res = "BgWorkerStartup"; + break; + case LATCH_BGWORKER_SHUTDOWN: + res = "BgWorkerShutdown"; + break; + case LATCH_BGWRITER_MAIN: + res = "BgWriterMain"; + break; + case LATCH_BGWRITER_HIBERNATE: + res = "BgWriterHibernate"; + break; + case LATCH_CHECKPOINTER_MAIN: + res = "CheckpointerMain"; + break; + case LATCH_EXECUTE_GATHER: + res = "ExecuteGather"; + break; + case LATCH_EXTENSION: + res = "Extension"; + break; + case LATCH_MQ_PUT_MESSAGE: + res = "MessageQueuePutMessage"; + break; + case LATCH_MQ_SEND_BYTES: + res = "MessageQueueSend"; + break; + case LATCH_MQ_RECEIVE_BYTES: + res = "MessageQueueReceive"; + break; + case LATCH_MQ_WAIT_INTERNAL: + res = "MessageQueueInternal"; + break; + case LATCH_PARALLEL_WAIT_FINISH: + res = "ParallelFinish"; + break; + case LATCH_PG_SLEEP: + res = "PGSleep"; + break; + case LATCH_PGSTAT_MAIN: + res = "PGStatMain"; + break; + case LATCH_PROC_SLEEP: + res = "ProcSleep"; + break; + case LATCH_PROC_SIGNAL: + res = "ProcSignal"; + break; + case LATCH_RECOVERY_APPLY_DELAY: + res = "XLogApplyDelay"; + break; + case LATCH_RECOVERY_WAL_STREAM: + res = "RecoveryWALStream"; + break; + case LATCH_RECOVERY_WAL_ALL: + res = "XLogAfterAvailable"; + break; + case LATCH_SSL_OPEN_SERVER: + res = "SSLOpenServer"; + break; + case LATCH_SYNC_REP: + res = "SyncRep"; + break; + case LATCH_SYSLOGGER_MAIN: + res = "SysLoggerMain"; + break; + case LATCH_WALWRITER_MAIN: + res = "WALWriterMain"; + break; + case LATCH_WAL_RECEIVER_WAIT_START: + res = "WALSenderWaitStart"; + break; + case LATCH_WAL_RECEIVER_MAIN: + res = "WALReceiverMain"; + break; + case LATCH_WAL_SENDER_LOOP: + res = "WALSenderMain"; + break; + case LATCH_WAL_SENDER_WAIT_WAL: + res = "WALSenderWaitForWAL"; + break; + case LATCH_WAL_SENDER_WRITE_DATA: + res = "WALSenderWriteData"; + break; + default: + res = "???"; + } + + return res; +} + + /* * SetLatch uses SIGUSR1 to wake up the process waiting on the latch. * diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c index 7d1c9cd..a9542c2 100644 --- a/src/backend/storage/ipc/shm_mq.c +++ b/src/backend/storage/ipc/shm_mq.c @@ -866,7 +866,7 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data, * at top of loop, because setting an already-set latch is much * cheaper than setting one that has been reset. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, LATCH_MQ_SEND_BYTES); /* An interrupt may have occurred while we were waiting. */ CHECK_FOR_INTERRUPTS(); @@ -963,7 +963,7 @@ shm_mq_receive_bytes(shm_mq *mq, Size bytes_needed, bool nowait, * loop, because setting an already-set latch is much cheaper than * setting one that has been reset. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, LATCH_MQ_RECEIVE_BYTES); /* An interrupt may have occurred while we were waiting. */ CHECK_FOR_INTERRUPTS(); @@ -1062,7 +1062,7 @@ shm_mq_wait_internal(volatile shm_mq *mq, PGPROC *volatile * ptr, } /* Wait to be signalled. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, LATCH_MQ_WAIT_INTERNAL); /* An interrupt may have occurred while we were waiting. */ CHECK_FOR_INTERRUPTS(); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index a66e07b..8f910d74 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1216,7 +1216,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) } else { - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, LATCH_PROC_SLEEP); ResetLatch(MyLatch); /* check for deadlocks first, as that's probably log-worthy */ if (got_deadlock_timeout) @@ -1728,7 +1728,7 @@ CheckDeadLockAlert(void) void ProcWaitForSignal(void) { - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, LATCH_PROC_SIGNAL); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); } diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index a44fa38..36de861 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -560,7 +560,7 @@ pg_sleep(PG_FUNCTION_ARGS) (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT, - delay_ms); + delay_ms, LATCH_PG_SLEEP); ResetLatch(MyLatch); } diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 4be09fe..80db5ef 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -707,7 +707,8 @@ typedef enum WaitClass WAIT_LWLOCK_NAMED, WAIT_LWLOCK_TRANCHE, WAIT_LOCK, - WAIT_BUFFER_PIN + WAIT_BUFFER_PIN, + WAIT_LATCH } WaitClass; diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 85d211c..cf2c9e1 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -119,6 +119,45 @@ typedef struct WaitEvent void *user_data; /* pointer provided in AddWaitEventToSet */ } WaitEvent; +/* + * List of latch identifiers used when reporting activity to statistics + * collector. + */ +typedef enum LatchIdentifier +{ + LATCH_ARCHIVER_MAIN, + LATCH_AUTOVACUUM_MAIN, + LATCH_BASEBACKUP_THROTTLE, + LATCH_BGWORKER_STARTUP, + LATCH_BGWORKER_SHUTDOWN, + LATCH_BGWRITER_MAIN, + LATCH_BGWRITER_HIBERNATE, + LATCH_CHECKPOINTER_MAIN, + LATCH_EXECUTE_GATHER, + LATCH_EXTENSION, + LATCH_MQ_PUT_MESSAGE, + LATCH_MQ_SEND_BYTES, + LATCH_MQ_RECEIVE_BYTES, + LATCH_MQ_WAIT_INTERNAL, + LATCH_PARALLEL_WAIT_FINISH, + LATCH_PGSTAT_MAIN, + LATCH_PROC_SLEEP, + LATCH_PROC_SIGNAL, + LATCH_PG_SLEEP, + LATCH_SSL_OPEN_SERVER, + LATCH_SYNC_REP, + LATCH_SYSLOGGER_MAIN, + LATCH_RECOVERY_APPLY_DELAY, + LATCH_RECOVERY_WAL_ALL, + LATCH_RECOVERY_WAL_STREAM, + LATCH_WAL_RECEIVER_WAIT_START, + LATCH_WAL_RECEIVER_MAIN, + LATCH_WAL_SENDER_WRITE_DATA, + LATCH_WAL_SENDER_LOOP, + LATCH_WAL_SENDER_WAIT_WAL, + LATCH_WALWRITER_MAIN, +} LatchIdentifier; + /* forward declaration to avoid exposing latch.c implementation details */ typedef struct WaitEventSet WaitEventSet; @@ -140,9 +179,11 @@ extern int AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, extern void ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch); extern int WaitEventSetWait(WaitEventSet *set, long timeout, WaitEvent *occurred_events, int nevents); -extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout); +extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout, + LatchIdentifier eventId); extern int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, - pgsocket sock, long timeout); + pgsocket sock, long timeout, LatchIdentifier eventId); +extern const char *GetLatchIdentifier(uint16 eventId); /* * Unix implementation uses SIGUSR1 for inter-process signaling. diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c index 5bd2820..2fd4e24 100644 --- a/src/test/modules/test_shm_mq/setup.c +++ b/src/test/modules/test_shm_mq/setup.c @@ -279,7 +279,7 @@ wait_for_workers_to_become_ready(worker_state *wstate, } /* Wait to be signalled. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, LATCH_EXTENSION); /* An interrupt may have occurred while we were waiting. */ CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c index 6948e20..a89a52a 100644 --- a/src/test/modules/test_shm_mq/test.c +++ b/src/test/modules/test_shm_mq/test.c @@ -230,7 +230,7 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS) * have read or written data and therefore there may now be work * for us to do. */ - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, LATCH_EXTENSION); CHECK_FOR_INTERRUPTS(); ResetLatch(MyLatch); } diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index 314e371..af4549a 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -227,7 +227,8 @@ worker_spi_main(Datum main_arg) */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - worker_spi_naptime * 1000L); + worker_spi_naptime * 1000L, + LATCH_EXTENSION); ResetLatch(MyLatch); /* emergency bailout if postmaster has died */