1313 *
1414 * Copyright (c) 2001-2007, PostgreSQL Global Development Group
1515 *
16- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.144 2007/01/26 20:06:52 tgl Exp $
16+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.145 2007/02/07 23:11:29 tgl Exp $
1717 * ----------
1818 */
1919#include "postgres.h"
@@ -130,9 +130,8 @@ static TabStatArray SharedTabStat = {0, 0, NULL};
130130static int pgStatXactCommit = 0 ;
131131static int pgStatXactRollback = 0 ;
132132
133- static TransactionId pgStatDBHashXact = InvalidTransactionId ;
133+ static MemoryContext pgStatLocalContext = NULL ;
134134static HTAB * pgStatDBHash = NULL ;
135- static TransactionId pgStatLocalStatusXact = InvalidTransactionId ;
136135static PgBackendStatus * localBackendStatusTable = NULL ;
137136static int localNumBackends = 0 ;
138137
@@ -156,11 +155,13 @@ static void pgstat_beshutdown_hook(int code, Datum arg);
156155static PgStat_StatDBEntry * pgstat_get_db_entry (Oid databaseid , bool create );
157156static void pgstat_drop_database (Oid databaseid );
158157static void pgstat_write_statsfile (void );
159- static void pgstat_read_statsfile ( HTAB * * dbhash , Oid onlydb );
158+ static HTAB * pgstat_read_statsfile ( Oid onlydb );
160159static void backend_read_statsfile (void );
161160static void pgstat_read_current_status (void );
162161static HTAB * pgstat_collect_oids (Oid catalogid );
163162
163+ static void pgstat_setup_memcxt (void );
164+
164165static void pgstat_setheader (PgStat_MsgHdr * hdr , StatMsgType mtype );
165166static void pgstat_send (void * msg , int len );
166167
@@ -1535,22 +1536,24 @@ pgstat_report_waiting(bool waiting)
15351536static void
15361537pgstat_read_current_status (void )
15371538{
1538- TransactionId topXid = GetTopTransactionId ();
15391539 volatile PgBackendStatus * beentry ;
1540+ PgBackendStatus * localtable ;
15401541 PgBackendStatus * localentry ;
15411542 int i ;
15421543
15431544 Assert (!pgStatRunningInCollector );
1544- if (TransactionIdEquals ( pgStatLocalStatusXact , topXid ) )
1545+ if (localBackendStatusTable )
15451546 return ; /* already done */
15461547
1547- localBackendStatusTable = (PgBackendStatus * )
1548- MemoryContextAlloc (TopTransactionContext ,
1548+ pgstat_setup_memcxt ();
1549+
1550+ localtable = (PgBackendStatus * )
1551+ MemoryContextAlloc (pgStatLocalContext ,
15491552 sizeof (PgBackendStatus ) * MaxBackends );
15501553 localNumBackends = 0 ;
15511554
15521555 beentry = BackendStatusArray ;
1553- localentry = localBackendStatusTable ;
1556+ localentry = localtable ;
15541557 for (i = 1 ; i <= MaxBackends ; i ++ )
15551558 {
15561559 /*
@@ -1587,7 +1590,8 @@ pgstat_read_current_status(void)
15871590 }
15881591 }
15891592
1590- pgStatLocalStatusXact = topXid ;
1593+ /* Set the pointer only after completion of a valid table */
1594+ localBackendStatusTable = localtable ;
15911595}
15921596
15931597
@@ -1720,7 +1724,7 @@ PgstatCollectorMain(int argc, char *argv[])
17201724 * zero.
17211725 */
17221726 pgStatRunningInCollector = true;
1723- pgstat_read_statsfile ( & pgStatDBHash , InvalidOid );
1727+ pgStatDBHash = pgstat_read_statsfile ( InvalidOid );
17241728
17251729 /*
17261730 * Setup the descriptor set for select(2). Since only one bit in the set
@@ -2090,38 +2094,24 @@ pgstat_write_statsfile(void)
20902094 * databases' hash table (whose entries point to the tables' hash tables).
20912095 * ----------
20922096 */
2093- static void
2094- pgstat_read_statsfile (HTAB * * dbhash , Oid onlydb )
2097+ static HTAB *
2098+ pgstat_read_statsfile (Oid onlydb )
20952099{
20962100 PgStat_StatDBEntry * dbentry ;
20972101 PgStat_StatDBEntry dbbuf ;
20982102 PgStat_StatTabEntry * tabentry ;
20992103 PgStat_StatTabEntry tabbuf ;
21002104 HASHCTL hash_ctl ;
2105+ HTAB * dbhash ;
21012106 HTAB * tabhash = NULL ;
21022107 FILE * fpin ;
21032108 int32 format_id ;
21042109 bool found ;
2105- MemoryContext use_mcxt ;
2106- int mcxt_flags ;
21072110
21082111 /*
2109- * If running in the collector or the autovacuum process, we use the
2110- * DynaHashCxt memory context. If running in a backend, we use the
2111- * TopTransactionContext instead, so the caller must only know the last
2112- * XactId when this call happened to know if his tables are still valid or
2113- * already gone!
2112+ * The tables will live in pgStatLocalContext.
21142113 */
2115- if (pgStatRunningInCollector || IsAutoVacuumProcess ())
2116- {
2117- use_mcxt = NULL ;
2118- mcxt_flags = 0 ;
2119- }
2120- else
2121- {
2122- use_mcxt = TopTransactionContext ;
2123- mcxt_flags = HASH_CONTEXT ;
2124- }
2114+ pgstat_setup_memcxt ();
21252115
21262116 /*
21272117 * Create the DB hashtable
@@ -2130,17 +2120,17 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
21302120 hash_ctl .keysize = sizeof (Oid );
21312121 hash_ctl .entrysize = sizeof (PgStat_StatDBEntry );
21322122 hash_ctl .hash = oid_hash ;
2133- hash_ctl .hcxt = use_mcxt ;
2134- * dbhash = hash_create ("Databases hash" , PGSTAT_DB_HASH_SIZE , & hash_ctl ,
2135- HASH_ELEM | HASH_FUNCTION | mcxt_flags );
2123+ hash_ctl .hcxt = pgStatLocalContext ;
2124+ dbhash = hash_create ("Databases hash" , PGSTAT_DB_HASH_SIZE , & hash_ctl ,
2125+ HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT );
21362126
21372127 /*
21382128 * Try to open the status file. If it doesn't exist, the backends simply
21392129 * return zero for anything and the collector simply starts from scratch
21402130 * with empty counters.
21412131 */
21422132 if ((fpin = AllocateFile (PGSTAT_STAT_FILENAME , PG_BINARY_R )) == NULL )
2143- return ;
2133+ return dbhash ;
21442134
21452135 /*
21462136 * Verify it's of the expected format.
@@ -2178,7 +2168,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
21782168 /*
21792169 * Add to the DB hash
21802170 */
2181- dbentry = (PgStat_StatDBEntry * ) hash_search (* dbhash ,
2171+ dbentry = (PgStat_StatDBEntry * ) hash_search (dbhash ,
21822172 (void * ) & dbbuf .databaseid ,
21832173 HASH_ENTER ,
21842174 & found );
@@ -2207,11 +2197,11 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
22072197 hash_ctl .keysize = sizeof (Oid );
22082198 hash_ctl .entrysize = sizeof (PgStat_StatTabEntry );
22092199 hash_ctl .hash = oid_hash ;
2210- hash_ctl .hcxt = use_mcxt ;
2200+ hash_ctl .hcxt = pgStatLocalContext ;
22112201 dbentry -> tables = hash_create ("Per-database table" ,
22122202 PGSTAT_TAB_HASH_SIZE ,
22132203 & hash_ctl ,
2214- HASH_ELEM | HASH_FUNCTION | mcxt_flags );
2204+ HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT );
22152205
22162206 /*
22172207 * Arrange that following 'T's add entries to this database's
@@ -2274,44 +2264,78 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
22742264
22752265done :
22762266 FreeFile (fpin );
2267+
2268+ return dbhash ;
22772269}
22782270
22792271/*
2280- * If not done for this transaction, read the statistics collector
2281- * stats file into some hash tables.
2282- *
2283- * Because we store the tables in TopTransactionContext, the result
2284- * is good for the entire current main transaction.
2285- *
2286- * Inside the autovacuum process, the statfile is assumed to be valid
2287- * "forever", that is one iteration, within one database. This means
2288- * we only consider the statistics as they were when the autovacuum
2289- * iteration started.
2272+ * If not already done, read the statistics collector stats file into
2273+ * some hash tables. The results will be kept until pgstat_clear_snapshot()
2274+ * is called (typically, at end of transaction).
22902275 */
22912276static void
22922277backend_read_statsfile (void )
22932278{
2279+ /* already read it? */
2280+ if (pgStatDBHash )
2281+ return ;
2282+ Assert (!pgStatRunningInCollector );
2283+
2284+ /* Autovacuum wants stats about all databases */
22942285 if (IsAutoVacuumProcess ())
2295- {
2296- /* already read it? */
2297- if (pgStatDBHash )
2298- return ;
2299- Assert (!pgStatRunningInCollector );
2300- pgstat_read_statsfile (& pgStatDBHash , InvalidOid );
2301- }
2286+ pgStatDBHash = pgstat_read_statsfile (InvalidOid );
23022287 else
2303- {
2304- TransactionId topXid = GetTopTransactionId ();
2288+ pgStatDBHash = pgstat_read_statsfile ( MyDatabaseId );
2289+ }
23052290
2306- if (!TransactionIdEquals (pgStatDBHashXact , topXid ))
2307- {
2308- Assert (!pgStatRunningInCollector );
2309- pgstat_read_statsfile (& pgStatDBHash , MyDatabaseId );
2310- pgStatDBHashXact = topXid ;
2311- }
2312- }
2291+
2292+ /* ----------
2293+ * pgstat_setup_memcxt() -
2294+ *
2295+ * Create pgStatLocalContext, if not already done.
2296+ * ----------
2297+ */
2298+ static void
2299+ pgstat_setup_memcxt (void )
2300+ {
2301+ if (!pgStatLocalContext )
2302+ pgStatLocalContext = AllocSetContextCreate (TopMemoryContext ,
2303+ "Statistics snapshot" ,
2304+ ALLOCSET_SMALL_MINSIZE ,
2305+ ALLOCSET_SMALL_INITSIZE ,
2306+ ALLOCSET_SMALL_MAXSIZE );
23132307}
23142308
2309+
2310+ /* ----------
2311+ * pgstat_clear_snapshot() -
2312+ *
2313+ * Discard any data collected in the current transaction. Any subsequent
2314+ * request will cause new snapshots to be read.
2315+ *
2316+ * This is also invoked during transaction commit or abort to discard
2317+ * the no-longer-wanted snapshot.
2318+ * ----------
2319+ */
2320+ void
2321+ pgstat_clear_snapshot (void )
2322+ {
2323+ /* In an autovacuum process we keep the stats forever */
2324+ if (IsAutoVacuumProcess ())
2325+ return ;
2326+
2327+ /* Release memory, if any was allocated */
2328+ if (pgStatLocalContext )
2329+ MemoryContextDelete (pgStatLocalContext );
2330+
2331+ /* Reset variables */
2332+ pgStatLocalContext = NULL ;
2333+ pgStatDBHash = NULL ;
2334+ localBackendStatusTable = NULL ;
2335+ localNumBackends = 0 ;
2336+ }
2337+
2338+
23152339/* ----------
23162340 * pgstat_recv_tabstat() -
23172341 *
0 commit comments