1313 *
1414 * Copyright (c) 2001-2005, PostgreSQL Global Development Group
1515 *
16- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.93 2005/05/09 11:31:33 neilc Exp $
16+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.94 2005/05/11 01:41:40 neilc Exp $
1717 * ----------
1818 */
1919#include "postgres.h"
@@ -162,6 +162,7 @@ static void pgstat_exit(SIGNAL_ARGS);
162162static void pgstat_die (SIGNAL_ARGS );
163163static void pgstat_beshutdown_hook (int code , Datum arg );
164164
165+ static PgStat_StatDBEntry * pgstat_get_db_entry (int databaseid );
165166static int pgstat_add_backend (PgStat_MsgHdr * msg );
166167static void pgstat_sub_backend (int procpid );
167168static void pgstat_drop_database (Oid databaseid );
@@ -653,6 +654,9 @@ pgstat_bestart(void)
653654 return ;
654655
655656 pgstat_setheader (& msg .m_hdr , PGSTAT_MTYPE_BESTART );
657+ msg .m_databaseid = MyDatabaseId ;
658+ msg .m_userid = GetSessionUserId ();
659+ memcpy (& msg .m_clientaddr , & MyProcPort -> raddr , sizeof (msg .m_clientaddr ));
656660 pgstat_send (& msg , sizeof (msg ));
657661
658662 /*
@@ -748,6 +752,7 @@ pgstat_report_tabstat(void)
748752 pgStatXactRollback = 0 ;
749753
750754 pgstat_setheader (& tsmsg -> m_hdr , PGSTAT_MTYPE_TABSTAT );
755+ tsmsg -> m_databaseid = MyDatabaseId ;
751756 pgstat_send (tsmsg , len );
752757 }
753758
@@ -825,7 +830,7 @@ pgstat_vacuum_tabstat(void)
825830 }
826831
827832 /*
828- * Add this tables Oid to the message
833+ * Add this table's Oid to the message
829834 */
830835 msg .m_tableid [msg .m_nentries ++ ] = tabentry -> tableid ;
831836 nobjects ++ ;
@@ -854,6 +859,7 @@ pgstat_vacuum_tabstat(void)
854859 + msg .m_nentries * sizeof (Oid );
855860
856861 pgstat_setheader (& msg .m_hdr , PGSTAT_MTYPE_TABPURGE );
862+ msg .m_databaseid = MyDatabaseId ;
857863 pgstat_send (& msg , len );
858864 }
859865
@@ -933,9 +939,8 @@ pgstat_drop_database(Oid databaseid)
933939 if (pgStatSock < 0 )
934940 return ;
935941
936- msg .m_databaseid = databaseid ;
937-
938942 pgstat_setheader (& msg .m_hdr , PGSTAT_MTYPE_DROPDB );
943+ msg .m_databaseid = databaseid ;
939944 pgstat_send (& msg , sizeof (msg ));
940945}
941946
@@ -960,6 +965,7 @@ pgstat_reset_counters(void)
960965 errmsg ("must be superuser to reset statistics counters" )));
961966
962967 pgstat_setheader (& msg .m_hdr , PGSTAT_MTYPE_RESETCOUNTER );
968+ msg .m_databaseid = MyDatabaseId ;
963969 pgstat_send (& msg , sizeof (msg ));
964970}
965971
@@ -1176,24 +1182,18 @@ pgstat_count_xact_rollback(void)
11761182PgStat_StatDBEntry *
11771183pgstat_fetch_stat_dbentry (Oid dbid )
11781184{
1179- PgStat_StatDBEntry * dbentry ;
1180-
11811185 /*
11821186 * If not done for this transaction, read the statistics collector
11831187 * stats file into some hash tables.
11841188 */
11851189 backend_read_statsfile ();
11861190
11871191 /*
1188- * Lookup the requested database
1192+ * Lookup the requested database; return NULL if not found
11891193 */
1190- dbentry = (PgStat_StatDBEntry * ) hash_search (pgStatDBHash ,
1191- (void * ) & dbid ,
1192- HASH_FIND , NULL );
1193- if (dbentry == NULL )
1194- return NULL ;
1195-
1196- return dbentry ;
1194+ return (PgStat_StatDBEntry * ) hash_search (pgStatDBHash ,
1195+ (void * ) & dbid ,
1196+ HASH_FIND , NULL );
11971197}
11981198
11991199
@@ -1298,9 +1298,6 @@ pgstat_setheader(PgStat_MsgHdr *hdr, int mtype)
12981298 hdr -> m_type = mtype ;
12991299 hdr -> m_backendid = MyBackendId ;
13001300 hdr -> m_procpid = MyProcPid ;
1301- hdr -> m_databaseid = MyDatabaseId ;
1302- hdr -> m_userid = GetSessionUserId ();
1303- memcpy (& hdr -> m_clientaddr , & MyProcPort -> raddr , sizeof (hdr -> m_clientaddr ));
13041301}
13051302
13061303
@@ -1976,10 +1973,8 @@ pgstat_die(SIGNAL_ARGS)
19761973static int
19771974pgstat_add_backend (PgStat_MsgHdr * msg )
19781975{
1979- PgStat_StatDBEntry * dbentry ;
19801976 PgStat_StatBeEntry * beentry ;
19811977 PgStat_StatBeDead * deadbe ;
1982- bool found ;
19831978
19841979 /*
19851980 * Check that the backend ID is valid
@@ -1995,19 +1990,19 @@ pgstat_add_backend(PgStat_MsgHdr *msg)
19951990 * Get the slot for this backendid.
19961991 */
19971992 beentry = & pgStatBeTable [msg -> m_backendid - 1 ];
1998- if ( beentry -> databaseid != InvalidOid )
1999- {
2000- /*
2001- * If the slot contains the PID of this backend, everything is
2002- * fine and we got nothing to do.
2003- */
2004- if ( beentry -> procpid == msg -> m_procpid )
2005- return 0 ;
2006- }
1993+
1994+ /*
1995+ * If the slot contains the PID of this backend, everything is
1996+ * fine and we have nothing to do. Note that all the slots are
1997+ * zero'd out when the collector is started. We assume that a slot
1998+ * is "empty" iff procpid == 0.
1999+ */
2000+ if ( beentry -> procpid > 0 && beentry -> procpid == msg -> m_procpid )
2001+ return 0 ;
20072002
20082003 /*
20092004 * Lookup if this backend is known to be dead. This can be caused due
2010- * to messages arriving in the wrong order - i.e. Postmaster 's BETERM
2005+ * to messages arriving in the wrong order - e.g. postmaster 's BETERM
20112006 * message might have arrived before we received all the backends
20122007 * stats messages, or even a new backend with the same backendid was
20132008 * faster in sending his BESTART.
@@ -2024,65 +2019,78 @@ pgstat_add_backend(PgStat_MsgHdr *msg)
20242019 * Backend isn't known to be dead. If it's slot is currently used, we
20252020 * have to kick out the old backend.
20262021 */
2027- if (beentry -> databaseid != InvalidOid )
2022+ if (beentry -> procpid > 0 )
20282023 pgstat_sub_backend (beentry -> procpid );
20292024
2030- /*
2031- * Put this new backend into the slot.
2032- */
2033- beentry -> databaseid = msg -> m_databaseid ;
2025+ /* Must be able to distinguish between empty and non-empty slots */
2026+ Assert ( msg -> m_procpid > 0 );
2027+
2028+ /* Put this new backend into the slot */
20342029 beentry -> procpid = msg -> m_procpid ;
2035- beentry -> userid = msg -> m_userid ;
20362030 beentry -> start_sec =
20372031 GetCurrentAbsoluteTimeUsec (& beentry -> start_usec );
20382032 beentry -> activity_start_sec = 0 ;
20392033 beentry -> activity_start_usec = 0 ;
2040- memcpy (& beentry -> clientaddr , & msg -> m_clientaddr , sizeof (beentry -> clientaddr ));
2041- MemSet (beentry -> activity , 0 , PGSTAT_ACTIVITY_SIZE );
2034+ beentry -> activity [0 ] = '\0' ;
20422035
20432036 /*
2044- * Lookup or create the database entry for this backend's DB.
2037+ * We can't initialize the rest of the data in this slot until we
2038+ * see the BESTART message. Therefore, we set the database and
2039+ * user to sentinel values, to indicate "undefined". There is no
2040+ * easy way to do this for the client address, so make sure to
2041+ * check that the database or user are defined before accessing
2042+ * the client address.
20452043 */
2046- dbentry = (PgStat_StatDBEntry * ) hash_search (pgStatDBHash ,
2047- (void * ) & (msg -> m_databaseid ),
2048- HASH_ENTER , & found );
2049- if (dbentry == NULL )
2044+ beentry -> userid = InvalidOid ;
2045+ beentry -> databaseid = InvalidOid ;
2046+
2047+ return 0 ;
2048+ }
2049+
2050+ /*
2051+ * Lookup the hash table entry for the specified database. If no hash
2052+ * table entry exists, initialize it.
2053+ */
2054+ static PgStat_StatDBEntry *
2055+ pgstat_get_db_entry (int databaseid )
2056+ {
2057+ PgStat_StatDBEntry * result ;
2058+ bool found ;
2059+
2060+ /* Lookup or create the hash table entry for this database */
2061+ result = (PgStat_StatDBEntry * ) hash_search (pgStatDBHash ,
2062+ & databaseid ,
2063+ HASH_ENTER , & found );
2064+ if (result == NULL )
20502065 ereport (ERROR ,
20512066 (errcode (ERRCODE_OUT_OF_MEMORY ),
2052- errmsg ("out of memory in statistics collector --- abort" )));
2067+ errmsg ("out of memory in statistics collector --- abort" )));
20532068
2054- /*
2055- * If not found, initialize the new one.
2056- */
2069+ /* If not found, initialize the new one. */
20572070 if (!found )
20582071 {
20592072 HASHCTL hash_ctl ;
20602073
2061- dbentry -> tables = NULL ;
2062- dbentry -> n_xact_commit = 0 ;
2063- dbentry -> n_xact_rollback = 0 ;
2064- dbentry -> n_blocks_fetched = 0 ;
2065- dbentry -> n_blocks_hit = 0 ;
2066- dbentry -> n_connects = 0 ;
2067- dbentry -> destroy = 0 ;
2074+ result -> tables = NULL ;
2075+ result -> n_xact_commit = 0 ;
2076+ result -> n_xact_rollback = 0 ;
2077+ result -> n_blocks_fetched = 0 ;
2078+ result -> n_blocks_hit = 0 ;
2079+ result -> destroy = 0 ;
20682080
20692081 memset (& hash_ctl , 0 , sizeof (hash_ctl ));
20702082 hash_ctl .keysize = sizeof (Oid );
20712083 hash_ctl .entrysize = sizeof (PgStat_StatTabEntry );
20722084 hash_ctl .hash = oid_hash ;
2073- dbentry -> tables = hash_create ("Per-database table" ,
2085+ result -> tables = hash_create ("Per-database table" ,
20742086 PGSTAT_TAB_HASH_SIZE ,
20752087 & hash_ctl ,
20762088 HASH_ELEM | HASH_FUNCTION );
20772089 }
20782090
2079- /* Count the number of connects to the database */
2080- dbentry -> n_connects ++ ;
2081-
2082- return 0 ;
2091+ return result ;
20832092}
20842093
2085-
20862094/* ----------
20872095 * pgstat_sub_backend() -
20882096 *
@@ -2102,8 +2110,7 @@ pgstat_sub_backend(int procpid)
21022110 */
21032111 for (i = 0 ; i < MaxBackends ; i ++ )
21042112 {
2105- if (pgStatBeTable [i ].databaseid != InvalidOid &&
2106- pgStatBeTable [i ].procpid == procpid )
2113+ if (pgStatBeTable [i ].procpid == procpid )
21072114 {
21082115 /*
21092116 * That's him. Add an entry to the known to be dead backends.
@@ -2133,7 +2140,7 @@ pgstat_sub_backend(int procpid)
21332140 /*
21342141 * Declare the backend slot empty.
21352142 */
2136- pgStatBeTable [i ].databaseid = InvalidOid ;
2143+ pgStatBeTable [i ].procpid = 0 ;
21372144 return ;
21382145 }
21392146 }
@@ -2263,7 +2270,7 @@ pgstat_write_statsfile(void)
22632270
22642271 for (i = 0 ; i < MaxBackends ; i ++ )
22652272 {
2266- if (pgStatBeTable [i ].databaseid != InvalidOid )
2273+ if (pgStatBeTable [i ].procpid > 0 )
22672274 {
22682275 fputc ('B' , fpout );
22692276 fwrite (& pgStatBeTable [i ], sizeof (PgStat_StatBeEntry ), 1 , fpout );
@@ -2624,7 +2631,20 @@ backend_read_statsfile(void)
26242631static void
26252632pgstat_recv_bestart (PgStat_MsgBestart * msg , int len )
26262633{
2627- pgstat_add_backend (& msg -> m_hdr );
2634+ PgStat_StatBeEntry * entry ;
2635+
2636+ /*
2637+ * If the backend is known dead, we ignore the message -- we don't
2638+ * want to update the backend entry's state since this BESTART
2639+ * message refers to an old, dead backend
2640+ */
2641+ if (pgstat_add_backend (& msg -> m_hdr ) != 0 )
2642+ return ;
2643+
2644+ entry = & (pgStatBeTable [msg -> m_hdr .m_backendid - 1 ]);
2645+ entry -> userid = msg -> m_userid ;
2646+ memcpy (& entry -> clientaddr , & msg -> m_clientaddr , sizeof (entry -> clientaddr ));
2647+ entry -> databaseid = msg -> m_databaseid ;
26282648}
26292649
26302650
@@ -2690,14 +2710,7 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
26902710 if (pgstat_add_backend (& msg -> m_hdr ) < 0 )
26912711 return ;
26922712
2693- /*
2694- * Lookup the database in the hashtable.
2695- */
2696- dbentry = (PgStat_StatDBEntry * ) hash_search (pgStatDBHash ,
2697- (void * ) & (msg -> m_hdr .m_databaseid ),
2698- HASH_FIND , NULL );
2699- if (!dbentry )
2700- return ;
2713+ dbentry = pgstat_get_db_entry (msg -> m_databaseid );
27012714
27022715 /*
27032716 * If the database is marked for destroy, this is a delayed UDP packet
@@ -2782,14 +2795,7 @@ pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len)
27822795 if (pgstat_add_backend (& msg -> m_hdr ) < 0 )
27832796 return ;
27842797
2785- /*
2786- * Lookup the database in the hashtable.
2787- */
2788- dbentry = (PgStat_StatDBEntry * ) hash_search (pgStatDBHash ,
2789- (void * ) & (msg -> m_hdr .m_databaseid ),
2790- HASH_FIND , NULL );
2791- if (!dbentry )
2792- return ;
2798+ dbentry = pgstat_get_db_entry (msg -> m_databaseid );
27932799
27942800 /*
27952801 * If the database is marked for destroy, this is a delayed UDP packet
@@ -2832,11 +2838,7 @@ pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len)
28322838 /*
28332839 * Lookup the database in the hashtable.
28342840 */
2835- dbentry = (PgStat_StatDBEntry * ) hash_search (pgStatDBHash ,
2836- (void * ) & (msg -> m_databaseid ),
2837- HASH_FIND , NULL );
2838- if (!dbentry )
2839- return ;
2841+ dbentry = pgstat_get_db_entry (msg -> m_databaseid );
28402842
28412843 /*
28422844 * Mark the database for destruction.
@@ -2846,9 +2848,9 @@ pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len)
28462848
28472849
28482850/* ----------
2849- * pgstat_recv_dropdb () -
2851+ * pgstat_recv_resetcounter () -
28502852 *
2851- * Arrange for dead database removal
2853+ * Reset the statistics for the specified database.
28522854 * ----------
28532855 */
28542856static void
@@ -2866,15 +2868,11 @@ pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
28662868 /*
28672869 * Lookup the database in the hashtable.
28682870 */
2869- dbentry = (PgStat_StatDBEntry * ) hash_search (pgStatDBHash ,
2870- (void * ) & (msg -> m_hdr .m_databaseid ),
2871- HASH_FIND , NULL );
2872- if (!dbentry )
2873- return ;
2871+ dbentry = pgstat_get_db_entry (msg -> m_databaseid );
28742872
28752873 /*
2876- * We simply throw away all the databases table entries by recreating
2877- * a new hash table for them.
2874+ * We simply throw away all the database's table entries by
2875+ * recreating a new hash table for them.
28782876 */
28792877 if (dbentry -> tables != NULL )
28802878 hash_destroy (dbentry -> tables );
@@ -2884,7 +2882,6 @@ pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len)
28842882 dbentry -> n_xact_rollback = 0 ;
28852883 dbentry -> n_blocks_fetched = 0 ;
28862884 dbentry -> n_blocks_hit = 0 ;
2887- dbentry -> n_connects = 0 ;
28882885 dbentry -> destroy = 0 ;
28892886
28902887 memset (& hash_ctl , 0 , sizeof (hash_ctl ));
0 commit comments