From: Alvaro Herrera Date: Sun, 14 Jan 2007 20:18:30 +0000 (+0000) Subject: Fix autovacuum to avoid leaving non-permanent Xids in non-connectable X-Git-Tag: REL8_1_7~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d8b5a71c51c01f7cbfa7de64310b892a0c3c7143;p=thirdparty%2Fpostgresql.git Fix autovacuum to avoid leaving non-permanent Xids in non-connectable databases. Apply to the 8.1 branch only, as the new 8.2 (and HEAD) coding does not have this problem. --- diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 866f6460035..8c26a074a7b 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -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. */