From c7bba5e21c25e5b4afda3df7c1a9ef9d7a4584ed Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 9 Aug 2005 21:14:55 +0000 Subject: [PATCH] Make backends that are reading the pgstats file verify each backend PID against the PGPROC array. Anything in the file that isn't in PGPROC gets rejected as being a stale entry. This should solve complaints about stale entries in pg_stat_activity after a BETERM message has been dropped due to overload. --- src/backend/postmaster/pgstat.c | 55 +++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 9a07915f79b..00ed7b837da 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.103 2005/08/08 03:11:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.104 2005/08/09 21:14:55 tgl Exp $ * ---------- */ #include "postgres.h" @@ -46,6 +46,7 @@ #include "storage/ipc.h" #include "storage/pg_shmem.h" #include "storage/pmsignal.h" +#include "storage/procarray.h" #include "tcop/tcopprot.h" #include "utils/hsearch.h" #include "utils/memutils.h" @@ -1605,8 +1606,8 @@ PgstatCollectorMain(int argc, char *argv[]) /* * Create the known backends table */ - pgStatBeTable = (PgStat_StatBeEntry *) palloc0( - sizeof(PgStat_StatBeEntry) * MaxBackends); + pgStatBeTable = (PgStat_StatBeEntry *) + palloc0(sizeof(PgStat_StatBeEntry) * MaxBackends); readPipe = pgStatPipe[0]; @@ -2456,6 +2457,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, PgStat_StatDBEntry dbbuf; PgStat_StatTabEntry *tabentry; PgStat_StatTabEntry tabbuf; + PgStat_StatBeEntry *beentry; HASHCTL hash_ctl; HTAB *tabhash = NULL; FILE *fpin; @@ -2463,6 +2465,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, int maxbackends = 0; int havebackends = 0; bool found; + bool check_pids; MemoryContext use_mcxt; int mcxt_flags; @@ -2472,16 +2475,22 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, * TopTransactionContext instead, so the caller must only know the last * XactId when this call happened to know if his tables are still valid or * already gone! + * + * Also, if running in a regular backend, we check backend entries against + * the PGPROC array so that we can detect stale entries. This lets us + * discard entries whose BETERM message got lost for some reason. */ if (pgStatRunningInCollector || IsAutoVacuumProcess()) { use_mcxt = NULL; mcxt_flags = 0; + check_pids = false; } else { use_mcxt = TopTransactionContext; mcxt_flags = HASH_CONTEXT; + check_pids = true; } /* @@ -2665,11 +2674,15 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, if (betab == NULL || numbackends == NULL || *betab == NULL) goto done; + if (havebackends >= maxbackends) + goto done; + /* * Read it directly into the table. */ - if (fread(&(*betab)[havebackends], 1, - sizeof(PgStat_StatBeEntry), fpin) != + beentry = &(*betab)[havebackends]; + + if (fread(beentry, 1, sizeof(PgStat_StatBeEntry), fpin) != sizeof(PgStat_StatBeEntry)) { ereport(pgStatRunningInCollector ? LOG : WARNING, @@ -2677,20 +2690,36 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb, goto done; } + /* + * If possible, check PID to verify still running + */ + if (check_pids && !IsBackendPid(beentry->procpid)) + { + /* + * Note: we could send a BETERM message to tell the + * collector to drop the entry, but I'm a bit worried + * about race conditions. For now, just silently ignore + * dead entries; they'll get recycled eventually anyway. + */ + + /* Don't accept the entry */ + memset(beentry, 0, sizeof(PgStat_StatBeEntry)); + break; + } + /* * Count backends per database here. */ - dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash, - (void *) &((*betab)[havebackends].databaseid), - HASH_FIND, NULL); + dbentry = (PgStat_StatDBEntry *) + hash_search(*dbhash, + &(beentry->databaseid), + HASH_FIND, + NULL); if (dbentry) dbentry->n_backends++; havebackends++; - if (numbackends != 0) - *numbackends = havebackends; - if (havebackends >= maxbackends) - goto done; + *numbackends = havebackends; break; @@ -2728,10 +2757,10 @@ backend_read_statsfile(void) { if (IsAutoVacuumProcess()) { - Assert(!pgStatRunningInCollector); /* already read it? */ if (pgStatDBHash) return; + Assert(!pgStatRunningInCollector); pgstat_read_statsfile(&pgStatDBHash, InvalidOid, &pgStatBeTable, &pgStatNumBackends); }