mirror of
https://github.com/postgres/postgres.git
synced 2025-06-07 11:02:12 +03:00
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.
This commit is contained in:
parent
d9ce68872f
commit
aec4cf1c8c
@ -1,4 +1,4 @@
|
|||||||
<!-- $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
|
|||||||
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">
|
||||||
@ -708,10 +711,19 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
|
|||||||
</row>
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><literal><function>pg_stat_reset</function>()</literal></entry>
|
<entry><literal><function>pg_stat_clear_snapshot</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
|
Discard the current statistics snapshot
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><literal><function>pg_stat_reset</function>()</literal></entry>
|
||||||
|
<entry><type>void</type></entry>
|
||||||
|
<entry>
|
||||||
|
Reset all statistics counters for the current database to zero
|
||||||
|
(requires superuser privileges)
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
* 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};
|
|||||||
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);
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pgStatLocalStatusXact = topXid;
|
/* Set the pointer only after completion of a valid table */
|
||||||
|
localBackendStatusTable = localtable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
||||||
{
|
|
||||||
if (IsAutoVacuumProcess())
|
|
||||||
{
|
{
|
||||||
/* already read it? */
|
/* already read it? */
|
||||||
if (pgStatDBHash)
|
if (pgStatDBHash)
|
||||||
return;
|
return;
|
||||||
Assert(!pgStatRunningInCollector);
|
Assert(!pgStatRunningInCollector);
|
||||||
pgstat_read_statsfile(&pgStatDBHash, InvalidOid);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TransactionId topXid = GetTopTransactionId();
|
|
||||||
|
|
||||||
if (!TransactionIdEquals(pgStatDBHashXact, topXid))
|
/* Autovacuum wants stats about all databases */
|
||||||
|
if (IsAutoVacuumProcess())
|
||||||
|
pgStatDBHash = pgstat_read_statsfile(InvalidOid);
|
||||||
|
else
|
||||||
|
pgStatDBHash = pgstat_read_statsfile(MyDatabaseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------
|
||||||
|
* pgstat_setup_memcxt() -
|
||||||
|
*
|
||||||
|
* Create pgStatLocalContext, if not already done.
|
||||||
|
* ----------
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
pgstat_setup_memcxt(void)
|
||||||
{
|
{
|
||||||
Assert(!pgStatRunningInCollector);
|
if (!pgStatLocalContext)
|
||||||
pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId);
|
pgStatLocalContext = AllocSetContextCreate(TopMemoryContext,
|
||||||
pgStatDBHashXact = topXid;
|
"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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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);
|
|||||||
|
|
||||||
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);
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
* 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 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200702051
|
#define CATALOG_VERSION_NO 200702071
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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
|
|||||||
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
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
* 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);
|
|||||||
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,6 +27,35 @@ 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';
|
||||||
|
-- function to wait for counters to advance
|
||||||
|
create function wait_for_stats() returns void as $$
|
||||||
|
declare
|
||||||
|
start_time timestamptz := clock_timestamp();
|
||||||
|
updated bool;
|
||||||
|
begin
|
||||||
|
-- we don't want to wait forever; loop will exit after 30 seconds
|
||||||
|
for i in 1 .. 300 loop
|
||||||
|
|
||||||
|
-- check to see if indexscan has been sensed
|
||||||
|
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 updated;
|
||||||
|
|
||||||
|
-- wait a little
|
||||||
|
perform pg_sleep(0.1);
|
||||||
|
|
||||||
|
-- reset stats snapshot so we can test again
|
||||||
|
perform pg_stat_clear_snapshot();
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
-- report time waited in postmaster log (where it won't change test output)
|
||||||
|
raise log 'wait_for_stats delayed % seconds',
|
||||||
|
extract(epoch from clock_timestamp() - start_time);
|
||||||
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
-- enable statistics
|
-- enable statistics
|
||||||
SET stats_block_level = on;
|
SET stats_block_level = on;
|
||||||
SET stats_row_level = on;
|
SET stats_row_level = on;
|
||||||
@ -44,58 +73,13 @@ SELECT count(*) FROM tenk2 WHERE unique1 = 1;
|
|||||||
1
|
1
|
||||||
(1 row)
|
(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
|
-- wait for stats collector to update
|
||||||
create function wait_for_stats() returns void as $$
|
|
||||||
declare
|
|
||||||
start_time timestamptz := clock_timestamp();
|
|
||||||
oldsize bigint;
|
|
||||||
newsize bigint;
|
|
||||||
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
|
|
||||||
for i in 1 .. 300 loop
|
|
||||||
|
|
||||||
-- look for update of stats file
|
|
||||||
select size into newsize from pg_stat_file('global/pgstat.stat');
|
|
||||||
|
|
||||||
exit when newsize != oldsize;
|
|
||||||
|
|
||||||
-- wait a little
|
|
||||||
perform pg_sleep(0.1);
|
|
||||||
|
|
||||||
end loop;
|
|
||||||
|
|
||||||
-- report time waited in postmaster log (where it won't change test output)
|
|
||||||
raise log 'wait_for_stats delayed % seconds',
|
|
||||||
extract(epoch from clock_timestamp() - start_time);
|
|
||||||
end
|
|
||||||
$$ language plpgsql;
|
|
||||||
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,
|
|||||||
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
|
|||||||
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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user