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 ();
15391539volatile PgBackendStatus * beentry ;
1540+ PgBackendStatus * localtable ;
15401541PgBackendStatus * localentry ;
15411542int i ;
15421543
15431544Assert (!pgStatRunningInCollector );
1544- if (TransactionIdEquals ( pgStatLocalStatusXact , topXid ) )
1545+ if (localBackendStatusTable )
15451546return ;/* already done */
15461547
1547- localBackendStatusTable = (PgBackendStatus * )
1548- MemoryContextAlloc (TopTransactionContext ,
1548+ pgstat_setup_memcxt ();
1549+
1550+ localtable = (PgBackendStatus * )
1551+ MemoryContextAlloc (pgStatLocalContext ,
15491552sizeof (PgBackendStatus )* MaxBackends );
15501553localNumBackends = 0 ;
15511554
15521555beentry = BackendStatusArray ;
1553- localentry = localBackendStatusTable ;
1556+ localentry = localtable ;
15541557for (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 */
17221726pgStatRunningInCollector = 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{
20962100PgStat_StatDBEntry * dbentry ;
20972101PgStat_StatDBEntry dbbuf ;
20982102PgStat_StatTabEntry * tabentry ;
20992103PgStat_StatTabEntry tabbuf ;
21002104HASHCTL hash_ctl ;
2105+ HTAB * dbhash ;
21012106HTAB * tabhash = NULL ;
21022107FILE * fpin ;
21032108int32 format_id ;
21042109bool 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)
21302120hash_ctl .keysize = sizeof (Oid );
21312121hash_ctl .entrysize = sizeof (PgStat_StatDBEntry );
21322122hash_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 */
21422132if ((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 ,
21832173HASH_ENTER ,
21842174& found );
@@ -2207,11 +2197,11 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
22072197hash_ctl .keysize = sizeof (Oid );
22082198hash_ctl .entrysize = sizeof (PgStat_StatTabEntry );
22092199hash_ctl .hash = oid_hash ;
2210- hash_ctl .hcxt = use_mcxt ;
2200+ hash_ctl .hcxt = pgStatLocalContext ;
22112201dbentry -> tables = hash_create ("Per-database table" ,
22122202PGSTAT_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 :
22762266FreeFile (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 */
22942285if (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 );
23022287else
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 *