* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.36 2007/09/21 16:32:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.37 2007/10/24 20:55:36 alvherre Exp $
*
* NOTES
* Each global transaction is associated with a global transaction
gxact->proc.databaseId = databaseid;
gxact->proc.roleId = owner;
gxact->proc.inCommit = false;
- gxact->proc.inVacuum = false;
- gxact->proc.isAutovacuum = false;
+ gxact->proc.vacuumFlags = 0;
gxact->proc.lwWaiting = false;
gxact->proc.lwExclusive = false;
gxact->proc.lwWaitLink = NULL;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.109 2007/09/24 03:12:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.110 2007/10/24 20:55:36 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_relation.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
+#include "storage/proc.h"
#include "utils/acl.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
return;
}
+ /* let others know what I'm doing */
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ MyProc->vacuumFlags |= PROC_IN_ANALYZE;
+ LWLockRelease(ProcArrayLock);
+
/* measure elapsed time iff autovacuum logging requires it */
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
{
RelationGetRelationName(onerel),
pg_rusage_show(&ru0))));
}
+
+ /*
+ * Reset my PGPROC flag. Note: we need this here, and not in vacuum_rel,
+ * because the vacuum flag is cleared by the end-of-xact code.
+ */
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ MyProc->vacuumFlags &= ~PROC_IN_ANALYZE;
+ LWLockRelease(ProcArrayLock);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.359 2007/09/20 17:56:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.360 2007/10/24 20:55:36 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
* fixed-size never-null columns, but these are.
*
* Another reason for doing it this way is that when we are in a lazy
- * VACUUM and have inVacuum set, we mustn't do any updates --- somebody
- * vacuuming pg_class might think they could delete a tuple marked with
- * xmin = our xid.
+ * VACUUM and have PROC_IN_VACUUM set, we mustn't do any updates ---
+ * somebody vacuuming pg_class might think they could delete a tuple
+ * marked with xmin = our xid.
*
* This routine is shared by full VACUUM, lazy VACUUM, and stand-alone
* ANALYZE.
* During a lazy VACUUM we do not run any user-supplied functions, and
* so it should be safe to not create a transaction snapshot.
*
- * We can furthermore set the inVacuum flag, which lets other
+ * We can furthermore set the PROC_IN_VACUUM flag, which lets other
* concurrent VACUUMs know that they can ignore this one while
- * determining their OldestXmin. (The reason we don't set inVacuum
+ * determining their OldestXmin. (The reason we don't set it
* during a full VACUUM is exactly that we may have to run user-
* defined functions for functional indexes, and we want to make sure
* that if they use the snapshot set above, any tuples it requires
* depends on the contents of other tables is arguably broken, but we
* won't break it here by violating transaction semantics.)
*
- * Note: the inVacuum flag remains set until CommitTransaction or
+ * Note: this flag remains set until CommitTransaction or
* AbortTransaction. We don't want to clear it until we reset
* MyProc->xid/xmin, else OldestXmin might appear to go backwards,
* which is probably Not Good.
*/
- MyProc->inVacuum = true;
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ MyProc->vacuumFlags |= PROC_IN_VACUUM;
+ LWLockRelease(ProcArrayLock);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.62 2007/10/24 19:08:25 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.63 2007/10/24 20:55:36 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
int at_freeze_min_age;
int at_vacuum_cost_delay;
int at_vacuum_cost_limit;
+ bool at_wraparound;
} autovac_table;
/*-------------
static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry, bool *dovacuum,
- bool *doanalyze);
+ bool *doanalyze, bool *wraparound);
static void autovacuum_do_vac_analyze(Oid relid, bool dovacuum,
bool doanalyze, int freeze_min_age,
/* Identify myself via ps */
init_ps_display("autovacuum worker process", "", "", "");
- if (PostAuthDelay)
- pg_usleep(PostAuthDelay * 1000000L);
-
SetProcessingMode(InitProcessing);
/*
ereport(DEBUG1,
(errmsg("autovacuum: processing database \"%s\"", dbname)));
+ if (PostAuthDelay)
+ pg_usleep(PostAuthDelay * 1000000L);
+
/* And do an appropriate amount of work */
recentXid = ReadNewTransactionId();
do_autovacuum();
/* clean up memory before each iteration */
MemoryContextResetAndDeleteChildren(PortalContext);
+ /* set the "vacuum for wraparound" flag in PGPROC */
+ if (tab->at_wraparound)
+ {
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ MyProc->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
+ LWLockRelease(ProcArrayLock);
+ }
+
/*
* We will abort vacuuming the current table if something errors out,
* and continue with the next one in schedule; in particular, this
get_rel_name(tab->at_relid));
EmitErrorReport();
+ /* this resets the PGPROC flags too */
AbortOutOfAnyTransaction();
FlushErrorState();
MemoryContextResetAndDeleteChildren(PortalContext);
}
PG_END_TRY();
+ /* reset my PGPROC flag */
+ if (tab->at_wraparound)
+ {
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+ MyProc->vacuumFlags &= ~PROC_VACUUM_FOR_WRAPAROUND;
+ LWLockRelease(ProcArrayLock);
+ }
+
/* be tidy */
pfree(tab);
{
bool dovacuum;
bool doanalyze;
+ bool dummy;
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
- &dovacuum, &doanalyze);
+ &dovacuum, &doanalyze, &dummy);
if (classForm->relkind == RELKIND_TOASTVALUE)
{
bool doit = false;
PgStat_StatDBEntry *shared;
PgStat_StatDBEntry *dbentry;
+ bool wraparound,
+ toast_wraparound = false;
/* use fresh stats */
autovac_refresh_stats();
shared, dbentry);
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
- &dovacuum, &doanalyze);
+ &dovacuum, &doanalyze, &wraparound);
/* OK, it needs vacuum by itself */
if (dovacuum)
{
bool toast_dovacuum;
bool toast_doanalyze;
+ bool toast_wraparound;
Form_pg_class toastClassForm;
PgStat_StatTabEntry *toasttabentry;
shared, dbentry);
/* note we use the pg_autovacuum entry for the main table */
- relation_needs_vacanalyze(toastrelid, avForm, toastClassForm,
- toasttabentry, &toast_dovacuum,
- &toast_doanalyze);
+ relation_needs_vacanalyze(toastrelid, avForm,
+ toastClassForm, toasttabentry,
+ &toast_dovacuum, &toast_doanalyze,
+ &toast_wraparound);
/* we only consider VACUUM for toast tables */
if (toast_dovacuum)
{
tab->at_freeze_min_age = freeze_min_age;
tab->at_vacuum_cost_limit = vac_cost_limit;
tab->at_vacuum_cost_delay = vac_cost_delay;
+ tab->at_wraparound = wraparound || toast_wraparound;
}
heap_close(avRel, AccessShareLock);
* relation_needs_vacanalyze
*
* Check whether a relation needs to be vacuumed or analyzed; return each into
- * "dovacuum" and "doanalyze", respectively. avForm and tabentry can be NULL,
+ * "dovacuum" and "doanalyze", respectively. Also return whether the vacuum is
+ * being forced because of Xid wraparound. avForm and tabentry can be NULL,
* classForm shouldn't.
*
* A table needs to be vacuumed if the number of dead tuples exceeds a
PgStat_StatTabEntry *tabentry,
/* output params below */
bool *dovacuum,
- bool *doanalyze)
+ bool *doanalyze,
+ bool *wraparound)
{
bool force_vacuum;
float4 reltuples; /* pg_class.reltuples */
force_vacuum = (TransactionIdIsNormal(classForm->relfrozenxid) &&
TransactionIdPrecedes(classForm->relfrozenxid,
xidForceLimit));
+ *wraparound = force_vacuum;
/* User disabled it in pg_autovacuum? (But ignore if at risk) */
if (avForm && !avForm->enabled && !force_vacuum)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.35 2007/09/23 18:50:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.36 2007/10/24 20:55:36 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
proc->xid = InvalidTransactionId;
proc->lxid = InvalidLocalTransactionId;
proc->xmin = InvalidTransactionId;
- proc->inVacuum = false; /* must be cleared with xid/xmin */
+ /* must be cleared with xid/xmin: */
+ proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
proc->inCommit = false; /* be sure this is cleared in abort */
/* Clear the subtransaction-XID cache too while holding the lock */
proc->lxid = InvalidLocalTransactionId;
proc->xmin = InvalidTransactionId;
- proc->inVacuum = false; /* must be cleared with xid/xmin */
+ /* must be cleared with xid/xmin: */
+ proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
proc->inCommit = false; /* be sure this is cleared in abort */
Assert(proc->subxids.nxids == 0);
proc->xid = InvalidTransactionId;
proc->lxid = InvalidLocalTransactionId;
proc->xmin = InvalidTransactionId;
- proc->inVacuum = false; /* redundant, but just in case */
- proc->inCommit = false; /* ditto */
+
+ /* redundant, but just in case */
+ proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
+ proc->inCommit = false;
/* Clear the subtransaction-XID cache too */
proc->subxids.nxids = 0;
* If allDbs is TRUE then all backends are considered; if allDbs is FALSE
* then only backends running in my own database are considered.
*
- * If ignoreVacuum is TRUE then backends with inVacuum set are ignored.
+ * If ignoreVacuum is TRUE then backends with the PROC_IN_VACUUM flag set are
+ * ignored.
*
* This is used by VACUUM to decide which deleted tuples must be preserved
* in a table. allDbs = TRUE is needed for shared relations, but allDbs =
{
volatile PGPROC *proc = arrayP->procs[index];
- if (ignoreVacuum && proc->inVacuum)
+ if (ignoreVacuum && (proc->vacuumFlags & PROC_IN_VACUUM))
continue;
if (allDbs || proc->databaseId == MyDatabaseId)
TransactionId xid;
/* Ignore procs running LAZY VACUUM */
- if (proc->inVacuum)
+ if (proc->vacuumFlags & PROC_IN_VACUUM)
continue;
/* Update globalxmin to be the smallest valid xmin */
found = true;
- if (proc->isAutovacuum)
+ if (proc->vacuumFlags & PROC_IS_AUTOVACUUM)
{
/* an autovacuum --- send it SIGTERM before sleeping */
int autopid = proc->pid;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.194 2007/09/08 20:31:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.195 2007/10/24 20:55:36 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
MyProc->inCommit = false;
- MyProc->inVacuum = false;
- MyProc->isAutovacuum = IsAutoVacuumWorkerProcess();
+ MyProc->vacuumFlags = 0;
+ if (IsAutoVacuumWorkerProcess())
+ MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM;
MyProc->lwWaiting = false;
MyProc->lwExclusive = false;
MyProc->lwWaitLink = NULL;
MyProc->databaseId = InvalidOid;
MyProc->roleId = InvalidOid;
MyProc->inCommit = false;
- MyProc->inVacuum = false;
- MyProc->isAutovacuum = IsAutoVacuumLauncherProcess(); /* is this needed? */
+ /* we don't set the "is autovacuum" flag in the launcher */
+ MyProc->vacuumFlags = 0;
MyProc->lwWaiting = false;
MyProc->lwExclusive = false;
MyProc->lwWaitLink = NULL;
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.100 2007/09/05 18:10:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.101 2007/10/24 20:55:36 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS];
};
+/* Flags for PGPROC->vacuumFlags */
+#define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */
+#define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */
+#define PROC_IN_ANALYZE 0x04 /* currently running analyze */
+#define PROC_VACUUM_FOR_WRAPAROUND 0x08 /* set by autovac only */
+
+/* flags reset at EOXact */
+#define PROC_VACUUM_STATE_MASK (0x0E)
+
/*
* Each backend has a PGPROC struct in shared memory. There is also a list of
* currently-unused PGPROC structs that will be reallocated to new backends.
bool inCommit; /* true if within commit critical section */
- bool inVacuum; /* true if current xact is a LAZY VACUUM */
- bool isAutovacuum; /* true if it's autovacuum */
+ uint8 vacuumFlags; /* vacuum-related flags, see above */
/* Info about LWLock the process is currently waiting for, if any. */
bool lwWaiting; /* true if waiting for an LW lock */