Tom Lane wrote:
> Alvaro Herrera <[EMAIL PROTECTED]> writes:
> > Maybe we could forcibly activate the freeze mode on a template database?
>
> Might not be a bad idea. And even more to the point, forcibly disable
> analyze.
Patch implementing this (albeit untested!) attached. I'll try to
reproduce the problem without the patch, and then test with the patch
applied.
--
Alvaro Herrera http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.5.2.6
diff -c -p -r1.5.2.6 autovacuum.c
*** src/backend/postmaster/autovacuum.c 19 May 2006 15:15:38 -0000 1.5.2.6
--- src/backend/postmaster/autovacuum.c 12 Jan 2007 15:49:52 -0000
*************** autovac_get_database_list(void)
*** 482,511 ****
}
/*
! * 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)
{
! Relation dbRel;
ScanKeyData entry[1];
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);
--- 482,500 ----
}
/*
! * 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 Form_pg_database
! get_pg_database_entry(Oid dbid)
{
! Form_pg_database dbForm;
ScanKeyData entry[1];
+ Relation dbRel;
SysScanDesc scan;
HeapTuple tup;
dbRel = heap_open(DatabaseRelationId, AccessShareLock);
*************** process_whole_db(void)
*** 523,539 ****
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;
systable_endscan(scan);
heap_close(dbRel, AccessShareLock);
elog(DEBUG2, "autovacuum: VACUUM%s whole database",
(freeze) ? " FREEZE" : "");
--- 512,555 ----
if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for database %u", MyDatabaseId);
! 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" : "");
*************** do_autovacuum(PgStat_StatDBEntry *dbentr
*** 564,569 ****
--- 580,587 ----
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();
*************** do_autovacuum(PgStat_StatDBEntry *dbentr
*** 579,584 ****
--- 597,610 ----
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
* relations to vacuum/analyze across transactions.
*************** do_autovacuum(PgStat_StatDBEntry *dbentr
*** 694,703 ****
VacuumCostDelay = tab->vacuum_cost_delay;
VacuumCostLimit = tab->vacuum_cost_limit;
autovacuum_do_vac_analyze(list_make1_oid(tab->relid),
tab->dovacuum,
! tab->doanalyze,
! false);
}
/* Finally close out the last transaction. */
--- 720,730 ----
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,
! !istemplate && tab->doanalyze,
! istemplate);
}
/* Finally close out the last transaction. */
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings