Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit aec4cf1

Browse files
committed
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.
1 parent d9ce688 commit aec4cf1

File tree

9 files changed

+188
-166
lines changed

9 files changed

+188
-166
lines changed

doc/src/sgml/monitoring.sgml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/monitoring.sgml,v 1.45 2007/02/01 00:28:17 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/monitoring.sgml,v 1.46 2007/02/07 23:11:29 tgl Exp $ -->
22

33
<chapter id="monitoring">
44
<title>Monitoring Database Activity</title>
@@ -227,7 +227,10 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
227227
queries on the statistics and correlate the results without worrying that
228228
the numbers are changing underneath you. But if you want to see new
229229
results with each query, be sure to do the queries outside any transaction
230-
block.
230+
block. Alternatively, you can invoke
231+
<function>pg_stat_clear_snapshot</function>(), which will discard the
232+
current transaction's statistics snapshot (if any). The next use of
233+
statistical information will cause a new snapshot to be fetched.
231234
</para>
232235

233236
<table id="monitoring-stats-views-table">
@@ -707,11 +710,20 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
707710
</entry>
708711
</row>
709712

713+
<row>
714+
<entry><literal><function>pg_stat_clear_snapshot</function>()</literal></entry>
715+
<entry><type>void</type></entry>
716+
<entry>
717+
Discard the current statistics snapshot
718+
</entry>
719+
</row>
720+
710721
<row>
711722
<entry><literal><function>pg_stat_reset</function>()</literal></entry>
712-
<entry><type>boolean</type></entry>
723+
<entry><type>void</type></entry>
713724
<entry>
714-
Reset all block-level and row-level statistics to zero
725+
Reset all statistics counters for the current database to zero
726+
(requires superuser privileges)
715727
</entry>
716728
</row>
717729
</tbody>

src/backend/access/transam/xact.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.232 2007/02/01 19:10:25 momjian Exp $
13+
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.233 2007/02/07 23:11:29 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -1628,6 +1628,7 @@ CommitTransaction(void)
16281628
AtEOXact_Namespace(true);
16291629
/* smgrcommit already done */
16301630
AtEOXact_Files();
1631+
pgstat_clear_snapshot();
16311632
pgstat_count_xact_commit();
16321633
pgstat_report_txn_timestamp(0);
16331634

@@ -1844,6 +1845,7 @@ PrepareTransaction(void)
18441845
AtEOXact_Namespace(true);
18451846
/* smgrcommit already done */
18461847
AtEOXact_Files();
1848+
pgstat_clear_snapshot();
18471849

18481850
CurrentResourceOwner = NULL;
18491851
ResourceOwnerDelete(TopTransactionResourceOwner);
@@ -1995,6 +1997,7 @@ AbortTransaction(void)
19951997
AtEOXact_Namespace(false);
19961998
smgrabort();
19971999
AtEOXact_Files();
2000+
pgstat_clear_snapshot();
19982001
pgstat_count_xact_rollback();
19992002
pgstat_report_txn_timestamp(0);
20002003

src/backend/postmaster/pgstat.c

Lines changed: 87 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
* Copyright (c) 2001-2007, PostgreSQL Global Development Group
1515
*
16-
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.144 2007/01/26 20:06:52 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.145 2007/02/07 23:11:29 tgl Exp $
1717
* ----------
1818
*/
1919
#include "postgres.h"
@@ -130,9 +130,8 @@ static TabStatArray SharedTabStat = {0, 0, NULL};
130130
static int pgStatXactCommit = 0;
131131
static int pgStatXactRollback = 0;
132132

133-
static TransactionId pgStatDBHashXact = InvalidTransactionId;
133+
static MemoryContext pgStatLocalContext = NULL;
134134
static HTAB *pgStatDBHash = NULL;
135-
static TransactionId pgStatLocalStatusXact = InvalidTransactionId;
136135
static PgBackendStatus *localBackendStatusTable = NULL;
137136
static int localNumBackends = 0;
138137

@@ -156,11 +155,13 @@ static void pgstat_beshutdown_hook(int code, Datum arg);
156155
static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create);
157156
static void pgstat_drop_database(Oid databaseid);
158157
static void pgstat_write_statsfile(void);
159-
static void pgstat_read_statsfile(HTAB **dbhash, Oid onlydb);
158+
static HTAB *pgstat_read_statsfile(Oid onlydb);
160159
static void backend_read_statsfile(void);
161160
static void pgstat_read_current_status(void);
162161
static HTAB *pgstat_collect_oids(Oid catalogid);
163162

163+
static void pgstat_setup_memcxt(void);
164+
164165
static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
165166
static void pgstat_send(void *msg, int len);
166167

