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.
This commit is contained in:
Tom Lane 2005-08-09 21:14:55 +00:00
parent f80cf69031
commit c7bba5e21c

View File

@ -13,7 +13,7 @@
* *
* Copyright (c) 2001-2005, PostgreSQL Global Development Group * 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" #include "postgres.h"
@ -46,6 +46,7 @@
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/pg_shmem.h" #include "storage/pg_shmem.h"
#include "storage/pmsignal.h" #include "storage/pmsignal.h"
#include "storage/procarray.h"
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
#include "utils/memutils.h" #include "utils/memutils.h"
@ -1605,8 +1606,8 @@ PgstatCollectorMain(int argc, char *argv[])
/* /*
* Create the known backends table * Create the known backends table
*/ */
pgStatBeTable = (PgStat_StatBeEntry *) palloc0( pgStatBeTable = (PgStat_StatBeEntry *)
sizeof(PgStat_StatBeEntry) * MaxBackends); palloc0(sizeof(PgStat_StatBeEntry) * MaxBackends);
readPipe = pgStatPipe[0]; readPipe = pgStatPipe[0];
@ -2456,6 +2457,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
PgStat_StatDBEntry dbbuf; PgStat_StatDBEntry dbbuf;
PgStat_StatTabEntry *tabentry; PgStat_StatTabEntry *tabentry;
PgStat_StatTabEntry tabbuf; PgStat_StatTabEntry tabbuf;
PgStat_StatBeEntry *beentry;
HASHCTL hash_ctl; HASHCTL hash_ctl;
HTAB *tabhash = NULL; HTAB *tabhash = NULL;
FILE *fpin; FILE *fpin;
@ -2463,6 +2465,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
int maxbackends = 0; int maxbackends = 0;
int havebackends = 0; int havebackends = 0;
bool found; bool found;
bool check_pids;
MemoryContext use_mcxt; MemoryContext use_mcxt;
int mcxt_flags; int mcxt_flags;
@ -2472,16 +2475,22 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
* TopTransactionContext instead, so the caller must only know the last * TopTransactionContext instead, so the caller must only know the last
* XactId when this call happened to know if his tables are still valid or * XactId when this call happened to know if his tables are still valid or
* already gone! * 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()) if (pgStatRunningInCollector || IsAutoVacuumProcess())
{ {
use_mcxt = NULL; use_mcxt = NULL;
mcxt_flags = 0; mcxt_flags = 0;
check_pids = false;
} }
else else
{ {
use_mcxt = TopTransactionContext; use_mcxt = TopTransactionContext;
mcxt_flags = HASH_CONTEXT; 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) if (betab == NULL || numbackends == NULL || *betab == NULL)
goto done; goto done;
if (havebackends >= maxbackends)
goto done;
/* /*
* Read it directly into the table. * Read it directly into the table.
*/ */
if (fread(&(*betab)[havebackends], 1, beentry = &(*betab)[havebackends];
sizeof(PgStat_StatBeEntry), fpin) !=
if (fread(beentry, 1, sizeof(PgStat_StatBeEntry), fpin) !=
sizeof(PgStat_StatBeEntry)) sizeof(PgStat_StatBeEntry))
{ {
ereport(pgStatRunningInCollector ? LOG : WARNING, ereport(pgStatRunningInCollector ? LOG : WARNING,
@ -2677,20 +2690,36 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
goto done; 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. * Count backends per database here.
*/ */
dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash, dbentry = (PgStat_StatDBEntry *)
(void *) &((*betab)[havebackends].databaseid), hash_search(*dbhash,
HASH_FIND, NULL); &(beentry->databaseid),
HASH_FIND,
NULL);
if (dbentry) if (dbentry)
dbentry->n_backends++; dbentry->n_backends++;
havebackends++; havebackends++;
if (numbackends != 0)
*numbackends = havebackends; *numbackends = havebackends;
if (havebackends >= maxbackends)
goto done;
break; break;
@ -2728,10 +2757,10 @@ backend_read_statsfile(void)
{ {
if (IsAutoVacuumProcess()) if (IsAutoVacuumProcess())
{ {
Assert(!pgStatRunningInCollector);
/* already read it? */ /* already read it? */
if (pgStatDBHash) if (pgStatDBHash)
return; return;
Assert(!pgStatRunningInCollector);
pgstat_read_statsfile(&pgStatDBHash, InvalidOid, pgstat_read_statsfile(&pgStatDBHash, InvalidOid,
&pgStatBeTable, &pgStatNumBackends); &pgStatBeTable, &pgStatNumBackends);
} }