Skip to content

Commit 23616b4

Browse files
committed
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...)
1 parent 3468ed5 commit 23616b4

File tree

1 file changed

+38
-18
lines changed

1 file changed

+38
-18
lines changed

src/backend/commands/vacuum.c

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.240 2002/09/23 20:43:41 tgl Exp $
16+
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.241 2002/09/27 20:57:08 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -105,9 +105,6 @@ static int elevel = -1;
105105
static TransactionId OldestXmin;
106106
static TransactionId FreezeLimit;
107107

108-
static TransactionId initialOldestXmin;
109-
static TransactionId initialFreezeLimit;
110-
111108

112109
/* non-export function prototypes */
113110
static List *getrels(const RangeVar *vacrel, const char *stmttype);
@@ -116,7 +113,7 @@ static void vac_update_dbstats(Oid dbid,
116113
TransactionId frozenXID);
117114
static void vac_truncate_clog(TransactionId vacuumXID,
118115
TransactionId frozenXID);
119-
static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind);
116+
static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind);
120117
static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
121118
static void scan_heap(VRelStats *vacrelstats, Relation onerel,
122119
VacPageList vacuum_pages, VacPageList fraged_pages);
@@ -160,6 +157,9 @@ vacuum(VacuumStmt *vacstmt)
160157
{
161158
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
162159
MemoryContext anl_context = NULL;
160+
TransactionId initialOldestXmin = InvalidTransactionId;
161+
TransactionId initialFreezeLimit = InvalidTransactionId;
162+
bool all_rels;
163163
List *vrl,
164164
*cur;
165165

@@ -215,6 +215,9 @@ vacuum(VacuumStmt *vacstmt)
215215
ALLOCSET_DEFAULT_INITSIZE,
216216
ALLOCSET_DEFAULT_MAXSIZE);
217217

218+
/* Assume we are processing everything unless one table is mentioned */
219+
all_rels = (vacstmt->relation == NULL);
220+
218221
/* Build list of relations to process (note this lives in vac_context) */
219222
vrl = getrels(vacstmt->relation, stmttype);
220223

@@ -248,7 +251,7 @@ vacuum(VacuumStmt *vacstmt)
248251
*/
249252
if (vacstmt->vacuum)
250253
{
251-
if (vacstmt->relation == NULL)
254+
if (all_rels)
252255
{
253256
/*
254257
* It's a database-wide VACUUM.
@@ -271,7 +274,8 @@ vacuum(VacuumStmt *vacstmt)
271274
* recorded in pg_database.
272275
*/
273276
vacuum_set_xid_limits(vacstmt, false,
274-
&initialOldestXmin, &initialFreezeLimit);
277+
&initialOldestXmin,
278+
&initialFreezeLimit);
275279
}
276280

277281
/* matches the StartTransaction in PostgresMain() */
@@ -286,7 +290,10 @@ vacuum(VacuumStmt *vacstmt)
286290
Oid relid = (Oid) lfirsti(cur);
287291

288292
if (vacstmt->vacuum)
289-
vacuum_rel(relid, vacstmt, RELKIND_RELATION);
293+
{
294+
if (! vacuum_rel(relid, vacstmt, RELKIND_RELATION))
295+
all_rels = false; /* forget about updating dbstats */
296+
}
290297
if (vacstmt->analyze)
291298
{
292299
MemoryContext old_context = NULL;
@@ -331,11 +338,11 @@ vacuum(VacuumStmt *vacstmt)
331338
StartTransactionCommand(true);
332339

333340
/*
334-
* If we did a database-wide VACUUM, update the database's
335-
* pg_database row with info about the transaction IDs used, and
336-
* try to truncate pg_clog.
341+
* If we completed a database-wide VACUUM without skipping any
342+
* relations, update the database's pg_database row with info
343+
* about the transaction IDs used, and try to truncate pg_clog.
337344
*/
338-
if (vacstmt->relation == NULL)
345+
if (all_rels)
339346
{
340347
vac_update_dbstats(MyDatabaseId,
341348
initialOldestXmin, initialFreezeLimit);
@@ -693,6 +700,11 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
693700
/*
694701
* vacuum_rel() -- vacuum one heap relation
695702
*
703+
* Returns TRUE if we actually processed the relation (or can ignore it
704+
* for some reason), FALSE if we failed to process it due to permissions
705+
* or other reasons. (A FALSE result really means that some data
706+
* may have been left unvacuumed, so we can't update XID stats.)
707+
*
696708
* Doing one heap at a time incurs extra overhead, since we need to
697709
* check that the heap exists again just before we vacuum it. The
698710
* reason that we do this is so that vacuuming can be spread across
@@ -701,13 +713,14 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
701713
*
702714
* At entry and exit, we are not inside a transaction.
703715
*/
704-
static void
716+
static bool
705717
vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
706718
{
707719
LOCKMODE lmode;
708720
Relation onerel;
709721
LockRelId onerelid;
710722
Oid toast_relid;
723+
bool result;
711724

712725
/* Begin a transaction for vacuuming this relation */
713726
StartTransactionCommand(true);
@@ -727,7 +740,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
727740
0, 0, 0))
728741
{
729742
CommitTransactionCommand(true);
730-
return;
743+
return true; /* okay 'cause no data there */
731744
}
732745

733746
/*
@@ -759,7 +772,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
759772
RelationGetRelationName(onerel));
760773
relation_close(onerel, lmode);
761774
CommitTransactionCommand(true);
762-
return;
775+
return false;
763776
}
764777

765778
/*
@@ -772,7 +785,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
772785
RelationGetRelationName(onerel));
773786
relation_close(onerel, lmode);
774787
CommitTransactionCommand(true);
775-
return;
788+
return false;
776789
}
777790

778791
/*
@@ -786,7 +799,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
786799
{
787800
relation_close(onerel, lmode);
788801
CommitTransactionCommand(true);
789-
return;
802+
return true; /* assume no long-lived data in temp tables */
790803
}
791804

792805
/*
@@ -815,6 +828,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
815828
else
816829
lazy_vacuum_rel(onerel, vacstmt);
817830

831+
result = true; /* did the vacuum */
832+
818833
/* all done with this class, but hold lock until commit */
819834
relation_close(onerel, NoLock);
820835

@@ -831,12 +846,17 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
831846
* statistics are totally unimportant for toast relations.
832847
*/
833848
if (toast_relid != InvalidOid)
834-
vacuum_rel(toast_relid, vacstmt, RELKIND_TOASTVALUE);
849+
{
850+
if (! vacuum_rel(toast_relid, vacstmt, RELKIND_TOASTVALUE))
851+
result = false; /* failed to vacuum the TOAST table? */
852+
}
835853

836854
/*
837855
* Now release the session-level lock on the master table.
838856
*/
839857
UnlockRelationForSession(&onerelid, lmode);
858+
859+
return result;
840860
}
841861

842862

0 commit comments

Comments
 (0)