Commit 23616b47 authored by Tom Lane's avatar Tom Lane

ARGH!

Vacuum must not advance pg_database.datvacuumxid nor truncate CLOG
unless it's processed *all* tables in the database.  Vacuums run by
unprivileged users don't count.

(Beats head against nearest convenient wall...)
parent 3468ed58
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.240 2002/09/23 20:43:41 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.241 2002/09/27 20:57:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -105,9 +105,6 @@ static int elevel = -1; ...@@ -105,9 +105,6 @@ static int elevel = -1;
static TransactionId OldestXmin; static TransactionId OldestXmin;
static TransactionId FreezeLimit; static TransactionId FreezeLimit;
static TransactionId initialOldestXmin;
static TransactionId initialFreezeLimit;
/* non-export function prototypes */ /* non-export function prototypes */
static List *getrels(const RangeVar *vacrel, const char *stmttype); static List *getrels(const RangeVar *vacrel, const char *stmttype);
...@@ -116,7 +113,7 @@ static void vac_update_dbstats(Oid dbid, ...@@ -116,7 +113,7 @@ static void vac_update_dbstats(Oid dbid,
TransactionId frozenXID); TransactionId frozenXID);
static void vac_truncate_clog(TransactionId vacuumXID, static void vac_truncate_clog(TransactionId vacuumXID,
TransactionId frozenXID); TransactionId frozenXID);
static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind); static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind);
static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt); static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
static void scan_heap(VRelStats *vacrelstats, Relation onerel, static void scan_heap(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages); VacPageList vacuum_pages, VacPageList fraged_pages);
...@@ -160,6 +157,9 @@ vacuum(VacuumStmt *vacstmt) ...@@ -160,6 +157,9 @@ vacuum(VacuumStmt *vacstmt)
{ {
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE"; const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
MemoryContext anl_context = NULL; MemoryContext anl_context = NULL;
TransactionId initialOldestXmin = InvalidTransactionId;
TransactionId initialFreezeLimit = InvalidTransactionId;
bool all_rels;
List *vrl, List *vrl,
*cur; *cur;
...@@ -215,6 +215,9 @@ vacuum(VacuumStmt *vacstmt) ...@@ -215,6 +215,9 @@ vacuum(VacuumStmt *vacstmt)
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
/* Assume we are processing everything unless one table is mentioned */
all_rels = (vacstmt->relation == NULL);
/* Build list of relations to process (note this lives in vac_context) */ /* Build list of relations to process (note this lives in vac_context) */
vrl = getrels(vacstmt->relation, stmttype); vrl = getrels(vacstmt->relation, stmttype);
...@@ -248,7 +251,7 @@ vacuum(VacuumStmt *vacstmt) ...@@ -248,7 +251,7 @@ vacuum(VacuumStmt *vacstmt)
*/ */
if (vacstmt->vacuum) if (vacstmt->vacuum)
{ {
if (vacstmt->relation == NULL) if (all_rels)
{ {
/* /*
* It's a database-wide VACUUM. * It's a database-wide VACUUM.
...@@ -271,7 +274,8 @@ vacuum(VacuumStmt *vacstmt) ...@@ -271,7 +274,8 @@ vacuum(VacuumStmt *vacstmt)
* recorded in pg_database. * recorded in pg_database.
*/ */
vacuum_set_xid_limits(vacstmt, false, vacuum_set_xid_limits(vacstmt, false,
&initialOldestXmin, &initialFreezeLimit); &initialOldestXmin,
&initialFreezeLimit);
} }
/* matches the StartTransaction in PostgresMain() */ /* matches the StartTransaction in PostgresMain() */
...@@ -286,7 +290,10 @@ vacuum(VacuumStmt *vacstmt) ...@@ -286,7 +290,10 @@ vacuum(VacuumStmt *vacstmt)
Oid relid = (Oid) lfirsti(cur); Oid relid = (Oid) lfirsti(cur);
if (vacstmt->vacuum) if (vacstmt->vacuum)
vacuum_rel(relid, vacstmt, RELKIND_RELATION); {
if (! vacuum_rel(relid, vacstmt, RELKIND_RELATION))
all_rels = false; /* forget about updating dbstats */
}
if (vacstmt->analyze) if (vacstmt->analyze)
{ {
MemoryContext old_context = NULL; MemoryContext old_context = NULL;
...@@ -331,11 +338,11 @@ vacuum(VacuumStmt *vacstmt) ...@@ -331,11 +338,11 @@ vacuum(VacuumStmt *vacstmt)
StartTransactionCommand(true); StartTransactionCommand(true);
/* /*
* If we did a database-wide VACUUM, update the database's * If we completed a database-wide VACUUM without skipping any
* pg_database row with info about the transaction IDs used, and * relations, update the database's pg_database row with info
* try to truncate pg_clog. * about the transaction IDs used, and try to truncate pg_clog.
*/ */
if (vacstmt->relation == NULL) if (all_rels)
{ {
vac_update_dbstats(MyDatabaseId, vac_update_dbstats(MyDatabaseId,
initialOldestXmin, initialFreezeLimit); initialOldestXmin, initialFreezeLimit);
...@@ -693,6 +700,11 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID) ...@@ -693,6 +700,11 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
/* /*
* vacuum_rel() -- vacuum one heap relation * vacuum_rel() -- vacuum one heap relation
* *
* Returns TRUE if we actually processed the relation (or can ignore it
* for some reason), FALSE if we failed to process it due to permissions
* or other reasons. (A FALSE result really means that some data
* may have been left unvacuumed, so we can't update XID stats.)
*
* Doing one heap at a time incurs extra overhead, since we need to * Doing one heap at a time incurs extra overhead, since we need to
* check that the heap exists again just before we vacuum it. The * check that the heap exists again just before we vacuum it. The
* reason that we do this is so that vacuuming can be spread across * reason that we do this is so that vacuuming can be spread across
...@@ -701,13 +713,14 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID) ...@@ -701,13 +713,14 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
* *
* At entry and exit, we are not inside a transaction. * At entry and exit, we are not inside a transaction.
*/ */
static void static bool
vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
{ {
LOCKMODE lmode; LOCKMODE lmode;
Relation onerel; Relation onerel;
LockRelId onerelid; LockRelId onerelid;
Oid toast_relid; Oid toast_relid;
bool result;
/* Begin a transaction for vacuuming this relation */ /* Begin a transaction for vacuuming this relation */
StartTransactionCommand(true); StartTransactionCommand(true);
...@@ -727,7 +740,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) ...@@ -727,7 +740,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
0, 0, 0)) 0, 0, 0))
{ {
CommitTransactionCommand(true); CommitTransactionCommand(true);
return; return true; /* okay 'cause no data there */
} }
/* /*
...@@ -759,7 +772,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) ...@@ -759,7 +772,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
RelationGetRelationName(onerel)); RelationGetRelationName(onerel));
relation_close(onerel, lmode); relation_close(onerel, lmode);
CommitTransactionCommand(true); CommitTransactionCommand(true);
return; return false;
} }
/* /*
...@@ -772,7 +785,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) ...@@ -772,7 +785,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
RelationGetRelationName(onerel)); RelationGetRelationName(onerel));
relation_close(onerel, lmode); relation_close(onerel, lmode);
CommitTransactionCommand(true); CommitTransactionCommand(true);
return; return false;
} }
/* /*
...@@ -786,7 +799,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) ...@@ -786,7 +799,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
{ {
relation_close(onerel, lmode); relation_close(onerel, lmode);
CommitTransactionCommand(true); CommitTransactionCommand(true);
return; return true; /* assume no long-lived data in temp tables */
} }
/* /*
...@@ -815,6 +828,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) ...@@ -815,6 +828,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
else else
lazy_vacuum_rel(onerel, vacstmt); lazy_vacuum_rel(onerel, vacstmt);
result = true; /* did the vacuum */
/* all done with this class, but hold lock until commit */ /* all done with this class, but hold lock until commit */
relation_close(onerel, NoLock); relation_close(onerel, NoLock);
...@@ -831,12 +846,17 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind) ...@@ -831,12 +846,17 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
* statistics are totally unimportant for toast relations. * statistics are totally unimportant for toast relations.
*/ */
if (toast_relid != InvalidOid) if (toast_relid != InvalidOid)
vacuum_rel(toast_relid, vacstmt, RELKIND_TOASTVALUE); {
if (! vacuum_rel(toast_relid, vacstmt, RELKIND_TOASTVALUE))
result = false; /* failed to vacuum the TOAST table? */
}
/* /*
* Now release the session-level lock on the master table. * Now release the session-level lock on the master table.
*/ */
UnlockRelationForSession(&onerelid, lmode); UnlockRelationForSession(&onerelid, lmode);
return result;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment