Commit aec4cf1c authored by Tom Lane's avatar Tom Lane

Add a function pg_stat_clear_snapshot() that discards any statistics snapshot

already collected in the current transaction; this allows plpgsql functions to
watch for stats updates even though they are confined to a single transaction.
Use this instead of the previous kluge involving pg_stat_file() to wait for
the stats collector to update in the stats regression test.  Internally,
decouple storage of stats snapshots from transaction boundaries; they'll
now stick around until someone calls pgstat_clear_snapshot --- which xact.c
still does at transaction end, to maintain the previous behavior.  This makes
the logic a lot cleaner, at the price of a couple dozen cycles per transaction
exit.
parent d9ce6887
<!-- $PostgreSQL: pgsql/doc/src/sgml/monitoring.sgml,v 1.45 2007/02/01 00:28:17 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/monitoring.sgml,v 1.46 2007/02/07 23:11:29 tgl Exp $ -->
<chapter id="monitoring"> <chapter id="monitoring">
<title>Monitoring Database Activity</title> <title>Monitoring Database Activity</title>
...@@ -227,7 +227,10 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re ...@@ -227,7 +227,10 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
queries on the statistics and correlate the results without worrying that queries on the statistics and correlate the results without worrying that
the numbers are changing underneath you. But if you want to see new the numbers are changing underneath you. But if you want to see new
results with each query, be sure to do the queries outside any transaction results with each query, be sure to do the queries outside any transaction
block. block. Alternatively, you can invoke
<function>pg_stat_clear_snapshot</function>(), which will discard the
current transaction's statistics snapshot (if any). The next use of
statistical information will cause a new snapshot to be fetched.
</para> </para>
<table id="monitoring-stats-views-table"> <table id="monitoring-stats-views-table">
...@@ -707,11 +710,20 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re ...@@ -707,11 +710,20 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
</entry> </entry>
</row> </row>
<row>
<entry><literal><function>pg_stat_clear_snapshot</function>()</literal></entry>
<entry><type>void</type></entry>
<entry>
Discard the current statistics snapshot
</entry>
</row>
<row> <row>
<entry><literal><function>pg_stat_reset</function>()</literal></entry> <entry><literal><function>pg_stat_reset</function>()</literal></entry>
<entry><type>boolean</type></entry> <entry><type>void</type></entry>
<entry> <entry>
Reset all block-level and row-level statistics to zero Reset all statistics counters for the current database to zero
(requires superuser privileges)
</entry> </entry>
</row> </row>
</tbody> </tbody>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.232 2007/02/01 19:10:25 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.233 2007/02/07 23:11:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1628,6 +1628,7 @@ CommitTransaction(void) ...@@ -1628,6 +1628,7 @@ CommitTransaction(void)
AtEOXact_Namespace(true); AtEOXact_Namespace(true);
/* smgrcommit already done */ /* smgrcommit already done */
AtEOXact_Files(); AtEOXact_Files();
pgstat_clear_snapshot();
pgstat_count_xact_commit(); pgstat_count_xact_commit();
pgstat_report_txn_timestamp(0); pgstat_report_txn_timestamp(0);
...@@ -1844,6 +1845,7 @@ PrepareTransaction(void) ...@@ -1844,6 +1845,7 @@ PrepareTransaction(void)
AtEOXact_Namespace(true); AtEOXact_Namespace(true);
/* smgrcommit already done */ /* smgrcommit already done */
AtEOXact_Files(); AtEOXact_Files();
pgstat_clear_snapshot();
CurrentResourceOwner = NULL; CurrentResourceOwner = NULL;
ResourceOwnerDelete(TopTransactionResourceOwner); ResourceOwnerDelete(TopTransactionResourceOwner);
...@@ -1995,6 +1997,7 @@ AbortTransaction(void) ...@@ -1995,6 +1997,7 @@ AbortTransaction(void)
AtEOXact_Namespace(false); AtEOXact_Namespace(false);
smgrabort(); smgrabort();
AtEOXact_Files(); AtEOXact_Files();
pgstat_clear_snapshot();
pgstat_count_xact_rollback(); pgstat_count_xact_rollback();
pgstat_report_txn_timestamp(0); pgstat_report_txn_timestamp(0);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* Copyright (c) 2001-2007, PostgreSQL Global Development Group * Copyright (c) 2001-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.144 2007/01/26 20:06:52 tgl Exp $ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.145 2007/02/07 23:11:29 tgl Exp $
* ---------- * ----------
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -130,9 +130,8 @@ static TabStatArray SharedTabStat = {0, 0, NULL}; ...@@ -130,9 +130,8 @@ static TabStatArray SharedTabStat = {0, 0, NULL};
static int pgStatXactCommit = 0; static int pgStatXactCommit = 0;
static int pgStatXactRollback = 0; static int pgStatXactRollback = 0;
static TransactionId pgStatDBHashXact = InvalidTransactionId; static MemoryContext pgStatLocalContext = NULL;
static HTAB *pgStatDBHash = NULL; static HTAB *pgStatDBHash = NULL;
static TransactionId pgStatLocalStatusXact = InvalidTransactionId;
static PgBackendStatus *localBackendStatusTable = NULL; static PgBackendStatus *localBackendStatusTable = NULL;
static int localNumBackends = 0; static int localNumBackends = 0;
...@@ -156,11 +155,13 @@ static void pgstat_beshutdown_hook(int code, Datum arg); ...@@ -156,11 +155,13 @@ static void pgstat_beshutdown_hook(int code, Datum arg);
static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create); static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create);
static void pgstat_drop_database(Oid databaseid); static void pgstat_drop_database(Oid databaseid);
static void pgstat_write_statsfile(void); static void pgstat_write_statsfile(void);
static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb); static HTAB *pgstat_read_statsfile(Oid onlydb);
static void backend_read_statsfile(void); static void backend_read_statsfile(void);
static void pgstat_read_current_status(void); static void pgstat_read_current_status(void);
static HTAB *pgstat_collect_oids(Oid catalogid); static HTAB *pgstat_collect_oids(Oid catalogid);
static void pgstat_setup_memcxt(void);
static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype); static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
static void pgstat_send(void *msg, int len); static void pgstat_send(void *msg, int len);
...@@ -1535,22 +1536,24 @@ pgstat_report_waiting(bool waiting) ...@@ -1535,22 +1536,24 @@ pgstat_report_waiting(bool waiting)
static void static void
pgstat_read_current_status(void) pgstat_read_current_status(void)
{ {
TransactionId topXid = GetTopTransactionId();
volatile PgBackendStatus *beentry; volatile PgBackendStatus *beentry;
PgBackendStatus *localtable;
PgBackendStatus *localentry; PgBackendStatus *localentry;
int i; int i;
Assert(!pgStatRunningInCollector); Assert(!pgStatRunningInCollector);
if (TransactionIdEquals(pgStatLocalStatusXact, topXid)) if (localBackendStatusTable)
return; /* already done */ return; /* already done */
localBackendStatusTable = (PgBackendStatus *) pgstat_setup_memcxt();
MemoryContextAlloc(TopTransactionContext,
localtable = (PgBackendStatus *)
MemoryContextAlloc(pgStatLocalContext,
sizeof(PgBackendStatus) * MaxBackends); sizeof(PgBackendStatus) * MaxBackends);
localNumBackends = 0; localNumBackends = 0;
beentry = BackendStatusArray; beentry = BackendStatusArray;
localentry = localBackendStatusTable; localentry = localtable;
for (i = 1; i <= MaxBackends; i++) for (i = 1; i <= MaxBackends; i++)
{ {
/* /*
...@@ -1587,7 +1590,8 @@ pgstat_read_current_status(void) ...@@ -1587,7 +1590,8 @@ pgstat_read_current_status(void)
} }
} }
pgStatLocalStatusXact = topXid; /* Set the pointer only after completion of a valid table */
localBackendStatusTable = localtable;
} }
...@@ -1720,7 +1724,7 @@ PgstatCollectorMain(int argc, char *argv[]) ...@@ -1720,7 +1724,7 @@ PgstatCollectorMain(int argc, char *argv[])
* zero. * zero.
*/ */
pgStatRunningInCollector = true; pgStatRunningInCollector = true;
pgstat_read_statsfile(&pgStatDBHash, InvalidOid); pgStatDBHash = pgstat_read_statsfile(InvalidOid);
/* /*
* Setup the descriptor set for select(2). Since only one bit in the set * Setup the descriptor set for select(2). Since only one bit in the set
...@@ -2090,38 +2094,24 @@ pgstat_write_statsfile(void) ...@@ -2090,38 +2094,24 @@ pgstat_write_statsfile(void)
* databases' hash table (whose entries point to the tables' hash tables). * databases' hash table (whose entries point to the tables' hash tables).
* ---------- * ----------
*/ */
static void static HTAB *
pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) pgstat_read_statsfile(Oid onlydb)
{ {
PgStat_StatDBEntry *dbentry; PgStat_StatDBEntry *dbentry;
PgStat_StatDBEntry dbbuf; PgStat_StatDBEntry dbbuf;
PgStat_StatTabEntry *tabentry; PgStat_StatTabEntry *tabentry;
PgStat_StatTabEntry tabbuf; PgStat_StatTabEntry tabbuf;
HASHCTL hash_ctl; HASHCTL hash_ctl;
HTAB *dbhash;
HTAB *tabhash = NULL; HTAB *tabhash = NULL;
FILE *fpin; FILE *fpin;
int32 format_id; int32 format_id;
bool found; bool found;
MemoryContext use_mcxt;
int mcxt_flags;
/* /*
* If running in the collector or the autovacuum process, we use the * The tables will live in pgStatLocalContext.
* DynaHashCxt memory context. If running in a backend, we use the
* 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!
*/ */
if (pgStatRunningInCollector || IsAutoVacuumProcess()) pgstat_setup_memcxt();
{
use_mcxt = NULL;
mcxt_flags = 0;
}
else
{
use_mcxt = TopTransactionContext;
mcxt_flags = HASH_CONTEXT;
}
/* /*
* Create the DB hashtable * Create the DB hashtable
...@@ -2130,9 +2120,9 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) ...@@ -2130,9 +2120,9 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
hash_ctl.keysize = sizeof(Oid); hash_ctl.keysize = sizeof(Oid);
hash_ctl.entrysize = sizeof(PgStat_StatDBEntry); hash_ctl.entrysize = sizeof(PgStat_StatDBEntry);
hash_ctl.hash = oid_hash; hash_ctl.hash = oid_hash;
hash_ctl.hcxt = use_mcxt; hash_ctl.hcxt = pgStatLocalContext;
*dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl, dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl,
HASH_ELEM | HASH_FUNCTION | mcxt_flags); HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
/* /*
* Try to open the status file. If it doesn't exist, the backends simply * Try to open the status file. If it doesn't exist, the backends simply
...@@ -2140,7 +2130,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) ...@@ -2140,7 +2130,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
* with empty counters. * with empty counters.
*/ */
if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL) if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL)
return; return dbhash;
/* /*
* Verify it's of the expected format. * Verify it's of the expected format.
...@@ -2178,7 +2168,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) ...@@ -2178,7 +2168,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
/* /*
* Add to the DB hash * Add to the DB hash
*/ */
dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash, dbentry = (PgStat_StatDBEntry *) hash_search(dbhash,
(void *) &dbbuf.databaseid, (void *) &dbbuf.databaseid,
HASH_ENTER, HASH_ENTER,
&found); &found);
...@@ -2207,11 +2197,11 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) ...@@ -2207,11 +2197,11 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
hash_ctl.keysize = sizeof(Oid); hash_ctl.keysize = sizeof(Oid);
hash_ctl.entrysize = sizeof(PgStat_StatTabEntry); hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
hash_ctl.hash = oid_hash; hash_ctl.hash = oid_hash;
hash_ctl.hcxt = use_mcxt; hash_ctl.hcxt = pgStatLocalContext;
dbentry->tables = hash_create("Per-database table", dbentry->tables = hash_create("Per-database table",
PGSTAT_TAB_HASH_SIZE, PGSTAT_TAB_HASH_SIZE,
&hash_ctl, &hash_ctl,
HASH_ELEM | HASH_FUNCTION | mcxt_flags); HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
/* /*
* Arrange that following 'T's add entries to this database's * Arrange that following 'T's add entries to this database's
...@@ -2274,44 +2264,78 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb) ...@@ -2274,44 +2264,78 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
done: done:
FreeFile(fpin); FreeFile(fpin);
return dbhash;
} }
/* /*
* If not done for this transaction, read the statistics collector * If not already done, read the statistics collector stats file into
* stats file into some hash tables. * some hash tables. The results will be kept until pgstat_clear_snapshot()
* * is called (typically, at end of transaction).
* 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
* "forever", that is one iteration, within one database. This means
* we only consider the statistics as they were when the autovacuum
* iteration started.
*/ */
static void static void
backend_read_statsfile(void) backend_read_statsfile(void)
{ {
/* already read it? */
if (pgStatDBHash)
return;
Assert(!pgStatRunningInCollector);
/* Autovacuum wants stats about all databases */
if (IsAutoVacuumProcess()) if (IsAutoVacuumProcess())
{ pgStatDBHash = pgstat_read_statsfile(InvalidOid);
/* already read it? */
if (pgStatDBHash)
return;
Assert(!pgStatRunningInCollector);
pgstat_read_statsfile(&pgStatDBHash, InvalidOid);
}
else else
{ pgStatDBHash = pgstat_read_statsfile(MyDatabaseId);
TransactionId topXid = GetTopTransactionId(); }
if (!TransactionIdEquals(pgStatDBHashXact, topXid))
{ /* ----------
Assert(!pgStatRunningInCollector); * pgstat_setup_memcxt() -
pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId); *
pgStatDBHashXact = topXid; * Create pgStatLocalContext, if not already done.
} * ----------
} */
static void
pgstat_setup_memcxt(void)
{
if (!pgStatLocalContext)
pgStatLocalContext = AllocSetContextCreate(TopMemoryContext,
"Statistics snapshot",
ALLOCSET_SMALL_MINSIZE,
ALLOCSET_SMALL_INITSIZE,
ALLOCSET_SMALL_MAXSIZE);
} }
/* ----------
* pgstat_clear_snapshot() -
*
* Discard any data collected in the current transaction. Any subsequent
* request will cause new snapshots to be read.
*
* This is also invoked during transaction commit or abort to discard
* the no-longer-wanted snapshot.
* ----------
*/
void
pgstat_clear_snapshot(void)
{
/* In an autovacuum process we keep the stats forever */
if (IsAutoVacuumProcess())
return;
/* Release memory, if any was allocated */
if (pgStatLocalContext)
MemoryContextDelete(pgStatLocalContext);
/* Reset variables */
pgStatLocalContext = NULL;
pgStatDBHash = NULL;
localBackendStatusTable = NULL;
localNumBackends = 0;
}
/* ---------- /* ----------
* pgstat_recv_tabstat() - * pgstat_recv_tabstat() -
* *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.37 2007/01/05 22:19:41 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.38 2007/02/07 23:11:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,7 +39,6 @@ extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS); ...@@ -39,7 +39,6 @@ extern Datum pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_idset(PG_FUNCTION_ARGS);
extern Datum pg_backend_pid(PG_FUNCTION_ARGS); extern Datum pg_backend_pid(PG_FUNCTION_ARGS);
extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS);
...@@ -57,6 +56,9 @@ extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS); ...@@ -57,6 +56,9 @@ extern Datum pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS); extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS); extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);
extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS);
extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
Datum Datum
pg_stat_get_numscans(PG_FUNCTION_ARGS) pg_stat_get_numscans(PG_FUNCTION_ARGS)
...@@ -336,16 +338,6 @@ pg_backend_pid(PG_FUNCTION_ARGS) ...@@ -336,16 +338,6 @@ pg_backend_pid(PG_FUNCTION_ARGS)
PG_RETURN_INT32(MyProcPid); PG_RETURN_INT32(MyProcPid);
} }
/*
* Built-in function for resetting the counters
*/
Datum
pg_stat_reset(PG_FUNCTION_ARGS)
{
pgstat_reset_counters();
PG_RETURN_BOOL(true);
}
Datum Datum
pg_stat_get_backend_pid(PG_FUNCTION_ARGS) pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
...@@ -678,3 +670,23 @@ pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS) ...@@ -678,3 +670,23 @@ pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
PG_RETURN_INT64(result); PG_RETURN_INT64(result);
} }
/* Discard the active statistics snapshot */
Datum
pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
{
pgstat_clear_snapshot();
PG_RETURN_VOID();
}
/* Reset all counters for the current database */
Datum
pg_stat_reset(PG_FUNCTION_ARGS)
{
pgstat_reset_counters();
PG_RETURN_VOID();
}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.381 2007/02/06 02:59:12 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.382 2007/02/07 23:11:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200702051 #define CATALOG_VERSION_NO 200702071
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.442 2007/02/03 14:06:55 petere Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.443 2007/02/07 23:11:30 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -2938,8 +2938,6 @@ DATA(insert OID = 1936 ( pg_stat_get_backend_idset PGNSP PGUID 12 1 100 f f t ...@@ -2938,8 +2938,6 @@ DATA(insert OID = 1936 ( pg_stat_get_backend_idset PGNSP PGUID 12 1 100 f f t
DESCR("Statistics: Currently active backend IDs"); DESCR("Statistics: Currently active backend IDs");
DATA(insert OID = 2026 ( pg_backend_pid PGNSP PGUID 12 1 0 f f t f s 0 23 "" _null_ _null_ _null_ pg_backend_pid - _null_ )); DATA(insert OID = 2026 ( pg_backend_pid PGNSP PGUID 12 1 0 f f t f s 0 23 "" _null_ _null_ _null_ pg_backend_pid - _null_ ));
DESCR("Statistics: Current backend PID"); DESCR("Statistics: Current backend PID");
DATA(insert OID = 2274 ( pg_stat_reset PGNSP PGUID 12 1 0 f f f f v 0 16 "" _null_ _null_ _null_ pg_stat_reset - _null_ ));
DESCR("Statistics: Reset collected statistics");
DATA(insert OID = 1937 ( pg_stat_get_backend_pid PGNSP PGUID 12 1 0 f f t f s 1 23 "23" _null_ _null_ _null_ pg_stat_get_backend_pid - _null_ )); DATA(insert OID = 1937 ( pg_stat_get_backend_pid PGNSP PGUID 12 1 0 f f t f s 1 23 "23" _null_ _null_ _null_ pg_stat_get_backend_pid - _null_ ));
DESCR("Statistics: PID of backend"); DESCR("Statistics: PID of backend");
DATA(insert OID = 1938 ( pg_stat_get_backend_dbid PGNSP PGUID 12 1 0 f f t f s 1 26 "23" _null_ _null_ _null_ pg_stat_get_backend_dbid - _null_ )); DATA(insert OID = 1938 ( pg_stat_get_backend_dbid PGNSP PGUID 12 1 0 f f t f s 1 26 "23" _null_ _null_ _null_ pg_stat_get_backend_dbid - _null_ ));
...@@ -2970,6 +2968,10 @@ DATA(insert OID = 1944 ( pg_stat_get_db_blocks_fetched PGNSP PGUID 12 1 0 f f t ...@@ -2970,6 +2968,10 @@ DATA(insert OID = 1944 ( pg_stat_get_db_blocks_fetched PGNSP PGUID 12 1 0 f f t
DESCR("Statistics: Blocks fetched for database"); DESCR("Statistics: Blocks fetched for database");
DATA(insert OID = 1945 ( pg_stat_get_db_blocks_hit PGNSP PGUID 12 1 0 f f t f s 1 20 "26" _null_ _null_ _null_ pg_stat_get_db_blocks_hit - _null_ )); DATA(insert OID = 1945 ( pg_stat_get_db_blocks_hit PGNSP PGUID 12 1 0 f f t f s 1 20 "26" _null_ _null_ _null_ pg_stat_get_db_blocks_hit - _null_ ));
DESCR("Statistics: Blocks found in cache for database"); DESCR("Statistics: Blocks found in cache for database");
DATA(insert OID = 2230 ( pg_stat_clear_snapshot PGNSP PGUID 12 1 0 f f f f v 0 2278 "" _null_ _null_ _null_ pg_stat_clear_snapshot - _null_ ));
DESCR("Statistics: Discard current transaction's statistics snapshot");
DATA(insert OID = 2274 ( pg_stat_reset PGNSP PGUID 12 1 0 f f f f v 0 2278 "" _null_ _null_ _null_ pg_stat_reset - _null_ ));
DESCR("Statistics: Reset collected statistics for current database");
DATA(insert OID = 1946 ( encode PGNSP PGUID 12 1 0 f f t f i 2 25 "17 25" _null_ _null_ _null_ binary_encode - _null_ )); DATA(insert OID = 1946 ( encode PGNSP PGUID 12 1 0 f f t f i 2 25 "17 25" _null_ _null_ _null_ binary_encode - _null_ ));
DESCR("Convert bytea value into some ascii-only text string"); DESCR("Convert bytea value into some ascii-only text string");
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 2001-2007, PostgreSQL Global Development Group * Copyright (c) 2001-2007, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/include/pgstat.h,v 1.52 2007/01/05 22:19:50 momjian Exp $ * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.53 2007/02/07 23:11:30 tgl Exp $
* ---------- * ----------
*/ */
#ifndef PGSTAT_H #ifndef PGSTAT_H
...@@ -380,6 +380,7 @@ extern void pgstat_report_tabstat(void); ...@@ -380,6 +380,7 @@ extern void pgstat_report_tabstat(void);
extern void pgstat_vacuum_tabstat(void); extern void pgstat_vacuum_tabstat(void);
extern void pgstat_drop_relation(Oid relid); extern void pgstat_drop_relation(Oid relid);
extern void pgstat_clear_snapshot(void);
extern void pgstat_reset_counters(void); extern void pgstat_reset_counters(void);
extern void pgstat_report_autovac(Oid dboid); extern void pgstat_report_autovac(Oid dboid);
......
...@@ -27,61 +27,28 @@ SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, ...@@ -27,61 +27,28 @@ SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch,
FROM pg_catalog.pg_stat_user_tables AS t, FROM pg_catalog.pg_stat_user_tables AS t,
pg_catalog.pg_statio_user_tables AS b pg_catalog.pg_statio_user_tables AS b
WHERE t.relname='tenk2' AND b.relname='tenk2'; WHERE t.relname='tenk2' AND b.relname='tenk2';
-- enable statistics -- function to wait for counters to advance
SET stats_block_level = on;
SET stats_row_level = on;
-- do a seqscan
SELECT count(*) FROM tenk2;
count
-------
10000
(1 row)
-- do an indexscan
SELECT count(*) FROM tenk2 WHERE unique1 = 1;
count
-------
1
(1 row)
-- All of the thrashing here is to wait for the stats collector to update,
-- without waiting too long (in fact, we'd like to try to measure how long
-- we wait). Watching for change in the stats themselves wouldn't work
-- because the backend only reads them once per transaction. The stats file
-- mod timestamp isn't too helpful because it may have resolution of only one
-- second, or even worse. So, we touch a new table and then watch for change
-- in the size of the stats file. Ugh.
-- save current stats-file size
CREATE TEMP TABLE prevfilesize AS
SELECT size FROM pg_stat_file('global/pgstat.stat');
-- make and touch a previously nonexistent table
CREATE TABLE stats_hack (f1 int);
SELECT * FROM stats_hack;
f1
----
(0 rows)
-- wait for stats collector to update
create function wait_for_stats() returns void as $$ create function wait_for_stats() returns void as $$
declare declare
start_time timestamptz := clock_timestamp(); start_time timestamptz := clock_timestamp();
oldsize bigint; updated bool;
newsize bigint;
begin begin
-- fetch previous stats-file size
select size into oldsize from prevfilesize;
-- we don't want to wait forever; loop will exit after 30 seconds -- we don't want to wait forever; loop will exit after 30 seconds
for i in 1 .. 300 loop for i in 1 .. 300 loop
-- look for update of stats file -- check to see if indexscan has been sensed
select size into newsize from pg_stat_file('global/pgstat.stat'); SELECT (st.idx_scan >= pr.idx_scan + 1) INTO updated
FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr
WHERE st.relname='tenk2' AND cl.relname='tenk2';
exit when newsize != oldsize; exit when updated;
-- wait a little -- wait a little
perform pg_sleep(0.1); perform pg_sleep(0.1);
-- reset stats snapshot so we can test again
perform pg_stat_clear_snapshot();
end loop; end loop;
-- report time waited in postmaster log (where it won't change test output) -- report time waited in postmaster log (where it won't change test output)
...@@ -89,13 +56,30 @@ begin ...@@ -89,13 +56,30 @@ begin
extract(epoch from clock_timestamp() - start_time); extract(epoch from clock_timestamp() - start_time);
end end
$$ language plpgsql; $$ language plpgsql;
-- enable statistics
SET stats_block_level = on;
SET stats_row_level = on;
-- do a seqscan
SELECT count(*) FROM tenk2;
count
-------
10000
(1 row)
-- do an indexscan
SELECT count(*) FROM tenk2 WHERE unique1 = 1;
count
-------
1
(1 row)
-- wait for stats collector to update
SELECT wait_for_stats(); SELECT wait_for_stats();
wait_for_stats wait_for_stats
---------------- ----------------
(1 row) (1 row)
DROP TABLE stats_hack;
-- check effects -- check effects
SELECT st.seq_scan >= pr.seq_scan + 1, SELECT st.seq_scan >= pr.seq_scan + 1,
st.seq_tup_read >= pr.seq_tup_read + cl.reltuples, st.seq_tup_read >= pr.seq_tup_read + cl.reltuples,
......
...@@ -21,52 +21,28 @@ SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, ...@@ -21,52 +21,28 @@ SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch,
pg_catalog.pg_statio_user_tables AS b pg_catalog.pg_statio_user_tables AS b
WHERE t.relname='tenk2' AND b.relname='tenk2'; WHERE t.relname='tenk2' AND b.relname='tenk2';
-- enable statistics -- function to wait for counters to advance
SET stats_block_level = on;
SET stats_row_level = on;
-- do a seqscan
SELECT count(*) FROM tenk2;
-- do an indexscan
SELECT count(*) FROM tenk2 WHERE unique1 = 1;
-- All of the thrashing here is to wait for the stats collector to update,
-- without waiting too long (in fact, we'd like to try to measure how long
-- we wait). Watching for change in the stats themselves wouldn't work
-- because the backend only reads them once per transaction. The stats file
-- mod timestamp isn't too helpful because it may have resolution of only one
-- second, or even worse. So, we touch a new table and then watch for change
-- in the size of the stats file. Ugh.
-- save current stats-file size
CREATE TEMP TABLE prevfilesize AS
SELECT size FROM pg_stat_file('global/pgstat.stat');
-- make and touch a previously nonexistent table
CREATE TABLE stats_hack (f1 int);
SELECT * FROM stats_hack;
-- wait for stats collector to update
create function wait_for_stats() returns void as $$ create function wait_for_stats() returns void as $$
declare declare
start_time timestamptz := clock_timestamp(); start_time timestamptz := clock_timestamp();
oldsize bigint; updated bool;
newsize bigint;
begin begin
-- fetch previous stats-file size
select size into oldsize from prevfilesize;
-- we don't want to wait forever; loop will exit after 30 seconds -- we don't want to wait forever; loop will exit after 30 seconds
for i in 1 .. 300 loop for i in 1 .. 300 loop
-- look for update of stats file -- check to see if indexscan has been sensed
select size into newsize from pg_stat_file('global/pgstat.stat'); SELECT (st.idx_scan >= pr.idx_scan + 1) INTO updated
FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr
WHERE st.relname='tenk2' AND cl.relname='tenk2';
exit when newsize != oldsize; exit when updated;
-- wait a little -- wait a little
perform pg_sleep(0.1); perform pg_sleep(0.1);
-- reset stats snapshot so we can test again
perform pg_stat_clear_snapshot();
end loop; end loop;
-- report time waited in postmaster log (where it won't change test output) -- report time waited in postmaster log (where it won't change test output)
...@@ -75,9 +51,17 @@ begin ...@@ -75,9 +51,17 @@ begin
end end
$$ language plpgsql; $$ language plpgsql;
SELECT wait_for_stats(); -- enable statistics
SET stats_block_level = on;
SET stats_row_level = on;
DROP TABLE stats_hack; -- do a seqscan
SELECT count(*) FROM tenk2;
-- do an indexscan
SELECT count(*) FROM tenk2 WHERE unique1 = 1;
-- wait for stats collector to update
SELECT wait_for_stats();
-- check effects -- check effects
SELECT st.seq_scan >= pr.seq_scan + 1, SELECT st.seq_scan >= pr.seq_scan + 1,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment