]> granicus.if.org Git - postgresql/commitdiff
Ensure that backends see up-to-date statistics for shared catalogs.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 25 May 2016 21:48:15 +0000 (17:48 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 25 May 2016 21:48:15 +0000 (17:48 -0400)
Ever since we split the statistics collector's reports into per-database
files (commit 187492b6c2e8cafc), backends have been seeing stale statistics
for shared catalogs.  This is because the inquiry message only prompts the
collector to write the per-database file for the requesting backend's own
database.  Stats for shared catalogs are in a separate file for "DB 0",
which didn't get updated.

In normal operation this was partially masked by the fact that the
autovacuum launcher would send an inquiry message at least once per
autovacuum_naptime that asked for "DB 0"; so the shared-catalog stats would
never be more than a minute out of date.  However the problem becomes very
obvious with autovacuum disabled, as reported by Peter Eisentraut.

To fix, redefine the semantics of inquiry messages so that both the
specified DB and DB 0 will be dumped.  (This might seem a bit inefficient,
but we have no good way to know whether a backend's transaction will look
at shared-catalog stats, so we have to read both groups of stats whenever
we request stats.  Sending two inquiry messages would definitely not be
better.)

Back-patch to 9.3 where the bug was introduced.

Report: <56AD41AC.1030509@gmx.net>

src/backend/postmaster/pgstat.c

index 41f43749b5020b7de227fdf582f42d74ea029148..a6db9cdbfac55b8bd588a77b621efe2f9ee98c44 100644 (file)
@@ -5504,7 +5504,16 @@ pgstat_db_requested(Oid databaseid)
 {
        slist_iter      iter;
 
-       /* Check the databases if they need to refresh the stats. */
+       /*
+        * If any requests are outstanding at all, we should write the stats for
+        * shared catalogs (the "database" with OID 0).  This ensures that
+        * backends will see up-to-date stats for shared catalogs, even though
+        * they send inquiry messages mentioning only their own DB.
+        */
+       if (databaseid == InvalidOid && !slist_is_empty(&last_statrequests))
+               return true;
+
+       /* Search to see if there's an open request to write this database. */
        slist_foreach(iter, &last_statrequests)
        {
                DBWriteRequest *req = slist_container(DBWriteRequest, next, iter.cur);