aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-02-07 23:11:30 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-02-07 23:11:30 +0000
commitaec4cf1c8c410f9c9db3deabcb94502dcd355b3f (patch)
tree18ff3f246c08608d5b09f3da0d267a51f3318378 /src
parentd9ce68872f7f6aab6cea2481b991b3c1a83d1956 (diff)
downloadpostgresql-aec4cf1c8c410f9c9db3deabcb94502dcd355b3f.tar.gz
postgresql-aec4cf1c8c410f9c9db3deabcb94502dcd355b3f.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xact.c5
-rw-r--r--src/backend/postmaster/pgstat.c150
-rw-r--r--src/backend/utils/adt/pgstatfuncs.c36
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_proc.h8
-rw-r--r--src/include/pgstat.h3
-rw-r--r--src/test/regress/expected/stats.out72
-rw-r--r--src/test/regress/sql/stats.sql56
8 files changed, 172 insertions, 162 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 4ee1cc711cd..26a3c5ddc2c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -10,7 +10,7 @@
*
*
* 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);
/* smgrcommit already done */
AtEOXact_Files();
+ pgstat_clear_snapshot();
pgstat_count_xact_commit();
pgstat_report_txn_timestamp(0);
@@ -1844,6 +1845,7 @@ PrepareTransaction(void)
AtEOXact_Namespace(true);
/* smgrcommit already done */
AtEOXact_Files();
+ pgstat_clear_snapshot();
CurrentResourceOwner = NULL;
ResourceOwnerDelete(TopTransactionResourceOwner);
@@ -1995,6 +1997,7 @@ AbortTransaction(void)
AtEOXact_Namespace(false);
smgrabort();
AtEOXact_Files();
+ pgstat_clear_snapshot();
pgstat_count_xact_rollback();
pgstat_report_txn_timestamp(0);
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 6a5907c466e..f64e02020a8 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -13,7 +13,7 @@
*
* 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"
@@ -130,9 +130,8 @@ static TabStatArray SharedTabStat = {0, 0, NULL};
static int pgStatXactCommit = 0;
static int pgStatXactRollback = 0;
-static TransactionId pgStatDBHashXact = InvalidTransactionId;
+static MemoryContext pgStatLocalContext = NULL;
static HTAB *pgStatDBHash = NULL;
-static TransactionId pgStatLocalStatusXact = InvalidTransactionId;
static PgBackendStatus *localBackendStatusTable = NULL;
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 void pgstat_drop_database(Oid databaseid);
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 pgstat_read_current_status(void);
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_send(void *msg, int len);
@@ -1535,22 +1536,24 @@ pgstat_report_waiting(bool waiting)
static void
pgstat_read_current_status(void)
{
- TransactionId topXid = GetTopTransactionId();
volatile PgBackendStatus *beentry;
+ PgBackendStatus *localtable;
PgBackendStatus *localentry;
int i;
Assert(!pgStatRunningInCollector);
- if (TransactionIdEquals(pgStatLocalStatusXact, topXid))
+ if (localBackendStatusTable)
return; /* already done */
- localBackendStatusTable = (PgBackendStatus *)
- MemoryContextAlloc(TopTransactionContext,
+ pgstat_setup_memcxt();
+
+ localtable = (PgBackendStatus *)
+ MemoryContextAlloc(pgStatLocalContext,
sizeof(PgBackendStatus) * MaxBackends);
localNumBackends = 0;
beentry = BackendStatusArray;
- localentry = localBackendStatusTable;
+ localentry = localtable;
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.
*/
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
@@ -2090,38 +2094,24 @@ pgstat_write_statsfile(void)
* databases' hash table (whose entries point to the tables' hash tables).
* ----------
*/
-static void
-pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
+static HTAB *
+pgstat_read_statsfile(Oid onlydb)
{
PgStat_StatDBEntry *dbentry;
PgStat_StatDBEntry dbbuf;
PgStat_StatTabEntry *tabentry;
PgStat_StatTabEntry tabbuf;
HASHCTL hash_ctl;
+ HTAB *dbhash;
HTAB *tabhash = NULL;
FILE *fpin;
int32 format_id;
bool found;
- MemoryContext use_mcxt;
- int mcxt_flags;
/*
- * If running in the collector or the autovacuum process, we use the
- * 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!
+ * The tables will live in pgStatLocalContext.
*/
- if (pgStatRunningInCollector || IsAutoVacuumProcess())
- {
- use_mcxt = NULL;
- mcxt_flags = 0;
- }
- else
- {
- use_mcxt = TopTransactionContext;
- mcxt_flags = HASH_CONTEXT;
- }
+ pgstat_setup_memcxt();
/*
* Create the DB hashtable
@@ -2130,9 +2120,9 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
hash_ctl.keysize = sizeof(Oid);
hash_ctl.entrysize = sizeof(PgStat_StatDBEntry);
hash_ctl.hash = oid_hash;
- hash_ctl.hcxt = use_mcxt;
- *dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl,
- HASH_ELEM | HASH_FUNCTION | mcxt_flags);
+ hash_ctl.hcxt = pgStatLocalContext;
+ dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl,
+ HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
/*
* 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.
*/
if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL)
- return;
+ return dbhash;
/*
* Verify it's of the expected format.
@@ -2178,7 +2168,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
/*
* Add to the DB hash
*/
- dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash,
+ dbentry = (PgStat_StatDBEntry *) hash_search(dbhash,
(void *) &dbbuf.databaseid,
HASH_ENTER,
&found);
@@ -2207,11 +2197,11 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
hash_ctl.keysize = sizeof(Oid);
hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
hash_ctl.hash = oid_hash;
- hash_ctl.hcxt = use_mcxt;
+ hash_ctl.hcxt = pgStatLocalContext;
dbentry->tables = hash_create("Per-database table",
PGSTAT_TAB_HASH_SIZE,
&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
@@ -2274,44 +2264,78 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
done:
FreeFile(fpin);
+
+ return dbhash;
}
/*
- * If not done for this transaction, read the statistics collector
- * stats file into some hash tables.
- *
- * 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.
+ * If not already done, read the statistics collector stats file into
+ * some hash tables. The results will be kept until pgstat_clear_snapshot()
+ * is called (typically, at end of transaction).
*/
static void
backend_read_statsfile(void)
{
+ /* already read it? */
+ if (pgStatDBHash)
+ return;
+ Assert(!pgStatRunningInCollector);
+
+ /* Autovacuum wants stats about all databases */
if (IsAutoVacuumProcess())
- {
- /* already read it? */
- if (pgStatDBHash)
- return;
- Assert(!pgStatRunningInCollector);
- pgstat_read_statsfile(&pgStatDBHash, InvalidOid);
- }
+ pgStatDBHash = pgstat_read_statsfile(InvalidOid);
else
- {
- TransactionId topXid = GetTopTransactionId();
+ pgStatDBHash = pgstat_read_statsfile(MyDatabaseId);
+}
- if (!TransactionIdEquals(pgStatDBHashXact, topXid))
- {
- Assert(!pgStatRunningInCollector);
- pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId);
- pgStatDBHashXact = topXid;
- }
- }
+
+/* ----------
+ * pgstat_setup_memcxt() -
+ *
+ * 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() -
*
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 94631969d0e..d011fff76f8 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -8,7 +8,7 @@
*
*
* 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_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_dbid(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_hit(PG_FUNCTION_ARGS);
+extern Datum pg_stat_clear_snapshot(PG_FUNCTION_ARGS);
+extern Datum pg_stat_reset(PG_FUNCTION_ARGS);
+
Datum
pg_stat_get_numscans(PG_FUNCTION_ARGS)
@@ -336,16 +338,6 @@ pg_backend_pid(PG_FUNCTION_ARGS)
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
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);
}
+
+
+/* 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();
+}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 154b56b32dd..9ebc4e9b9fd 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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 */
-#define CATALOG_VERSION_NO 200702051
+#define CATALOG_VERSION_NO 200702071
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 500d2395422..e8014c2bda8 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* 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
* 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");
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");
-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_ ));
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_ ));
@@ -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");
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");
+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_ ));
DESCR("Convert bytea value into some ascii-only text string");
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index e64fb8bf550..896cc5ad68c 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -5,7 +5,7 @@
*
* 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
@@ -380,6 +380,7 @@ extern void pgstat_report_tabstat(void);
extern void pgstat_vacuum_tabstat(void);
extern void pgstat_drop_relation(Oid relid);
+extern void pgstat_clear_snapshot(void);
extern void pgstat_reset_counters(void);
extern void pgstat_report_autovac(Oid dboid);
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index d6b17157b06..fc76d142259 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -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,
pg_catalog.pg_statio_user_tables AS b
WHERE t.relname='tenk2' AND b.relname='tenk2';
--- 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)
-
--- 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
+-- function to wait for counters to advance
create function wait_for_stats() returns void as $$
declare
start_time timestamptz := clock_timestamp();
- oldsize bigint;
- newsize bigint;
+ updated bool;
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');
+ -- 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 newsize != oldsize;
+ 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)
@@ -89,13 +56,30 @@ begin
extract(epoch from clock_timestamp() - start_time);
end
$$ 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();
wait_for_stats
----------------
(1 row)
-DROP TABLE stats_hack;
-- check effects
SELECT st.seq_scan >= pr.seq_scan + 1,
st.seq_tup_read >= pr.seq_tup_read + cl.reltuples,
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index dca0031470b..cde38b3a379 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -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
WHERE t.relname='tenk2' AND b.relname='tenk2';
--- enable statistics
-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
+-- function to wait for counters to advance
create function wait_for_stats() returns void as $$
declare
start_time timestamptz := clock_timestamp();
- oldsize bigint;
- newsize bigint;
+ updated bool;
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');
+ -- 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 newsize != oldsize;
+ 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)
@@ -75,9 +51,17 @@ begin
end
$$ 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
SELECT st.seq_scan >= pr.seq_scan + 1,