]> granicus.if.org Git - postgresql/commitdiff
Add a function pg_stat_clear_snapshot() that discards any statistics snapshot
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 7 Feb 2007 23:11:30 +0000 (23:11 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 7 Feb 2007 23:11:30 +0000 (23:11 +0000)
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.

doc/src/sgml/monitoring.sgml
src/backend/access/transam/xact.c
src/backend/postmaster/pgstat.c
src/backend/utils/adt/pgstatfuncs.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/pgstat.h
src/test/regress/expected/stats.out
src/test/regress/sql/stats.sql

index 54adf3990b16cac299fe03a6987f84b083c3ff97..4a9732fc39a7417146e4f528cbf599dd49cd5970 100644 (file)
@@ -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">
  <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
    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
-   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>
 
   <table id="monitoring-stats-views-table">
@@ -707,11 +710,20 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
       </entry>
      </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>
       <entry><literal><function>pg_stat_reset</function>()</literal></entry>
-      <entry><type>boolean</type></entry>
+      <entry><type>void</type></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>
      </row>
     </tbody>
index 4ee1cc711cd6ef1189b6f4e955da46b094a597cf..26a3c5ddc2ccd69d777183e93bbc0798111880af 100644 (file)
@@ -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);
 
index 6a5907c466e2e1134b31bfdb9ecaf9cd85c6e147..f64e02020a882876acfa04caa784ecbecc9ca978 100644 (file)
@@ -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() -
  *
index 94631969d0eddedfcbca0f83212873510c7ce9af..d011fff76f8495064ce0f37f2ded9d6b5ddb4c4f 100644 (file)
@@ -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();
+}
index 154b56b32ddf6ad791aaa9b0ceb120cba092402f..9ebc4e9b9fda65397b9b6ac1cd6defef8ce218e5 100644 (file)
@@ -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
index 500d23954220cd0e4f3778a4bb97afb4570c0a19..e8014c2bda819e27a2b658a1074b35867a820531 100644 (file)
@@ -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");
index e64fb8bf5508c07dfdf7a586134f3a566170d551..896cc5ad68c146e8c5f4b6c38c0d8fbb9d05eb2c 100644 (file)
@@ -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);
index d6b17157b069e3c12ed48a65561159d002bc7fcb..fc76d1422599b375f51ed488bc61b86d173cade2 100644 (file)
@@ -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,
index dca0031470bffc244194093f4c54dc0a678dd146..cde38b3a379e5310f57fe3392625d17fdaa16260 100644 (file)
@@ -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,