mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
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...)
This commit is contained in:
@ -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;
|
|||||||
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,
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user