aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-06-19 01:51:22 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-06-19 01:51:22 +0000
commitb13c9686d08411a284afeb881b49d7955761d8cb (patch)
treeec956d8cc1a3176b73b064d711ce5ccda547e23b /src
parent6075feed40804a963f9a7c041e7d157a86cc758d (diff)
downloadpostgresql-b13c9686d08411a284afeb881b49d7955761d8cb.tar.gz
postgresql-b13c9686d08411a284afeb881b49d7955761d8cb.zip
Take the statistics collector out of the loop for monitoring backends'
current commands; instead, store current-status information in shared memory. This substantially reduces the overhead of stats_command_string and also ensures that pg_stat_activity is fully up to date at all times. Per my recent proposal.
Diffstat (limited to 'src')
-rw-r--r--src/backend/postmaster/pgstat.c1160
-rw-r--r--src/backend/postmaster/postmaster.c9
-rw-r--r--src/backend/storage/ipc/ipci.c5
-rw-r--r--src/backend/storage/ipc/procarray.c38
-rw-r--r--src/backend/utils/adt/pgstatfuncs.c217
-rw-r--r--src/backend/utils/misc/guc.c23
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample16
-rw-r--r--src/include/pgstat.h266
-rw-r--r--src/include/storage/procarray.h3
9 files changed, 697 insertions, 1040 deletions
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 50486f8cef2..f6949f14377 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -13,7 +13,7 @@
*
* Copyright (c) 2001-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.128 2006/06/18 15:38:37 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.129 2006/06/19 01:51:21 tgl Exp $
* ----------
*/
#include "postgres.h"
@@ -84,7 +84,6 @@
* ----------
*/
#define PGSTAT_DB_HASH_SIZE 16
-#define PGSTAT_BE_HASH_SIZE 512
#define PGSTAT_TAB_HASH_SIZE 512
@@ -94,9 +93,9 @@
*/
bool pgstat_collect_startcollector = true;
bool pgstat_collect_resetonpmstart = false;
-bool pgstat_collect_querystring = false;
bool pgstat_collect_tuplelevel = false;
bool pgstat_collect_blocklevel = false;
+bool pgstat_collect_querystring = false;
/* ----------
* Local data
@@ -104,13 +103,13 @@ bool pgstat_collect_blocklevel = false;
*/
NON_EXEC_STATIC int pgStatSock = -1;
NON_EXEC_STATIC int pgStatPipe[2] = {-1, -1};
+
static struct sockaddr_storage pgStatAddr;
+
static pid_t pgStatCollectorPid = 0;
static time_t last_pgstat_start_time;
-static long pgStatNumMessages = 0;
-
static bool pgStatRunningInCollector = false;
/*
@@ -135,8 +134,9 @@ static int pgStatXactRollback = 0;
static TransactionId pgStatDBHashXact = InvalidTransactionId;
static HTAB *pgStatDBHash = NULL;
-static PgStat_StatBeEntry *pgStatBeTable = NULL;
-static int pgStatNumBackends = 0;
+static TransactionId pgStatLocalStatusXact = InvalidTransactionId;
+static PgBackendStatus *localBackendStatusTable = NULL;
+static int localNumBackends = 0;
static volatile bool need_statwrite;
@@ -166,21 +166,15 @@ static void pgstat_die(SIGNAL_ARGS);
static void pgstat_beshutdown_hook(int code, Datum arg);
static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create);
-static int pgstat_add_backend(PgStat_MsgHdr *msg);
-static void pgstat_sub_backend(int procpid);
static void pgstat_drop_database(Oid databaseid);
static void pgstat_write_statsfile(void);
-static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
- PgStat_StatBeEntry **betab,
- int *numbackends);
+static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb);
static void backend_read_statsfile(void);
+static void pgstat_read_current_status(void);
static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
static void pgstat_send(void *msg, int len);
-static void pgstat_recv_bestart(PgStat_MsgBestart *msg, int len);
-static void pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len);
-static void pgstat_recv_activity(PgStat_MsgActivity *msg, int len);
static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len);
static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len);
static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len);
@@ -221,10 +215,11 @@ pgstat_init(void)
#define TESTBYTEVAL ((char) 199)
/*
- * Force start of collector daemon if something to collect
+ * Force start of collector daemon if something to collect. Note that
+ * pgstat_collect_querystring is now an independent facility that does
+ * not require the collector daemon.
*/
- if (pgstat_collect_querystring ||
- pgstat_collect_tuplelevel ||
+ if (pgstat_collect_tuplelevel ||
pgstat_collect_blocklevel)
pgstat_collect_startcollector = true;
@@ -451,7 +446,6 @@ startup_failed:
/* Adjust GUC variables to suppress useless activity */
pgstat_collect_startcollector = false;
- pgstat_collect_querystring = false;
pgstat_collect_tuplelevel = false;
pgstat_collect_blocklevel = false;
}
@@ -626,52 +620,6 @@ pgstat_start(void)
}
-/* ----------
- * pgstat_beterm() -
- *
- * Called from postmaster to tell collector a backend terminated.
- * ----------
- */
-void
-pgstat_beterm(int pid)
-{
- PgStat_MsgBeterm msg;
-
- if (pgStatSock < 0)
- return;
-
- /* can't use pgstat_setheader() because it's not called in a backend */
- MemSet(&(msg.m_hdr), 0, sizeof(msg.m_hdr));
- msg.m_hdr.m_type = PGSTAT_MTYPE_BETERM;
- msg.m_hdr.m_procpid = pid;
-
- pgstat_send(&msg, sizeof(msg));
-}
-
-
-/* ----------
- * pgstat_report_autovac() -
- *
- * Called from autovacuum.c to report startup of an autovacuum process.
- * We are called before InitPostgres is done, so can't rely on MyDatabaseId;
- * the db OID must be passed in, instead.
- * ----------
- */
-void
-pgstat_report_autovac(Oid dboid)
-{
- PgStat_MsgAutovacStart msg;
-
- if (pgStatSock < 0)
- return;
-
- pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_AUTOVAC_START);
- msg.m_databaseid = dboid;
- msg.m_start_time = GetCurrentTimestamp();
-
- pgstat_send(&msg, sizeof(msg));
-}
-
/* ------------------------------------------------------------
* Public functions used by backends follow
*------------------------------------------------------------
@@ -679,135 +627,6 @@ pgstat_report_autovac(Oid dboid)
/* ----------
- * pgstat_bestart() -
- *
- * Tell the collector that this new backend is soon ready to process
- * queries. Called from InitPostgres.
- * ----------
- */
-void
-pgstat_bestart(void)
-{
- PgStat_MsgBestart msg;
-
- if (pgStatSock < 0)
- return;
-
- /*
- * We may not have a MyProcPort (eg, if this is the autovacuum process).
- * Send an all-zeroes client address, which is dealt with specially in
- * pg_stat_get_backend_client_addr and pg_stat_get_backend_client_port.
- */
- pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_BESTART);
- msg.m_databaseid = MyDatabaseId;
- msg.m_userid = GetSessionUserId();
- if (MyProcPort)
- memcpy(&msg.m_clientaddr, &MyProcPort->raddr, sizeof(msg.m_clientaddr));
- else
- MemSet(&msg.m_clientaddr, 0, sizeof(msg.m_clientaddr));
- pgstat_send(&msg, sizeof(msg));
-
- /*
- * Set up a process-exit hook to ensure we flush the last batch of
- * statistics to the collector.
- */
- on_shmem_exit(pgstat_beshutdown_hook, 0);
-}
-
-/* ---------
- * pgstat_report_vacuum() -
- *
- * Tell the collector about the table we just vacuumed.
- * ---------
- */
-void
-pgstat_report_vacuum(Oid tableoid, bool shared,
- bool analyze, PgStat_Counter tuples)
-{
- PgStat_MsgVacuum msg;
-
- if (pgStatSock < 0 ||
- !pgstat_collect_tuplelevel)
- return;
-
- pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM);
- msg.m_databaseid = shared ? InvalidOid : MyDatabaseId;
- msg.m_tableoid = tableoid;
- msg.m_analyze = analyze;
- msg.m_autovacuum = IsAutoVacuumProcess(); /* is this autovacuum? */
- msg.m_vacuumtime = GetCurrentTimestamp();
- msg.m_tuples = tuples;
- pgstat_send(&msg, sizeof(msg));
-}
-
-/* --------
- * pgstat_report_analyze() -
- *
- * Tell the collector about the table we just analyzed.
- * --------
- */
-void
-pgstat_report_analyze(Oid tableoid, bool shared, PgStat_Counter livetuples,
- PgStat_Counter deadtuples)
-{
- PgStat_MsgAnalyze msg;
-
- if (pgStatSock < 0 ||
- !pgstat_collect_tuplelevel)
- return;
-
- pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANALYZE);
- msg.m_databaseid = shared ? InvalidOid : MyDatabaseId;
- msg.m_tableoid = tableoid;
- msg.m_autovacuum = IsAutoVacuumProcess(); /* is this autovacuum? */
- msg.m_analyzetime = GetCurrentTimestamp();
- msg.m_live_tuples = livetuples;
- msg.m_dead_tuples = deadtuples;
- pgstat_send(&msg, sizeof(msg));
-}
-
-/*
- * Flush any remaining statistics counts out to the collector at process
- * exit. Without this, operations triggered during backend exit (such as
- * temp table deletions) won't be counted.
- */
-static void
-pgstat_beshutdown_hook(int code, Datum arg)
-{
- pgstat_report_tabstat();
-}
-
-
-/* ----------
- * pgstat_report_activity() -
- *
- * Called from tcop/postgres.c to tell the collector what the backend
- * is actually doing (usually "<IDLE>" or the start of the query to
- * be executed).
- * ----------
- */
-void
-pgstat_report_activity(const char *cmd_str)
-{
- PgStat_MsgActivity msg;
- int len;
-
- if (!pgstat_collect_querystring || pgStatSock < 0)
- return;
-
- len = strlen(cmd_str);
- len = pg_mbcliplen(cmd_str, len, PGSTAT_ACTIVITY_SIZE - 1);
-
- memcpy(msg.m_cmd_str, cmd_str, len);
- msg.m_cmd_str[len] = '\0';
- len += offsetof(PgStat_MsgActivity, m_cmd_str) + 1;
-
- pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ACTIVITY);
- pgstat_send(&msg, len);
-}
-
-
-/* ----------
* pgstat_report_tabstat() -
*
* Called from tcop/postgres.c to send the so far collected
@@ -820,8 +639,7 @@ pgstat_report_tabstat(void)
int i;
if (pgStatSock < 0 ||
- (!pgstat_collect_querystring &&
- !pgstat_collect_tuplelevel &&
+ (!pgstat_collect_tuplelevel &&
!pgstat_collect_blocklevel))
{
/* Not reporting stats, so just flush whatever we have */
@@ -1086,6 +904,83 @@ pgstat_reset_counters(void)
/* ----------
+ * pgstat_report_autovac() -
+ *
+ * Called from autovacuum.c to report startup of an autovacuum process.
+ * We are called before InitPostgres is done, so can't rely on MyDatabaseId;
+ * the db OID must be passed in, instead.
+ * ----------
+ */
+void
+pgstat_report_autovac(Oid dboid)
+{
+ PgStat_MsgAutovacStart msg;
+
+ if (pgStatSock < 0)
+ return;
+
+ pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_AUTOVAC_START);
+ msg.m_databaseid = dboid;
+ msg.m_start_time = GetCurrentTimestamp();
+
+ pgstat_send(&msg, sizeof(msg));
+}
+
+
+/* ---------
+ * pgstat_report_vacuum() -
+ *
+ * Tell the collector about the table we just vacuumed.
+ * ---------
+ */
+void
+pgstat_report_vacuum(Oid tableoid, bool shared,
+ bool analyze, PgStat_Counter tuples)
+{
+ PgStat_MsgVacuum msg;
+
+ if (pgStatSock < 0 ||
+ !pgstat_collect_tuplelevel)
+ return;
+
+ pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM);
+ msg.m_databaseid = shared ? InvalidOid : MyDatabaseId;
+ msg.m_tableoid = tableoid;
+ msg.m_analyze = analyze;
+ msg.m_autovacuum = IsAutoVacuumProcess(); /* is this autovacuum? */
+ msg.m_vacuumtime = GetCurrentTimestamp();
+ msg.m_tuples = tuples;
+ pgstat_send(&msg, sizeof(msg));
+}
+
+/* --------
+ * pgstat_report_analyze() -
+ *
+ * Tell the collector about the table we just analyzed.
+ * --------
+ */
+void
+pgstat_report_analyze(Oid tableoid, bool shared, PgStat_Counter livetuples,
+ PgStat_Counter deadtuples)
+{
+ PgStat_MsgAnalyze msg;
+
+ if (pgStatSock < 0 ||
+ !pgstat_collect_tuplelevel)
+ return;
+
+ pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANALYZE);
+ msg.m_databaseid = shared ? InvalidOid : MyDatabaseId;
+ msg.m_tableoid = tableoid;
+ msg.m_autovacuum = IsAutoVacuumProcess(); /* is this autovacuum? */
+ msg.m_analyzetime = GetCurrentTimestamp();
+ msg.m_live_tuples = livetuples;
+ msg.m_dead_tuples = deadtuples;
+ pgstat_send(&msg, sizeof(msg));
+}
+
+
+/* ----------
* pgstat_ping() -
*
* Send some junk data to the collector to increase traffic.
@@ -1231,8 +1126,7 @@ pgstat_initstats(PgStat_Info *stats, Relation rel)
void
pgstat_count_xact_commit(void)
{
- if (!pgstat_collect_querystring &&
- !pgstat_collect_tuplelevel &&
+ if (!pgstat_collect_tuplelevel &&
!pgstat_collect_blocklevel)
return;
@@ -1263,8 +1157,7 @@ pgstat_count_xact_commit(void)
void
pgstat_count_xact_rollback(void)
{
- if (!pgstat_collect_querystring &&
- !pgstat_collect_tuplelevel &&
+ if (!pgstat_collect_tuplelevel &&
!pgstat_collect_blocklevel)
return;
@@ -1375,20 +1268,21 @@ pgstat_fetch_stat_tabentry(Oid relid)
* pgstat_fetch_stat_beentry() -
*
* Support function for the SQL-callable pgstat* functions. Returns
- * the actual activity slot of one active backend. The caller is
- * responsible for a check if the actual user is permitted to see
- * that info (especially the querystring).
+ * our local copy of the current-activity entry for one backend.
+ *
+ * NB: caller is responsible for a check if the user is permitted to see
+ * this info (especially the querystring).
* ----------
*/
-PgStat_StatBeEntry *
+PgBackendStatus *
pgstat_fetch_stat_beentry(int beid)
{
- backend_read_statsfile();
+ pgstat_read_current_status();
- if (beid < 1 || beid > pgStatNumBackends)
+ if (beid < 1 || beid > localNumBackends)
return NULL;
- return &pgStatBeTable[beid - 1];
+ return &localBackendStatusTable[beid - 1];
}
@@ -1402,12 +1296,262 @@ pgstat_fetch_stat_beentry(int beid)
int
pgstat_fetch_stat_numbackends(void)
{
- backend_read_statsfile();
+ pgstat_read_current_status();
- return pgStatNumBackends;
+ return localNumBackends;
}
+/* ------------------------------------------------------------
+ * Functions for management of the shared-memory PgBackendStatus array
+ * ------------------------------------------------------------
+ */
+
+static PgBackendStatus *BackendStatusArray = NULL;
+static PgBackendStatus *MyBEEntry = NULL;
+
+
+/*
+ * Report shared-memory space needed by CreateSharedBackendStatus.
+ */
+Size
+BackendStatusShmemSize(void)
+{
+ Size size;
+
+ size = mul_size(sizeof(PgBackendStatus), MaxBackends);
+ return size;
+}
+
+/*
+ * Initialize the shared status array during postmaster startup.
+ */
+void
+CreateSharedBackendStatus(void)
+{
+ Size size = BackendStatusShmemSize();
+ bool found;
+
+ /* Create or attach to the shared array */
+ BackendStatusArray = (PgBackendStatus *)
+ ShmemInitStruct("Backend Status Array", size, &found);
+
+ if (!found)
+ {
+ /*
+ * We're the first - initialize.
+ */
+ MemSet(BackendStatusArray, 0, size);
+ }
+}
+
+
+/* ----------
+ * pgstat_bestart() -
+ *
+ * Initialize this backend's entry in the PgBackendStatus array,
+ * and set up an on-proc-exit hook that will clear it again.
+ * Called from InitPostgres. MyBackendId and MyDatabaseId must be set.
+ * ----------
+ */
+void
+pgstat_bestart(void)
+{
+ volatile PgBackendStatus *beentry;
+ TimestampTz proc_start_timestamp;
+ Oid userid;
+ SockAddr clientaddr;
+
+ Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
+ MyBEEntry = &BackendStatusArray[MyBackendId - 1];
+
+ /*
+ * To minimize the time spent modifying the entry, fetch all the
+ * needed data first.
+ */
+ proc_start_timestamp = GetCurrentTimestamp();
+ userid = GetSessionUserId();
+
+ /*
+ * We may not have a MyProcPort (eg, if this is the autovacuum process).
+ * If so, use all-zeroes client address, which is dealt with specially in
+ * pg_stat_get_backend_client_addr and pg_stat_get_backend_client_port.
+ */
+ if (MyProcPort)
+ memcpy(&clientaddr, &MyProcPort->raddr, sizeof(clientaddr));
+ else
+ MemSet(&clientaddr, 0, sizeof(clientaddr));
+
+ /*
+ * Initialize my status entry, following the protocol of bumping
+ * st_changecount before and after; and make sure it's even afterwards.
+ * We use a volatile pointer here to ensure the compiler doesn't try to
+ * get cute.
+ */
+ beentry = MyBEEntry;
+ do {
+ beentry->st_changecount++;
+ } while ((beentry->st_changecount & 1) == 0);
+
+ beentry->st_procpid = MyProcPid;
+ beentry->st_proc_start_timestamp = proc_start_timestamp;
+ beentry->st_activity_start_timestamp = 0;
+ beentry->st_databaseid = MyDatabaseId;
+ beentry->st_userid = userid;
+ beentry->st_clientaddr = clientaddr;
+ beentry->st_activity[0] = '\0';
+ /* Also make sure the last byte in the string area is always 0 */
+ beentry->st_activity[PGBE_ACTIVITY_SIZE - 1] = '\0';
+
+ beentry->st_changecount++;
+ Assert((beentry->st_changecount & 1) == 0);
+
+ /*
+ * Set up a process-exit hook to clean up.
+ */
+ on_shmem_exit(pgstat_beshutdown_hook, 0);
+}
+
+/*
+ * Shut down a single backend's statistics reporting at process exit.
+ *
+ * Flush any remaining statistics counts out to the collector.
+ * Without this, operations triggered during backend exit (such as
+ * temp table deletions) won't be counted.
+ *
+ * Lastly, clear out our entry in the PgBackendStatus array.
+ */
+static void
+pgstat_beshutdown_hook(int code, Datum arg)
+{
+ volatile PgBackendStatus *beentry;
+
+ pgstat_report_tabstat();
+
+ /*
+ * Clear my status entry, following the protocol of bumping
+ * st_changecount before and after. We use a volatile pointer here
+ * to ensure the compiler doesn't try to get cute.
+ */
+ beentry = MyBEEntry;
+ beentry->st_changecount++;
+
+ beentry->st_procpid = 0; /* mark invalid */
+
+ beentry->st_changecount++;
+ Assert((beentry->st_changecount & 1) == 0);
+}
+
+
+/* ----------
+ * pgstat_report_activity() -
+ *
+ * Called from tcop/postgres.c to report what the backend is actually doing
+ * (usually "<IDLE>" or the start of the query to be executed).
+ * ----------
+ */
+void
+pgstat_report_activity(const char *cmd_str)
+{
+ volatile PgBackendStatus *beentry;
+ TimestampTz start_timestamp;
+ int len;
+
+ if (!pgstat_collect_querystring)
+ return;
+
+ /*
+ * To minimize the time spent modifying the entry, fetch all the
+ * needed data first.
+ */
+ start_timestamp = GetCurrentTimestamp();
+
+ len = strlen(cmd_str);
+ len = pg_mbcliplen(cmd_str, len, PGBE_ACTIVITY_SIZE - 1);
+
+ /*
+ * Update my status entry, following the protocol of bumping
+ * st_changecount before and after. We use a volatile pointer here
+ * to ensure the compiler doesn't try to get cute.
+ */
+ beentry = MyBEEntry;
+ beentry->st_changecount++;
+
+ beentry->st_activity_start_timestamp = start_timestamp;
+ memcpy((char *) beentry->st_activity, cmd_str, len);
+ beentry->st_activity[len] = '\0';
+
+ beentry->st_changecount++;
+ Assert((beentry->st_changecount & 1) == 0);
+}
+
+
+/* ----------
+ * pgstat_read_current_status() -
+ *
+ * Copy the current contents of the PgBackendStatus array to local memory,
+ * if not already done in this transaction.
+ * ----------
+ */
+static void
+pgstat_read_current_status(void)
+{
+ TransactionId topXid = GetTopTransactionId();
+ volatile PgBackendStatus *beentry;
+ PgBackendStatus *localentry;
+ int i;
+
+ Assert(!pgStatRunningInCollector);
+ if (TransactionIdEquals(pgStatLocalStatusXact, topXid))
+ return; /* already done */
+
+ localBackendStatusTable = (PgBackendStatus *)
+ MemoryContextAlloc(TopTransactionContext,
+ sizeof(PgBackendStatus) * MaxBackends);
+ localNumBackends = 0;
+
+ beentry = BackendStatusArray;
+ localentry = localBackendStatusTable;
+ for (i = 1; i <= MaxBackends; i++)
+ {
+ /*
+ * Follow the protocol of retrying if st_changecount changes while
+ * we copy the entry, or if it's odd. (The check for odd is needed
+ * to cover the case where we are able to completely copy the entry
+ * while the source backend is between increment steps.) We use a
+ * volatile pointer here to ensure the compiler doesn't try to get
+ * cute.
+ */
+ for (;;)
+ {
+ int save_changecount = beentry->st_changecount;
+
+ /*
+ * XXX if PGBE_ACTIVITY_SIZE is really large, it might be best
+ * to use strcpy not memcpy for copying the activity string?
+ */
+ memcpy(localentry, (char *) beentry, sizeof(PgBackendStatus));
+
+ if (save_changecount == beentry->st_changecount &&
+ (save_changecount & 1) == 0)
+ break;
+
+ /* Make sure we can break out of loop if stuck... */
+ CHECK_FOR_INTERRUPTS();
+ }
+
+ beentry++;
+ /* Only valid entries get included into the local array */
+ if (localentry->st_procpid > 0)
+ {
+ localentry++;
+ localNumBackends++;
+ }
+ }
+
+ pgStatLocalStatusXact = topXid;
+}
+
/* ------------------------------------------------------------
* Local support functions follow
@@ -1425,8 +1569,6 @@ static void
pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype)
{
hdr->m_type = mtype;
- hdr->m_backendid = MyBackendId;
- hdr->m_procpid = MyProcPid;
}
@@ -1613,13 +1755,7 @@ PgstatCollectorMain(int argc, char *argv[])
* zero.
*/
pgStatRunningInCollector = true;
- pgstat_read_statsfile(&pgStatDBHash, InvalidOid, NULL, NULL);
-
- /*
- * Create the known backends table
- */
- pgStatBeTable = (PgStat_StatBeEntry *)
- palloc0(sizeof(PgStat_StatBeEntry) * MaxBackends);
+ pgstat_read_statsfile(&pgStatDBHash, InvalidOid);
readPipe = pgStatPipe[0];
@@ -1727,14 +1863,6 @@ PgstatCollectorMain(int argc, char *argv[])
case PGSTAT_MTYPE_DUMMY:
break;
- case PGSTAT_MTYPE_BESTART:
- pgstat_recv_bestart((PgStat_MsgBestart *) &msg, nread);
- break;
-
- case PGSTAT_MTYPE_BETERM:
- pgstat_recv_beterm((PgStat_MsgBeterm *) &msg, nread);
- break;
-
case PGSTAT_MTYPE_TABSTAT:
pgstat_recv_tabstat((PgStat_MsgTabstat *) &msg, nread);
break;
@@ -1743,10 +1871,6 @@ PgstatCollectorMain(int argc, char *argv[])
pgstat_recv_tabpurge((PgStat_MsgTabpurge *) &msg, nread);
break;
- case PGSTAT_MTYPE_ACTIVITY:
- pgstat_recv_activity((PgStat_MsgActivity *) &msg, nread);
- break;
-
case PGSTAT_MTYPE_DROPDB:
pgstat_recv_dropdb((PgStat_MsgDropdb *) &msg, nread);
break;
@@ -1773,11 +1897,6 @@ PgstatCollectorMain(int argc, char *argv[])
}
/*
- * Globally count messages.
- */
- pgStatNumMessages++;
-
- /*
* If this is the first message after we wrote the stats file the
* last time, enable the alarm interrupt to make it be written
* again later.
@@ -2066,66 +2185,6 @@ pgstat_die(SIGNAL_ARGS)
}
-/* ----------
- * pgstat_add_backend() -
- *
- * Support function to keep our backend list up to date.
- * ----------
- */
-static int
-pgstat_add_backend(PgStat_MsgHdr *msg)
-{
- PgStat_StatBeEntry *beentry;
-
- /*
- * Check that the backend ID is valid
- */
- if (msg->m_backendid < 1 || msg->m_backendid > MaxBackends)
- {
- ereport(LOG,
- (errmsg("invalid server process ID %d", msg->m_backendid)));
- return -1;
- }
-
- /*
- * Get the slot for this backendid.
- */
- beentry = &pgStatBeTable[msg->m_backendid - 1];
-
- /*
- * If the slot contains the PID of this backend, everything is fine and we
- * have nothing to do. Note that all the slots are zero'd out when the
- * collector is started. We assume that a slot is "empty" iff procpid ==
- * 0.
- */
- if (beentry->procpid > 0 && beentry->procpid == msg->m_procpid)
- return 0;
-
- /* Must be able to distinguish between empty and non-empty slots */
- Assert(msg->m_procpid > 0);
-
- /*
- * Put this new backend into the slot (possibly overwriting an old entry,
- * if we missed its BETERM or the BETERM hasn't arrived yet).
- */
- beentry->procpid = msg->m_procpid;
- beentry->start_timestamp = GetCurrentTimestamp();
- beentry->activity_start_timestamp = 0;
- beentry->activity[0] = '\0';
-
- /*
- * We can't initialize the rest of the data in this slot until we see the
- * BESTART message. Therefore, we set the database and user to sentinel
- * values, to indicate "undefined". There is no easy way to do this for
- * the client address, so make sure to check that the database or user are
- * defined before accessing the client address.
- */
- beentry->userid = InvalidOid;
- beentry->databaseid = InvalidOid;
-
- return 0;
-}
-
/*
* Lookup the hash table entry for the specified database. If no hash
* table entry exists, initialize it, if the create parameter is true.
@@ -2171,38 +2230,6 @@ pgstat_get_db_entry(Oid databaseid, bool create)
return result;
}
-/* ----------
- * pgstat_sub_backend() -
- *
- * Remove a backend from the actual backends list.
- * ----------
- */
-static void
-pgstat_sub_backend(int procpid)
-{
- int i;
-
- /*
- * Search in the known-backends table for the slot containing this PID.
- */
- for (i = 0; i < MaxBackends; i++)
- {
- if (pgStatBeTable[i].procpid == procpid)
- {
- /*
- * That's him. Mark the backend slot empty.
- */
- pgStatBeTable[i].procpid = 0;
- return;
- }
- }
-
- /*
- * No big problem if not found. This can happen if UDP messages arrive out
- * of order here.
- */
-}
-
/* ----------
* pgstat_write_statsfile() -
@@ -2218,7 +2245,6 @@ pgstat_write_statsfile(void)
PgStat_StatDBEntry *dbentry;
PgStat_StatTabEntry *tabentry;
FILE *fpout;
- int i;
int32 format_id;
/*
@@ -2271,29 +2297,6 @@ pgstat_write_statsfile(void)
}
/*
- * Write out the known running backends to the stats file.
- */
- i = MaxBackends;
- fputc('M', fpout);
- fwrite(&i, sizeof(i), 1, fpout);
-
- for (i = 0; i < MaxBackends; i++)
- {
- PgStat_StatBeEntry *beentry = &pgStatBeTable[i];
-
- if (beentry->procpid > 0)
- {
- int len;
-
- len = offsetof(PgStat_StatBeEntry, activity) +
- strlen(beentry->activity) + 1;
- fputc('B', fpout);
- fwrite(&len, sizeof(len), 1, fpout);
- fwrite(beentry, len, 1, fpout);
- }
- }
-
- /*
* No more output to be done. Close the temp file and replace the old
* pgstat.stat with it. The ferror() check replaces testing for error
* after each individual fputc or fwrite above.
@@ -2327,43 +2330,26 @@ pgstat_write_statsfile(void)
}
}
-/*
- * qsort/bsearch comparison routine for PIDs
- *
- * We assume PIDs are nonnegative, so there's no overflow risk
- */
-static int
-comparePids(const void *v1, const void *v2)
-{
- return *((const int *) v1) - *((const int *) v2);
-}
/* ----------
* pgstat_read_statsfile() -
*
- * Reads in an existing statistics collector and initializes the
- * databases' hash table (whose entries point to the tables' hash tables)
- * and the current backend table.
+ * Reads in an existing statistics collector file and initializes the
+ * databases' hash table (whose entries point to the tables' hash tables).
* ----------
*/
static void
-pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
- PgStat_StatBeEntry **betab, int *numbackends)
+pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
{
PgStat_StatDBEntry *dbentry;
PgStat_StatDBEntry dbbuf;
PgStat_StatTabEntry *tabentry;
PgStat_StatTabEntry tabbuf;
- PgStat_StatBeEntry *beentry;
HASHCTL hash_ctl;
HTAB *tabhash = NULL;
FILE *fpin;
int32 format_id;
- int len;
- int maxbackends = 0;
- int havebackends = 0;
bool found;
- int *live_pids;
MemoryContext use_mcxt;
int mcxt_flags;
@@ -2373,26 +2359,16 @@ 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;
- live_pids = NULL;
}
else
{
use_mcxt = TopTransactionContext;
mcxt_flags = HASH_CONTEXT;
- live_pids = GetAllBackendPids();
- /* Sort the PID array so we can use bsearch */
- if (live_pids[0] > 1)
- qsort((void *) &live_pids[1], live_pids[0], sizeof(int),
- comparePids);
}
/*
@@ -2407,15 +2383,6 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
HASH_ELEM | HASH_FUNCTION | mcxt_flags);
/*
- * Initialize the number of known backends to zero, just in case we do a
- * silent error return below.
- */
- if (numbackends != NULL)
- *numbackends = 0;
- if (betab != NULL)
- *betab = NULL;
-
- /*
* Try to open the status file. If it doesn't exist, the backends simply
* return zero for anything and the collector simply starts from scratch
* with empty counters.
@@ -2472,7 +2439,6 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
memcpy(dbentry, &dbbuf, sizeof(PgStat_StatDBEntry));
dbentry->tables = NULL;
- dbentry->n_backends = 0;
/*
* Don't collect tables if not the requested DB (or the
@@ -2542,111 +2508,6 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb,
break;
/*
- * 'M' The maximum number of backends to expect follows.
- */
- case 'M':
- if (betab == NULL || numbackends == NULL)
- goto done;
- if (fread(&maxbackends, 1, sizeof(maxbackends), fpin) !=
- sizeof(maxbackends))
- {
- ereport(pgStatRunningInCollector ? LOG : WARNING,
- (errmsg("corrupted pgstat.stat file")));
- goto done;
- }
- if (maxbackends == 0)
- goto done;
-
- /*
- * Allocate space (in TopTransactionContext too) for the
- * backend table.
- */
- if (use_mcxt == NULL)
- *betab = (PgStat_StatBeEntry *)
- palloc(sizeof(PgStat_StatBeEntry) * maxbackends);
- else
- *betab = (PgStat_StatBeEntry *)
- MemoryContextAlloc(use_mcxt,
- sizeof(PgStat_StatBeEntry) * maxbackends);
- break;
-
- /*
- * 'B' A PgStat_StatBeEntry follows.
- */
- case 'B':
- if (betab == NULL || numbackends == NULL || *betab == NULL)
- goto done;
-
- if (havebackends >= maxbackends)
- goto done;
-
- /* Read and validate the entry length */
- if (fread(&len, 1, sizeof(len), fpin) != sizeof(len))
- {
- ereport(pgStatRunningInCollector ? LOG : WARNING,
- (errmsg("corrupted pgstat.stat file")));
- goto done;
- }
- if (len <= offsetof(PgStat_StatBeEntry, activity) ||
- len > sizeof(PgStat_StatBeEntry))
- {
- ereport(pgStatRunningInCollector ? LOG : WARNING,
- (errmsg("corrupted pgstat.stat file")));
- goto done;
- }
-
- /*
- * Read it directly into the table.
- */
- beentry = &(*betab)[havebackends];
-
- if (fread(beentry, 1, len, fpin) != len)
- {
- ereport(pgStatRunningInCollector ? LOG : WARNING,
- (errmsg("corrupted pgstat.stat file")));
- goto done;
- }
-
- /*
- * If possible, check PID to verify still running
- */
- if (live_pids &&
- (live_pids[0] == 0 ||
- bsearch((void *) &beentry->procpid,
- (void *) &live_pids[1],
- live_pids[0],
- sizeof(int),
- comparePids) == NULL))
- {
- /*
- * 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,
- &(beentry->databaseid),
- HASH_FIND,
- NULL);
- if (dbentry)
- dbentry->n_backends++;
-
- havebackends++;
- *numbackends = havebackends;
-
- break;
-
- /*
* 'E' The EOF marker of a complete stats file.
*/
case 'E':
@@ -2667,7 +2528,7 @@ done:
* If not done for this transaction, read the statistics collector
* stats file into some hash tables.
*
- * Because we store the hash tables in TopTransactionContext, the result
+ * Because we store the tables in TopTransactionContext, the result
* is good for the entire current main transaction.
*
* Inside the autovacuum process, the statfile is assumed to be valid
@@ -2684,8 +2545,7 @@ backend_read_statsfile(void)
if (pgStatDBHash)
return;
Assert(!pgStatRunningInCollector);
- pgstat_read_statsfile(&pgStatDBHash, InvalidOid,
- &pgStatBeTable, &pgStatNumBackends);
+ pgstat_read_statsfile(&pgStatDBHash, InvalidOid);
}
else
{
@@ -2694,183 +2554,12 @@ backend_read_statsfile(void)
if (!TransactionIdEquals(pgStatDBHashXact, topXid))
{
Assert(!pgStatRunningInCollector);
- pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId,
- &pgStatBeTable, &pgStatNumBackends);
+ pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId);
pgStatDBHashXact = topXid;
}
}
}
-
-/* ----------
- * pgstat_recv_bestart() -
- *
- * Process a backend startup message.
- * ----------
- */
-static void
-pgstat_recv_bestart(PgStat_MsgBestart *msg, int len)
-{
- PgStat_StatBeEntry *entry;
-
- /*
- * If the backend is known dead, we ignore the message -- we don't want to
- * update the backend entry's state since this BESTART message refers to
- * an old, dead backend
- */
- if (pgstat_add_backend(&msg->m_hdr) != 0)
- return;
-
- entry = &(pgStatBeTable[msg->m_hdr.m_backendid - 1]);
- entry->userid = msg->m_userid;
- memcpy(&entry->clientaddr, &msg->m_clientaddr, sizeof(entry->clientaddr));
- entry->databaseid = msg->m_databaseid;
-}
-
-
-/* ----------
- * pgstat_recv_beterm() -
- *
- * Process a backend termination message.
- * ----------
- */
-static void
-pgstat_recv_beterm(PgStat_MsgBeterm *msg, int len)
-{
- pgstat_sub_backend(msg->m_hdr.m_procpid);
-}
-
-/* ----------
- * pgstat_recv_autovac() -
- *
- * Process an autovacuum signalling message.
- * ----------
- */
-static void
-pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len)
-{
- PgStat_StatDBEntry *dbentry;
-
- /*
- * Lookup the database in the hashtable. Don't create the entry if it
- * doesn't exist, because autovacuum may be processing a template
- * database. If this isn't the case, the database is most likely to have
- * an entry already. (If it doesn't, not much harm is done anyway --
- * it'll get created as soon as somebody actually uses the database.)
- */
- dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
- if (dbentry == NULL)
- return;
-
- /*
- * Store the last autovacuum time in the database entry.
- */
- dbentry->last_autovac_time = msg->m_start_time;
-}
-
-/* ----------
- * pgstat_recv_vacuum() -
- *
- * Process a VACUUM message.
- * ----------
- */
-static void
-pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
-{
- PgStat_StatDBEntry *dbentry;
- PgStat_StatTabEntry *tabentry;
-
- /*
- * Don't create either the database or table entry if it doesn't already
- * exist. This avoids bloating the stats with entries for stuff that is
- * only touched by vacuum and not by live operations.
- */
- dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
- if (dbentry == NULL)
- return;
-
- tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
- HASH_FIND, NULL);
- if (tabentry == NULL)
- return;
-
- if (msg->m_autovacuum)
- tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime;
- else
- tabentry->vacuum_timestamp = msg->m_vacuumtime;
- tabentry->n_live_tuples = msg->m_tuples;
- tabentry->n_dead_tuples = 0;
- if (msg->m_analyze)
- {
- tabentry->last_anl_tuples = msg->m_tuples;
- if (msg->m_autovacuum)
- tabentry->autovac_analyze_timestamp = msg->m_vacuumtime;
- else
- tabentry->analyze_timestamp = msg->m_vacuumtime;
- }
-}
-
-/* ----------
- * pgstat_recv_analyze() -
- *
- * Process an ANALYZE message.
- * ----------
- */
-static void
-pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
-{
- PgStat_StatDBEntry *dbentry;
- PgStat_StatTabEntry *tabentry;
-
- /*
- * Don't create either the database or table entry if it doesn't already
- * exist. This avoids bloating the stats with entries for stuff that is
- * only touched by analyze and not by live operations.
- */
- dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
- if (dbentry == NULL)
- return;
-
- tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
- HASH_FIND, NULL);
- if (tabentry == NULL)
- return;
-
- if (msg->m_autovacuum)
- tabentry->autovac_analyze_timestamp = msg->m_analyzetime;
- else
- tabentry->analyze_timestamp = msg->m_analyzetime;
- tabentry->n_live_tuples = msg->m_live_tuples;
- tabentry->n_dead_tuples = msg->m_dead_tuples;
- tabentry->last_anl_tuples = msg->m_live_tuples + msg->m_dead_tuples;
-}
-
-/* ----------
- * pgstat_recv_activity() -
- *
- * Remember what the backend is doing.
- * ----------
- */
-static void
-pgstat_recv_activity(PgStat_MsgActivity *msg, int len)
-{
- PgStat_StatBeEntry *entry;
-
- /*
- * Here we check explicitly for 0 return, since we don't want to mangle
- * the activity of an active backend by a delayed packet from a dead one.
- */
- if (pgstat_add_backend(&msg->m_hdr) != 0)
- return;
-
- entry = &(pgStatBeTable[msg->m_hdr.m_backendid - 1]);
-
- StrNCpy(entry->activity, msg->m_cmd_str, PGSTAT_ACTIVITY_SIZE);
-
- entry->activity_start_timestamp = GetCurrentTimestamp();
-}
-
-
/* ----------
* pgstat_recv_tabstat() -
*
@@ -2886,12 +2575,6 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
int i;
bool found;
- /*
- * Make sure the backend is counted for.
- */
- if (pgstat_add_backend(&msg->m_hdr) < 0)
- return;
-
dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
/*
@@ -2975,12 +2658,6 @@ pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len)
PgStat_StatDBEntry *dbentry;
int i;
- /*
- * Make sure the backend is counted for.
- */
- if (pgstat_add_backend(&msg->m_hdr) < 0)
- return;
-
dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
/*
@@ -3014,12 +2691,6 @@ pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len)
PgStat_StatDBEntry *dbentry;
/*
- * Make sure the backend is counted for.
- */
- if (pgstat_add_backend(&msg->m_hdr) < 0)
- return;
-
- /*
* Lookup the database in the hashtable.
*/
dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
@@ -3055,12 +2726,6 @@ pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
PgStat_StatDBEntry *dbentry;
/*
- * Make sure the backend is counted for.
- */
- if (pgstat_add_backend(&msg->m_hdr) < 0)
- return;
-
- /*
* Lookup the database in the hashtable. Nothing to do if not there.
*/
dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
@@ -3090,3 +2755,108 @@ pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
&hash_ctl,
HASH_ELEM | HASH_FUNCTION);
}
+
+/* ----------
+ * pgstat_recv_autovac() -
+ *
+ * Process an autovacuum signalling message.
+ * ----------
+ */
+static void
+pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len)
+{
+ PgStat_StatDBEntry *dbentry;
+
+ /*
+ * Lookup the database in the hashtable. Don't create the entry if it
+ * doesn't exist, because autovacuum may be processing a template
+ * database. If this isn't the case, the database is most likely to have
+ * an entry already. (If it doesn't, not much harm is done anyway --
+ * it'll get created as soon as somebody actually uses the database.)
+ */
+ dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
+ if (dbentry == NULL)
+ return;
+
+ /*
+ * Store the last autovacuum time in the database entry.
+ */
+ dbentry->last_autovac_time = msg->m_start_time;
+}
+
+/* ----------
+ * pgstat_recv_vacuum() -
+ *
+ * Process a VACUUM message.
+ * ----------
+ */
+static void
+pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
+{
+ PgStat_StatDBEntry *dbentry;
+ PgStat_StatTabEntry *tabentry;
+
+ /*
+ * Don't create either the database or table entry if it doesn't already
+ * exist. This avoids bloating the stats with entries for stuff that is
+ * only touched by vacuum and not by live operations.
+ */
+ dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
+ if (dbentry == NULL)
+ return;
+
+ tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
+ HASH_FIND, NULL);
+ if (tabentry == NULL)
+ return;
+
+ if (msg->m_autovacuum)
+ tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime;
+ else
+ tabentry->vacuum_timestamp = msg->m_vacuumtime;
+ tabentry->n_live_tuples = msg->m_tuples;
+ tabentry->n_dead_tuples = 0;
+ if (msg->m_analyze)
+ {
+ tabentry->last_anl_tuples = msg->m_tuples;
+ if (msg->m_autovacuum)
+ tabentry->autovac_analyze_timestamp = msg->m_vacuumtime;
+ else
+ tabentry->analyze_timestamp = msg->m_vacuumtime;
+ }
+}
+
+/* ----------
+ * pgstat_recv_analyze() -
+ *
+ * Process an ANALYZE message.
+ * ----------
+ */
+static void
+pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
+{
+ PgStat_StatDBEntry *dbentry;
+ PgStat_StatTabEntry *tabentry;
+
+ /*
+ * Don't create either the database or table entry if it doesn't already
+ * exist. This avoids bloating the stats with entries for stuff that is
+ * only touched by analyze and not by live operations.
+ */
+ dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
+ if (dbentry == NULL)
+ return;
+
+ tabentry = hash_search(dbentry->tables, &(msg->m_tableoid),
+ HASH_FIND, NULL);
+ if (tabentry == NULL)
+ return;
+
+ if (msg->m_autovacuum)
+ tabentry->autovac_analyze_timestamp = msg->m_analyzetime;
+ else
+ tabentry->analyze_timestamp = msg->m_analyzetime;
+ tabentry->n_live_tuples = msg->m_live_tuples;
+ tabentry->n_dead_tuples = msg->m_dead_tuples;
+ tabentry->last_anl_tuples = msg->m_live_tuples + msg->m_dead_tuples;
+}
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index fc4a9bcdc33..aac116b466a 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.486 2006/06/18 15:38:37 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.487 2006/06/19 01:51:21 tgl Exp $
*
* NOTES
*
@@ -2109,9 +2109,6 @@ reaper(SIGNAL_ARGS)
{
AutoVacPID = 0;
autovac_stopped();
- /* Tell the collector about process termination */
- pgstat_beterm(pid);
-
if (exitstatus != 0)
HandleChildCrash(pid, exitstatus,
_("autovacuum process"));
@@ -2252,8 +2249,6 @@ CleanupBackend(int pid,
#ifdef EXEC_BACKEND
ShmemBackendArrayRemove(pid);
#endif
- /* Tell the collector about backend termination */
- pgstat_beterm(pid);
break;
}
}
@@ -2299,8 +2294,6 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
#ifdef EXEC_BACKEND
ShmemBackendArrayRemove(pid);
#endif
- /* Tell the collector about backend termination */
- pgstat_beterm(pid);
/* Keep looping so we can signal remaining backends */
}
else
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 872a33ff16b..4beba862de7 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.83 2006/05/08 00:00:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.84 2006/06/19 01:51:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
#include "access/twophase.h"
#include "access/xlog.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "postmaster/bgwriter.h"
#include "postmaster/postmaster.h"
#include "storage/bufmgr.h"
@@ -86,6 +87,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
size = add_size(size, MultiXactShmemSize());
size = add_size(size, LWLockShmemSize());
size = add_size(size, ProcArrayShmemSize());
+ size = add_size(size, BackendStatusShmemSize());
size = add_size(size, SInvalShmemSize());
size = add_size(size, FreeSpaceShmemSize());
size = add_size(size, BgWriterShmemSize());
@@ -167,6 +169,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
if (!IsUnderPostmaster)
InitProcGlobal();
CreateSharedProcArray();
+ CreateSharedBackendStatus();
/*
* Set up shared-inval messaging
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 1cee032b524..f899b7a0e81 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -23,7 +23,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.11 2006/03/05 15:58:37 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.12 2006/06/19 01:51:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -733,42 +733,6 @@ IsBackendPid(int pid)
}
/*
- * GetAllBackendPids -- get an array of all current backends' PIDs
- *
- * The result is a palloc'd array with the number of active backends in
- * entry [0], their PIDs in entries [1] .. [n]. The caller must bear in
- * mind that the result may already be obsolete when returned.
- */
-int *
-GetAllBackendPids(void)
-{
- int *result;
- int npids;
- ProcArrayStruct *arrayP = procArray;
- int index;
-
- result = (int *) palloc((MaxBackends + 1) * sizeof(int));
- npids = 0;
-
- LWLockAcquire(ProcArrayLock, LW_SHARED);
-
- for (index = 0; index < arrayP->numProcs; index++)
- {
- PGPROC *proc = arrayP->procs[index];
-
- if (proc->pid != 0) /* ignore dummy procs */
- result[++npids] = proc->pid;
- }
-
- LWLockRelease(ProcArrayLock);
-
- Assert(npids <= MaxBackends);
-
- result[0] = npids;
- return result;
-}
-
-/*
* CountActiveBackends --- count backends (other than myself) that are in
* active transactions. This is used as a heuristic to decide if
* a pre-XLOG-flush delay is worthwhile during commit.
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index eaf379389e4..dc03beec4de 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.29 2006/05/19 19:08:26 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.30 2006/06/19 01:51:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -61,11 +61,9 @@ extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
Datum
pg_stat_get_numscans(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
int64 result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -79,11 +77,9 @@ pg_stat_get_numscans(PG_FUNCTION_ARGS)
Datum
pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
int64 result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -97,11 +93,9 @@ pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
Datum
pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
int64 result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -115,11 +109,9 @@ pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)
Datum
pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
int64 result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -133,11 +125,9 @@ pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
Datum
pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
int64 result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -151,11 +141,9 @@ pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
Datum
pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
int64 result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -169,11 +157,9 @@ pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
Datum
pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
int64 result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -187,11 +173,9 @@ pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
Datum
pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
int64 result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -204,11 +188,9 @@ pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
Datum
pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
TimestampTz result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -224,11 +206,9 @@ pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS)
Datum
pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
TimestampTz result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -244,11 +224,9 @@ pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS)
Datum
pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
TimestampTz result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -264,11 +242,9 @@ pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS)
Datum
pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)
{
- PgStat_StatTabEntry *tabentry;
- Oid relid;
+ Oid relid = PG_GETARG_OID(0);
TimestampTz result;
-
- relid = PG_GETARG_OID(0);
+ PgStat_StatTabEntry *tabentry;
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0;
@@ -342,75 +318,59 @@ pg_stat_reset(PG_FUNCTION_ARGS)
Datum
pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
{
- PgStat_StatBeEntry *beentry;
- int32 beid;
-
- beid = PG_GETARG_INT32(0);
+ int32 beid = PG_GETARG_INT32(0);
+ PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
- PG_RETURN_INT32(beentry->procpid);
+ PG_RETURN_INT32(beentry->st_procpid);
}
Datum
pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
{
- PgStat_StatBeEntry *beentry;
- int32 beid;
-
- beid = PG_GETARG_INT32(0);
+ int32 beid = PG_GETARG_INT32(0);
+ PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
- /* Not initialized yet? */
- if (!OidIsValid(beentry->databaseid))
- PG_RETURN_NULL();
-
- PG_RETURN_OID(beentry->databaseid);
+ PG_RETURN_OID(beentry->st_databaseid);
}
Datum
pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
{
- PgStat_StatBeEntry *beentry;
- int32 beid;
-
- beid = PG_GETARG_INT32(0);
+ int32 beid = PG_GETARG_INT32(0);
+ PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
- /* Not initialized yet? */
- if (!OidIsValid(beentry->userid))
- PG_RETURN_NULL();
-
- PG_RETURN_OID(beentry->userid);
+ PG_RETURN_OID(beentry->st_userid);
}
Datum
pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
{
- PgStat_StatBeEntry *beentry;
- int32 beid;
- int len;
- char *activity;
+ int32 beid = PG_GETARG_INT32(0);
text *result;
-
- beid = PG_GETARG_INT32(0);
+ PgBackendStatus *beentry;
+ int len;
+ const char *activity;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
activity = "<backend information not available>";
- else if (!superuser() && beentry->userid != GetUserId())
+ else if (!superuser() && beentry->st_userid != GetUserId())
activity = "<insufficient privilege>";
- else if (*(beentry->activity) == '\0')
+ else if (*(beentry->st_activity) == '\0')
activity = "<command string not enabled>";
else
- activity = beentry->activity;
+ activity = beentry->st_activity;
len = strlen(activity);
result = palloc(VARHDRSZ + len);
@@ -426,15 +386,15 @@ pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
{
int32 beid = PG_GETARG_INT32(0);
TimestampTz result;
- PgStat_StatBeEntry *beentry;
+ PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
- if (!superuser() && beentry->userid != GetUserId())
+ if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
- result = beentry->activity_start_timestamp;
+ result = beentry->st_activity_start_timestamp;
/*
* No time recorded for start of current query -- this is the case if the
@@ -451,15 +411,15 @@ pg_stat_get_backend_start(PG_FUNCTION_ARGS)
{
int32 beid = PG_GETARG_INT32(0);
TimestampTz result;
- PgStat_StatBeEntry *beentry;
+ PgBackendStatus *beentry;
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
- if (!superuser() && beentry->userid != GetUserId())
+ if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
- result = beentry->start_timestamp;
+ result = beentry->st_proc_start_timestamp;
if (result == 0) /* probably can't happen? */
PG_RETURN_NULL();
@@ -471,31 +431,25 @@ pg_stat_get_backend_start(PG_FUNCTION_ARGS)
Datum
pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
{
- PgStat_StatBeEntry *beentry;
+ int32 beid = PG_GETARG_INT32(0);
+ PgBackendStatus *beentry;
SockAddr zero_clientaddr;
- int32 beid;
char remote_host[NI_MAXHOST];
int ret;
- beid = PG_GETARG_INT32(0);
-
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
- /* Not initialized yet? */
- if (!OidIsValid(beentry->userid))
- PG_RETURN_NULL();
-
- if (!superuser() && beentry->userid != GetUserId())
+ if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
/* A zeroed client addr means we don't know */
memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
- if (memcmp(&(beentry->clientaddr), &zero_clientaddr,
+ if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
sizeof(zero_clientaddr) == 0))
PG_RETURN_NULL();
- switch (beentry->clientaddr.addr.ss_family)
+ switch (beentry->st_clientaddr.addr.ss_family)
{
case AF_INET:
#ifdef HAVE_IPV6
@@ -507,7 +461,8 @@ pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
}
remote_host[0] = '\0';
- ret = pg_getnameinfo_all(&beentry->clientaddr.addr, beentry->clientaddr.salen,
+ ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
+ beentry->st_clientaddr.salen,
remote_host, sizeof(remote_host),
NULL, 0,
NI_NUMERICHOST | NI_NUMERICSERV);
@@ -521,31 +476,25 @@ pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
Datum
pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
{
- PgStat_StatBeEntry *beentry;
+ int32 beid = PG_GETARG_INT32(0);
+ PgBackendStatus *beentry;
SockAddr zero_clientaddr;
- int32 beid;
char remote_port[NI_MAXSERV];
int ret;
- beid = PG_GETARG_INT32(0);
-
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
PG_RETURN_NULL();
- /* Not initialized yet? */
- if (!OidIsValid(beentry->userid))
- PG_RETURN_NULL();
-
- if (!superuser() && beentry->userid != GetUserId())
+ if (!superuser() && beentry->st_userid != GetUserId())
PG_RETURN_NULL();
/* A zeroed client addr means we don't know */
memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
- if (memcmp(&(beentry->clientaddr), &zero_clientaddr,
+ if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
sizeof(zero_clientaddr) == 0))
PG_RETURN_NULL();
- switch (beentry->clientaddr.addr.ss_family)
+ switch (beentry->st_clientaddr.addr.ss_family)
{
case AF_INET:
#ifdef HAVE_IPV6
@@ -559,31 +508,35 @@ pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
}
remote_port[0] = '\0';
- ret = pg_getnameinfo_all(&beentry->clientaddr.addr,
- beentry->clientaddr.salen,
+ ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
+ beentry->st_clientaddr.salen,
NULL, 0,
remote_port, sizeof(remote_port),
NI_NUMERICHOST | NI_NUMERICSERV);
if (ret)
PG_RETURN_NULL();
- PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(remote_port)));
+ PG_RETURN_DATUM(DirectFunctionCall1(int4in,
+ CStringGetDatum(remote_port)));
}
Datum
pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
{
- PgStat_StatDBEntry *dbentry;
- Oid dbid;
+ Oid dbid = PG_GETARG_OID(0);
int32 result;
+ int tot_backends = pgstat_fetch_stat_numbackends();
+ int beid;
- dbid = PG_GETARG_OID(0);
+ result = 0;
+ for (beid = 1; beid <= tot_backends; beid++)
+ {
+ PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid);
- if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
- result = 0;
- else
- result = (int32) (dbentry->n_backends);
+ if (beentry && beentry->st_databaseid == dbid)
+ result++;
+ }
PG_RETURN_INT32(result);
}
@@ -592,11 +545,9 @@ pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
Datum
pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
{
- PgStat_StatDBEntry *dbentry;
- Oid dbid;
+ Oid dbid = PG_GETARG_OID(0);
int64 result;
-
- dbid = PG_GETARG_OID(0);
+ PgStat_StatDBEntry *dbentry;
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
result = 0;
@@ -610,11 +561,9 @@ pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
Datum
pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
{
- PgStat_StatDBEntry *dbentry;
- Oid dbid;
+ Oid dbid = PG_GETARG_OID(0);
int64 result;
-
- dbid = PG_GETARG_OID(0);
+ PgStat_StatDBEntry *dbentry;
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
result = 0;
@@ -628,11 +577,9 @@ pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
Datum
pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
{
- PgStat_StatDBEntry *dbentry;
- Oid dbid;
+ Oid dbid = PG_GETARG_OID(0);
int64 result;
-
- dbid = PG_GETARG_OID(0);
+ PgStat_StatDBEntry *dbentry;
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
result = 0;
@@ -646,11 +593,9 @@ pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
Datum
pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
{
- PgStat_StatDBEntry *dbentry;
- Oid dbid;
+ Oid dbid = PG_GETARG_OID(0);
int64 result;
-
- dbid = PG_GETARG_OID(0);
+ PgStat_StatDBEntry *dbentry;
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
result = 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 9ef561d4c12..8c3931c8383 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.321 2006/06/05 02:49:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.322 2006/06/19 01:51:21 tgl Exp $
*
*--------------------------------------------------------------------
*/
@@ -701,16 +701,6 @@ static struct config_bool ConfigureNamesBool[] =
false, NULL, NULL
},
{
- {"stats_command_string", PGC_SUSET, STATS_COLLECTOR,
- gettext_noop("Collects statistics about executing commands."),
- gettext_noop("Enables the collection of statistics on the currently "
- "executing command of each session, along with the time "
- "at which that command began execution.")
- },
- &pgstat_collect_querystring,
- false, NULL, NULL
- },
- {
{"stats_row_level", PGC_SUSET, STATS_COLLECTOR,
gettext_noop("Collects row-level statistics on database activity."),
NULL
@@ -728,6 +718,17 @@ static struct config_bool ConfigureNamesBool[] =
},
{
+ {"stats_command_string", PGC_SUSET, STATS_COLLECTOR,
+ gettext_noop("Collects information about executing commands."),
+ gettext_noop("Enables the collection of information on the currently "
+ "executing command of each session, along with the time "
+ "at which that command began execution.")
+ },
+ &pgstat_collect_querystring,
+ false, NULL, NULL
+ },
+
+ {
{"autovacuum", PGC_SIGHUP, AUTOVACUUM,
gettext_noop("Starts the autovacuum subprocess."),
NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index ee5adaa2ff2..26b2be6d6ef 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -320,21 +320,21 @@
# RUNTIME STATISTICS
#---------------------------------------------------------------------------
-# - Statistics Monitoring -
-
-#log_parser_stats = off
-#log_planner_stats = off
-#log_executor_stats = off
-#log_statement_stats = off
-
# - Query/Index Statistics Collector -
-#stats_start_collector = on
#stats_command_string = off
+#stats_start_collector = on # needed for block or row stats
#stats_block_level = off
#stats_row_level = off
#stats_reset_on_server_start = off
+# - Statistics Monitoring -
+
+#log_parser_stats = off
+#log_planner_stats = off
+#log_executor_stats = off
+#log_statement_stats = off
+
#---------------------------------------------------------------------------
# AUTOVACUUM PARAMETERS
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 0e4094bf3e9..83a45d7217f 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -5,7 +5,7 @@
*
* Copyright (c) 2001-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.46 2006/05/30 02:35:39 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.47 2006/06/19 01:51:21 tgl Exp $
* ----------
*/
#ifndef PGSTAT_H
@@ -16,16 +16,14 @@
#include "utils/rel.h"
#include "utils/timestamp.h"
+
/* ----------
- * The types of backend/postmaster -> collector messages
+ * The types of backend -> collector messages
* ----------
*/
typedef enum StatMsgType
{
PGSTAT_MTYPE_DUMMY,
- PGSTAT_MTYPE_BESTART,
- PGSTAT_MTYPE_BETERM,
- PGSTAT_MTYPE_ACTIVITY,
PGSTAT_MTYPE_TABSTAT,
PGSTAT_MTYPE_TABPURGE,
PGSTAT_MTYPE_DROPDB,
@@ -56,8 +54,6 @@ typedef struct PgStat_MsgHdr
{
StatMsgType m_type;
int m_size;
- int m_backendid;
- int m_procpid;
} PgStat_MsgHdr;
/* ----------
@@ -68,6 +64,17 @@ typedef struct PgStat_MsgHdr
*/
#define PGSTAT_MSG_PAYLOAD (1000 - sizeof(PgStat_MsgHdr))
+
+/* ----------
+ * PgStat_MsgDummy A dummy message, ignored by the collector
+ * ----------
+ */
+typedef struct PgStat_MsgDummy
+{
+ PgStat_MsgHdr m_hdr;
+} PgStat_MsgDummy;
+
+
/* ----------
* PgStat_TableEntry Per-table info in a MsgTabstat
*
@@ -96,37 +103,67 @@ typedef struct PgStat_TableEntry
PgStat_Counter t_blocks_hit;
} PgStat_TableEntry;
+/* ----------
+ * PgStat_MsgTabstat Sent by the backend to report table
+ * and buffer access statistics.
+ * ----------
+ */
+#define PGSTAT_NUM_TABENTRIES \
+ ((PGSTAT_MSG_PAYLOAD - sizeof(Oid) - 3 * sizeof(int)) \
+ / sizeof(PgStat_TableEntry))
+
+typedef struct PgStat_MsgTabstat
+{
+ PgStat_MsgHdr m_hdr;
+ Oid m_databaseid;
+ int m_nentries;
+ int m_xact_commit;
+ int m_xact_rollback;
+ PgStat_TableEntry m_entry[PGSTAT_NUM_TABENTRIES];
+} PgStat_MsgTabstat;
+
/* ----------
- * PgStat_MsgDummy A dummy message, ignored by the collector
+ * PgStat_MsgTabpurge Sent by the backend to tell the collector
+ * about dead tables.
* ----------
*/
-typedef struct PgStat_MsgDummy
+#define PGSTAT_NUM_TABPURGE \
+ ((PGSTAT_MSG_PAYLOAD - sizeof(Oid) - sizeof(int)) \
+ / sizeof(Oid))
+
+typedef struct PgStat_MsgTabpurge
{
PgStat_MsgHdr m_hdr;
- char m_dummy[512];
-} PgStat_MsgDummy;
+ Oid m_databaseid;
+ int m_nentries;
+ Oid m_tableid[PGSTAT_NUM_TABPURGE];
+} PgStat_MsgTabpurge;
+
/* ----------
- * PgStat_MsgBestart Sent by the backend on startup
+ * PgStat_MsgDropdb Sent by the backend to tell the collector
+ * about a dropped database
* ----------
*/
-typedef struct PgStat_MsgBestart
+typedef struct PgStat_MsgDropdb
{
PgStat_MsgHdr m_hdr;
Oid m_databaseid;
- Oid m_userid;
- SockAddr m_clientaddr;
-} PgStat_MsgBestart;
+} PgStat_MsgDropdb;
+
/* ----------
- * PgStat_MsgBeterm Sent by the postmaster after backend exit
+ * PgStat_MsgResetcounter Sent by the backend to tell the collector
+ * to reset counters
* ----------
*/
-typedef struct PgStat_MsgBeterm
+typedef struct PgStat_MsgResetcounter
{
PgStat_MsgHdr m_hdr;
-} PgStat_MsgBeterm;
+ Oid m_databaseid;
+} PgStat_MsgResetcounter;
+
/* ----------
* PgStat_MsgAutovacStart Sent by the autovacuum daemon to signal
@@ -140,6 +177,7 @@ typedef struct PgStat_MsgAutovacStart
TimestampTz m_start_time;
} PgStat_MsgAutovacStart;
+
/* ----------
* PgStat_MsgVacuum Sent by the backend or autovacuum daemon
* after VACUUM or VACUUM ANALYZE
@@ -156,6 +194,7 @@ typedef struct PgStat_MsgVacuum
PgStat_Counter m_tuples;
} PgStat_MsgVacuum;
+
/* ----------
* PgStat_MsgAnalyze Sent by the backend or autovacuum daemon
* after ANALYZE
@@ -174,80 +213,6 @@ typedef struct PgStat_MsgAnalyze
/* ----------
- * PgStat_MsgActivity Sent by the backends when they start
- * to parse a query.
- * ----------
- */
-#define PGSTAT_ACTIVITY_SIZE PGSTAT_MSG_PAYLOAD
-
-typedef struct PgStat_MsgActivity
-{
- PgStat_MsgHdr m_hdr;
- char m_cmd_str[PGSTAT_ACTIVITY_SIZE];
-} PgStat_MsgActivity;
-
-/* ----------
- * PgStat_MsgTabstat Sent by the backend to report table
- * and buffer access statistics.
- * ----------
- */
-#define PGSTAT_NUM_TABENTRIES \
- ((PGSTAT_MSG_PAYLOAD - sizeof(Oid) - 3 * sizeof(int)) \
- / sizeof(PgStat_TableEntry))
-
-typedef struct PgStat_MsgTabstat
-{
- PgStat_MsgHdr m_hdr;
- Oid m_databaseid;
- int m_nentries;
- int m_xact_commit;
- int m_xact_rollback;
- PgStat_TableEntry m_entry[PGSTAT_NUM_TABENTRIES];
-} PgStat_MsgTabstat;
-
-/* ----------
- * PgStat_MsgTabpurge Sent by the backend to tell the collector
- * about dead tables.
- * ----------
- */
-#define PGSTAT_NUM_TABPURGE \
- ((PGSTAT_MSG_PAYLOAD - sizeof(Oid) - sizeof(int)) \
- / sizeof(Oid))
-
-typedef struct PgStat_MsgTabpurge
-{
- PgStat_MsgHdr m_hdr;
- Oid m_databaseid;
- int m_nentries;
- Oid m_tableid[PGSTAT_NUM_TABPURGE];
-} PgStat_MsgTabpurge;
-
-
-/* ----------
- * PgStat_MsgDropdb Sent by the backend to tell the collector
- * about a dropped database
- * ----------
- */
-typedef struct PgStat_MsgDropdb
-{
- PgStat_MsgHdr m_hdr;
- Oid m_databaseid;
-} PgStat_MsgDropdb;
-
-
-/* ----------
- * PgStat_MsgResetcounter Sent by the backend to tell the collector
- * to reset counters
- * ----------
- */
-typedef struct PgStat_MsgResetcounter
-{
- PgStat_MsgHdr m_hdr;
- Oid m_databaseid;
-} PgStat_MsgResetcounter;
-
-
-/* ----------
* PgStat_Msg Union over all possible messages.
* ----------
*/
@@ -255,8 +220,6 @@ typedef union PgStat_Msg
{
PgStat_MsgHdr msg_hdr;
PgStat_MsgDummy msg_dummy;
- PgStat_MsgBestart msg_bestart;
- PgStat_MsgActivity msg_activity;
PgStat_MsgTabstat msg_tabstat;
PgStat_MsgTabpurge msg_tabpurge;
PgStat_MsgDropdb msg_dropdb;
@@ -275,19 +238,15 @@ typedef union PgStat_Msg
* ------------------------------------------------------------
*/
-#define PGSTAT_FILE_FORMAT_ID 0x01A5BC95
+#define PGSTAT_FILE_FORMAT_ID 0x01A5BC96
/* ----------
* PgStat_StatDBEntry The collector's data per database
- *
- * Note: n_backends is not maintained within the collector. It's computed
- * when a backend reads the stats file for use.
* ----------
*/
typedef struct PgStat_StatDBEntry
{
Oid databaseid;
- int n_backends;
PgStat_Counter n_xact_commit;
PgStat_Counter n_xact_rollback;
PgStat_Counter n_blocks_fetched;
@@ -303,45 +262,12 @@ typedef struct PgStat_StatDBEntry
/* ----------
- * PgStat_StatBeEntry The collector's data per backend
- * ----------
- */
-typedef struct PgStat_StatBeEntry
-{
- /* An entry is non-empty iff procpid > 0 */
- int procpid;
- TimestampTz start_timestamp;
- TimestampTz activity_start_timestamp;
-
- /*
- * These fields are initialized by the BESTART message. If we have
- * received messages from a backend before we have received its BESTART,
- * these fields will be uninitialized: userid and databaseid will be
- * InvalidOid, and clientaddr will be undefined.
- */
- Oid userid;
- Oid databaseid;
- SockAddr clientaddr;
-
- /*
- * activity[] must be last in the struct, because we only write as much
- * of it as needed to the stats file.
- */
- char activity[PGSTAT_ACTIVITY_SIZE];
-} PgStat_StatBeEntry;
-
-
-/* ----------
* PgStat_StatTabEntry The collector's data per table (or index)
* ----------
*/
typedef struct PgStat_StatTabEntry
{
Oid tableid;
- TimestampTz vacuum_timestamp; /* user initiated vacuum */
- TimestampTz autovac_vacuum_timestamp; /* autovacuum initiated */
- TimestampTz analyze_timestamp; /* user initiated */
- TimestampTz autovac_analyze_timestamp; /* autovacuum initiated */
PgStat_Counter numscans;
@@ -358,27 +284,81 @@ typedef struct PgStat_StatTabEntry
PgStat_Counter blocks_fetched;
PgStat_Counter blocks_hit;
+
+ TimestampTz vacuum_timestamp; /* user initiated vacuum */
+ TimestampTz autovac_vacuum_timestamp; /* autovacuum initiated */
+ TimestampTz analyze_timestamp; /* user initiated */
+ TimestampTz autovac_analyze_timestamp; /* autovacuum initiated */
} PgStat_StatTabEntry;
/* ----------
+ * Shared-memory data structures
+ * ----------
+ */
+
+/* Max length of st_activity string ... perhaps replace with a GUC var? */
+#define PGBE_ACTIVITY_SIZE 1024
+
+/* ----------
+ * PgBackendStatus
+ *
+ * Each live backend maintains a PgBackendStatus struct in shared memory
+ * showing its current activity. (The structs are allocated according to
+ * BackendId, but that is not critical.) Note that the collector process
+ * has no involvement in, or even access to, these structs.
+ * ----------
+ */
+typedef struct PgBackendStatus
+{
+ /*
+ * To avoid locking overhead, we use the following protocol: a backend
+ * increments st_changecount before modifying its entry, and again after
+ * finishing a modification. A would-be reader should note the value
+ * of st_changecount, copy the entry into private memory, then check
+ * st_changecount again. If the value hasn't changed, and if it's even,
+ * the copy is valid; otherwise start over. This makes updates cheap
+ * while reads are potentially expensive, but that's the tradeoff we want.
+ */
+ int st_changecount;
+
+ /* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */
+ int st_procpid;
+
+ /* Times of backend process start and current activity start */
+ TimestampTz st_proc_start_timestamp;
+ TimestampTz st_activity_start_timestamp;
+
+ /* Database OID, owning user's OID, connection client address */
+ Oid st_databaseid;
+ Oid st_userid;
+ SockAddr st_clientaddr;
+
+ /* current command string; MUST be null-terminated */
+ char st_activity[PGBE_ACTIVITY_SIZE];
+} PgBackendStatus;
+
+
+/* ----------
* GUC parameters
* ----------
*/
extern bool pgstat_collect_startcollector;
extern bool pgstat_collect_resetonpmstart;
-extern bool pgstat_collect_querystring;
extern bool pgstat_collect_tuplelevel;
extern bool pgstat_collect_blocklevel;
+extern bool pgstat_collect_querystring;
/* ----------
* Functions called from postmaster
* ----------
*/
+extern Size BackendStatusShmemSize(void);
+extern void CreateSharedBackendStatus(void);
+
extern void pgstat_init(void);
extern int pgstat_start(void);
-extern void pgstat_beterm(int pid);
extern void pgstat_reset_all(void);
#ifdef EXEC_BACKEND
@@ -391,21 +371,23 @@ extern void PgstatCollectorMain(int argc, char *argv[]);
* Functions called from backends
* ----------
*/
-extern void pgstat_bestart(void);
-
extern void pgstat_ping(void);
-extern void pgstat_report_activity(const char *what);
+
extern void pgstat_report_tabstat(void);
+extern void pgstat_vacuum_tabstat(void);
+extern void pgstat_drop_relation(Oid relid);
+
+extern void pgstat_reset_counters(void);
+
extern void pgstat_report_autovac(Oid dboid);
extern void pgstat_report_vacuum(Oid tableoid, bool shared,
bool analyze, PgStat_Counter tuples);
extern void pgstat_report_analyze(Oid tableoid, bool shared,
PgStat_Counter livetuples,
PgStat_Counter deadtuples);
-extern void pgstat_vacuum_tabstat(void);
-extern void pgstat_drop_relation(Oid relid);
-extern void pgstat_reset_counters(void);
+extern void pgstat_bestart(void);
+extern void pgstat_report_activity(const char *what);
extern void pgstat_initstats(PgStat_Info *stats, Relation rel);
@@ -492,7 +474,7 @@ extern void pgstat_count_xact_rollback(void);
*/
extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
-extern PgStat_StatBeEntry *pgstat_fetch_stat_beentry(int beid);
+extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid);
extern int pgstat_fetch_stat_numbackends(void);
#endif /* PGSTAT_H */
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index a7da09a07b7..e1710701a1d 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.8 2006/03/05 15:59:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.9 2006/06/19 01:51:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,7 +29,6 @@ extern TransactionId GetOldestXmin(bool allDbs);
extern PGPROC *BackendPidGetProc(int pid);
extern int BackendXidGetPid(TransactionId xid);
extern bool IsBackendPid(int pid);
-extern int *GetAllBackendPids(void);
extern bool DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself);
extern int CountActiveBackends(void);