]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix autovacuum to avoid leaving non-permanent Xids in non-connectable
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Sun, 14 Jan 2007 20:18:30 +0000 (20:18 +0000)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Sun, 14 Jan 2007 20:18:30 +0000 (20:18 +0000)
databases.

Apply to the 8.1 branch only, as the new 8.2 (and HEAD) coding does not have
this problem.

src/backend/postmaster/autovacuum.c

index 866f64600359202b74c8eaff836af11daa9ad3c9..8c26a074a7bbcda4d33c603f654e1c6f31f89d29 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.5.2.6 2006/05/19 15:15:38 alvherre Exp $
+ *       $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.5.2.7 2007/01/14 20:18:30 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -482,30 +482,19 @@ autovac_get_database_list(void)
 }
 
 /*
- * Process a whole database.  If it's a template database or is disallowing
- * connection by means of datallowconn=false, then issue a VACUUM FREEZE.
- * Else use a plain VACUUM.
+ * Return a palloc'ed copy of the pg_database entry for the given database.
+ * Note that no lock is retained on the entry whatsoever, so it may be stale by
+ * the time the caller inspects it.  This is sufficient for our purposes
+ * however.
  */
-static void
-process_whole_db(void)
+static Form_pg_database
+get_pg_database_entry(Oid dbid)
 {
-       Relation        dbRel;
+       Form_pg_database dbForm;
        ScanKeyData entry[1];
+       Relation        dbRel;
        SysScanDesc scan;
        HeapTuple       tup;
-       Form_pg_database dbForm;
-       bool            freeze;
-
-       /* Start a transaction so our commands have one to play into. */
-       StartTransactionCommand();
-
-        /* functions in indexes may want a snapshot set */
-       ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
-
-       /*
-        * Clean up any dead statistics collector entries for this DB.
-        */
-       pgstat_vacuum_tabstat();
 
        dbRel = heap_open(DatabaseRelationId, AccessShareLock);
 
@@ -523,17 +512,44 @@ process_whole_db(void)
        if (!HeapTupleIsValid(tup))
                elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
 
-       dbForm = (Form_pg_database) GETSTRUCT(tup);
-
-       if (!dbForm->datallowconn || dbForm->datistemplate)
-               freeze = true;
-       else
-               freeze = false;
+       dbForm = (Form_pg_database) palloc(sizeof(FormData_pg_database));
+       memcpy(dbForm, GETSTRUCT(tup), sizeof(FormData_pg_database));
 
        systable_endscan(scan);
 
        heap_close(dbRel, AccessShareLock);
 
+       return dbForm;
+}
+
+/*
+ * Process a whole database.  If it's a template database or is disallowing
+ * connection by means of datallowconn=false, then issue a VACUUM FREEZE.
+ * Else use a plain VACUUM.
+ */
+static void
+process_whole_db(void)
+{
+       Form_pg_database dbForm;
+       bool            freeze;
+
+       /* Start a transaction so our commands have one to play into. */
+       StartTransactionCommand();
+
+        /* functions in indexes may want a snapshot set */
+       ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
+
+       /*
+        * Clean up any dead statistics collector entries for this DB.
+        */
+       pgstat_vacuum_tabstat();
+
+       dbForm = get_pg_database_entry(MyDatabaseId);
+
+       freeze = (!dbForm->datallowconn || dbForm->datistemplate);
+
+       pfree(dbForm);
+
        elog(DEBUG2, "autovacuum: VACUUM%s whole database",
                 (freeze) ? " FREEZE" : "");
 
@@ -564,6 +580,8 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
        List       *toast_table_ids = NIL;
        ListCell   *cell;
        PgStat_StatDBEntry *shared;
+       Form_pg_database dbForm;
+       bool            istemplate;
 
        /* Start a transaction so our commands have one to play into. */
        StartTransactionCommand();
@@ -578,6 +596,14 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
         */
        pgstat_vacuum_tabstat();
 
+       /*
+        * In a template database, we need to avoid putting our Xid in any table,
+        * so disallow analyzes and force use of VACUUM FREEZE.
+        */
+       dbForm = get_pg_database_entry(MyDatabaseId);
+       istemplate = (!dbForm->datallowconn || dbForm->datistemplate);
+       pfree(dbForm);
+
        /*
         * StartTransactionCommand and CommitTransactionCommand will automatically
         * switch to other contexts.  We need this one to keep the list of
@@ -694,10 +720,11 @@ do_autovacuum(PgStat_StatDBEntry *dbentry)
                VacuumCostDelay = tab->vacuum_cost_delay;
                VacuumCostLimit = tab->vacuum_cost_limit;
 
+               /* in a template database, we never analyze and force freezing */
                autovacuum_do_vac_analyze(list_make1_oid(tab->relid),
                                                                  tab->dovacuum,
-                                                                 tab->doanalyze,
-                                                                 false);
+                                                                 !istemplate && tab->doanalyze,
+                                                                 istemplate);
        }
 
        /* Finally close out the last transaction. */