@@ -1535,22 +1536,24 @@ pgstat_report_waiting(bool waiting)
15351536
static void
15361537
pgstat_read_current_status(void)
15371538
{
1538-
TransactionId topXid = GetTopTransactionId();
15391539
volatile PgBackendStatus *beentry;
1540+
PgBackendStatus *localtable;
15401541
PgBackendStatus *localentry;
15411542
int i;
15421543

15431544
Assert(!pgStatRunningInCollector);
1544-
if (TransactionIdEquals(pgStatLocalStatusXact, topXid))
1545+
if (localBackendStatusTable)
15451546
return; /* already done */
15461547

1547-
localBackendStatusTable = (PgBackendStatus *)
1548-
MemoryContextAlloc(TopTransactionContext,
1548+
pgstat_setup_memcxt();
1549+
1550+
localtable = (PgBackendStatus *)
1551+
MemoryContextAlloc(pgStatLocalContext,
15491552
sizeof(PgBackendStatus) * MaxBackends);
15501553
localNumBackends = 0;
15511554

15521555
beentry = BackendStatusArray;
1553-
localentry = localBackendStatusTable;
1556+
localentry = localtable;
15541557
for (i = 1; i <= MaxBackends; i++)
15551558
{
15561559
/*
@@ -1587,7 +1590,8 @@ pgstat_read_current_status(void)
15871590
}
15881591
}
15891592

1590-
pgStatLocalStatusXact = topXid;
1593+
/* Set the pointer only after completion of a valid table */
1594+
localBackendStatusTable = localtable;
15911595
}
15921596

15931597

@@ -1720,7 +1724,7 @@ PgstatCollectorMain(int argc, char *argv[])
17201724
* zero.
17211725
*/
17221726
pgStatRunningInCollector = true;
1723-
pgstat_read_statsfile(&pgStatDBHash, InvalidOid);
1727+
pgStatDBHash = pgstat_read_statsfile(InvalidOid);
17241728

17251729
/*
17261730
* Setup the descriptor set for select(2). Since only one bit in the set
@@ -2090,38 +2094,24 @@ pgstat_write_statsfile(void)
20902094
* databases' hash table (whose entries point to the tables' hash tables).
20912095
* ----------
20922096
*/
2093-
static void
2094-
pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
2097+
static HTAB *
2098+
pgstat_read_statsfile(Oid onlydb)
20952099
{
20962100
PgStat_StatDBEntry *dbentry;
20972101
PgStat_StatDBEntry dbbuf;
20982102
PgStat_StatTabEntry *tabentry;
20992103
PgStat_StatTabEntry tabbuf;
21002104
HASHCTL hash_ctl;
2105+
HTAB *dbhash;
21012106
HTAB *tabhash = NULL;
21022107
FILE *fpin;
21032108
int32 format_id;
21042109
bool found;
2105-
MemoryContext use_mcxt;
2106-
int mcxt_flags;
21072110

21082111
/*
2109-
* If running in the collector or the autovacuum process, we use the
2110-
* DynaHashCxt memory context. If running in a backend, we use the
2111-
* TopTransactionContext instead, so the caller must only know the last
2112-
* XactId when this call happened to know if his tables are still valid or
2113-
* already gone!
2112+
* The tables will live in pgStatLocalContext.
21142113
*/
2115-
if (pgStatRunningInCollector || IsAutoVacuumProcess())
2116-
{
2117-
use_mcxt = NULL;
2118-
mcxt_flags = 0;
2119-
}
2120-
else
2121-
{
2122-
use_mcxt = TopTransactionContext;
2123-
mcxt_flags = HASH_CONTEXT;
2124-
}
2114+
pgstat_setup_memcxt();
21252115

21262116
/*
21272117
* Create the DB hashtable
@@ -2130,17 +2120,17 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
21302120
hash_ctl.keysize = sizeof(Oid);
21312121
hash_ctl.entrysize = sizeof(PgStat_StatDBEntry);
21322122
hash_ctl.hash = oid_hash;
2133-
hash_ctl.hcxt = use_mcxt;
2134-
*dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl,
2135-
HASH_ELEM | HASH_FUNCTION | mcxt_flags);
2123+
hash_ctl.hcxt = pgStatLocalContext;
2124+
dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl,
2125+
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
21362126

21372127
/*
21382128
* Try to open the status file. If it doesn't exist, the backends simply
21392129
* return zero for anything and the collector simply starts from scratch
21402130
* with empty counters.
21412131
*/
21422132
if ((fpin = AllocateFile(PGSTAT_STAT_FILENAME, PG_BINARY_R)) == NULL)
2143-
return;
2133+
return dbhash;
21442134

21452135
/*
21462136
* Verify it's of the expected format.
@@ -2178,7 +2168,7 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
21782168
/*
21792169
* Add to the DB hash
21802170
*/
2181-
dbentry = (PgStat_StatDBEntry *) hash_search(*dbhash,
2171+
dbentry = (PgStat_StatDBEntry *) hash_search(dbhash,
21822172
(void *) &dbbuf.databaseid,
21832173
HASH_ENTER,
21842174
&found);
@@ -2207,11 +2197,11 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
22072197
hash_ctl.keysize = sizeof(Oid);
22082198
hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
22092199
hash_ctl.hash = oid_hash;
2210-
hash_ctl.hcxt = use_mcxt;
2200+
hash_ctl.hcxt = pgStatLocalContext;
22112201
dbentry->tables = hash_create("Per-database table",
22122202
PGSTAT_TAB_HASH_SIZE,
22132203
&hash_ctl,
2214-
HASH_ELEM | HASH_FUNCTION | mcxt_flags);
2204+
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
22152205

22162206
/*
22172207
* Arrange that following 'T's add entries to this database's
@@ -2274,44 +2264,78 @@ pgstat_read_statsfile(HTAB **dbhash, Oid onlydb)
22742264

22752265
done:
22762266
FreeFile(fpin);
2267+
2268+
return dbhash;
22772269
}
22782270

22792271
/*
2280-
* If not done for this transaction, read the statistics collector
2281-
* stats file into some hash tables.
2282-
*
2283-
* Because we store the tables in TopTransactionContext, the result
2284-
* is good for the entire current main transaction.
2285-
*
2286-
* Inside the autovacuum process, the statfile is assumed to be valid
2287-
* "forever", that is one iteration, within one database. This means
2288-
* we only consider the statistics as they were when the autovacuum
2289-
* iteration started.
2272+
* If not already done, read the statistics collector stats file into
2273+
* some hash tables. The results will be kept until pgstat_clear_snapshot()
2274+
* is called (typically, at end of transaction).
22902275
*/
22912276
static void
22922277
backend_read_statsfile(void)
22932278
{
2279+
/* already read it? */
2280+
if (pgStatDBHash)
2281+
return;
2282+
Assert(!pgStatRunningInCollector);
2283+
2284+
/* Autovacuum wants stats about all databases */
22942285
if (IsAutoVacuumProcess())
2295-
{
2296-
/* already read it? */
2297-
if (pgStatDBHash)
2298-
return;
2299-
Assert(!pgStatRunningInCollector);
2300-
pgstat_read_statsfile(&pgStatDBHash, InvalidOid);
2301-
}
2286+
pgStatDBHash = pgstat_read_statsfile(InvalidOid);
23022287
else
2303-
{
2304-
TransactionId topXid = GetTopTransactionId();
2288+
pgStatDBHash = pgstat_read_statsfile(MyDatabaseId);
2289+
}
23052290

2306-
if (!TransactionIdEquals(pgStatDBHashXact, topXid))
2307-
{
2308-
Assert(!pgStatRunningInCollector);
2309-
pgstat_read_statsfile(&pgStatDBHash, MyDatabaseId);
2310-
pgStatDBHashXact = topXid;
2311-
}
2312-
}
2291+
2292+
/* ----------
2293+
* pgstat_setup_memcxt() -
2294+
*
2295+
* Create pgStatLocalContext, if not already done.
2296+
* ----------
2297+
*/
2298+
static void
2299+
pgstat_setup_memcxt(void)
2300+
{
2301+
if (!pgStatLocalContext)
2302+
pgStatLocalContext = AllocSetContextCreate(TopMemoryContext,
2303+
"Statistics snapshot",
2304+
ALLOCSET_SMALL_MINSIZE,
2305+
ALLOCSET_SMALL_INITSIZE,
2306+
ALLOCSET_SMALL_MAXSIZE);
23132307
}
23142308

2309+
2310+
/* ----------
2311+
* pgstat_clear_snapshot() -
2312+
*
2313+
* Discard any data collected in the current transaction. Any subsequent
2314+
* request will cause new snapshots to be read.
2315+
*
2316+
* This is also invoked during transaction commit or abort to discard
2317+
* the no-longer-wanted snapshot.
2318+
* ----------
2319+
*/
2320+
void
2321+
pgstat_clear_snapshot(void)
2322+
{
2323+
/* In an autovacuum process we keep the stats forever */
2324+
if (IsAutoVacuumProcess())
2325+
return;
2326+
2327+
/* Release memory, if any was allocated */
2328+
if (pgStatLocalContext)
2329+
MemoryContextDelete(pgStatLocalContext);
2330+
2331+
/* Reset variables */
2332+
pgStatLocalContext = NULL;
2333+
pgStatDBHash = NULL;
2334+
localBackendStatusTable = NULL;
2335+
localNumBackends = 0;
2336+
}
2337+
2338+
23152339
/* ----------
23162340
* pgstat_recv_tabstat() -
23172341
*

0 commit comments

Comments
 (0)