all autovacuum actions. Minus-one (the default) disables logging
autovacuum actions. For example, if you set this to
<literal>250ms</literal> then all automatic vacuums and analyzes that run
- 250ms or longer will be logged. Enabling this parameter can be helpful
+ 250ms or longer will be logged. In addition, when this parameter is
+ set to any value other than <literal>-1</literal>, a message will be
+ logged if an autovacuum action is skipped due to the existence of a
+ conflicting lock. Enabling this parameter can be helpful
in tracking autovacuum activity. This setting can only be set in
the <filename>postgresql.conf</> file or on the server command line.
</para>
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/bufmgr.h"
+#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/acl.h"
* matter if we ever try to accumulate stats on dead tuples.) If the rel
* has been dropped since we last saw it, we don't need to process it.
*/
- onerel = try_relation_open(relid, ShareUpdateExclusiveLock);
+ if (!(vacstmt->options & VACOPT_NOWAIT))
+ onerel = try_relation_open(relid, ShareUpdateExclusiveLock);
+ else if (ConditionalLockRelationOid(relid, ShareUpdateExclusiveLock))
+ onerel = try_relation_open(relid, NoLock);
+ else
+ {
+ onerel = NULL;
+ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
+ ereport(LOG,
+ (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+ errmsg("skipping analyze of \"%s\" --- lock not available",
+ vacstmt->relation->relname)));
+ }
if (!onerel)
return;
/* non-export function prototypes */
static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
static void vac_truncate_clog(TransactionId frozenXID);
-static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
+static bool vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
bool for_wraparound, bool *scanned_all);
bool scanned_all = false;
if (vacstmt->options & VACOPT_VACUUM)
- vacuum_rel(relid, vacstmt, do_toast, for_wraparound,
- &scanned_all);
+ {
+ if (!vacuum_rel(relid, vacstmt, do_toast, for_wraparound,
+ &scanned_all))
+ continue;
+ }
if (vacstmt->options & VACOPT_ANALYZE)
{
*
* At entry and exit, we are not inside a transaction.
*/
-static void
+static bool
vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound,
bool *scanned_all)
{
*
* There's a race condition here: the rel may have gone away since the
* last time we saw it. If so, we don't need to vacuum it.
+ *
+ * If we've been asked not to wait for the relation lock, acquire it
+ * first in non-blocking mode, before calling try_relation_open().
*/
- onerel = try_relation_open(relid, lmode);
+ if (!(vacstmt->options & VACOPT_NOWAIT))
+ onerel = try_relation_open(relid, lmode);
+ else if (ConditionalLockRelationOid(relid, lmode))
+ onerel = try_relation_open(relid, NoLock);
+ else
+ {
+ onerel = NULL;
+ if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
+ ereport(LOG,
+ (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+ errmsg("skipping vacuum of \"%s\" --- lock not available",
+ vacstmt->relation->relname)));
+ }
if (!onerel)
{
PopActiveSnapshot();
CommitTransactionCommand();
- return;
+ return false;
}
/*
relation_close(onerel, lmode);
PopActiveSnapshot();
CommitTransactionCommand();
- return;
+ return false;
}
/*
relation_close(onerel, lmode);
PopActiveSnapshot();
CommitTransactionCommand();
- return;
+ return false;
}
/*
relation_close(onerel, lmode);
PopActiveSnapshot();
CommitTransactionCommand();
- return;
+ return false;
}
/*
* Now release the session-level lock on the master table.
*/
UnlockRelationIdForSession(&onerelid, lmode);
+
+ /* Report that we really did it. */
+ return true;
}
BufferAccessStrategy bstrategy)
{
VacuumStmt vacstmt;
+ RangeVar rangevar;
- /* Set up command parameters --- use a local variable instead of palloc */
+ /* Set up command parameters --- use local variables instead of palloc */
MemSet(&vacstmt, 0, sizeof(vacstmt));
+ MemSet(&rangevar, 0, sizeof(rangevar));
+
+ rangevar.schemaname = tab->at_nspname;
+ rangevar.relname = tab->at_relname;
+ rangevar.location = -1;
vacstmt.type = T_VacuumStmt;
- vacstmt.options = 0;
+ if (!tab->at_wraparound)
+ vacstmt.options = VACOPT_NOWAIT;
if (tab->at_dovacuum)
vacstmt.options |= VACOPT_VACUUM;
if (tab->at_doanalyze)
vacstmt.options |= VACOPT_ANALYZE;
vacstmt.freeze_min_age = tab->at_freeze_min_age;
vacstmt.freeze_table_age = tab->at_freeze_table_age;
- vacstmt.relation = NULL; /* not used since we pass a relid */
+ /* we pass the OID, but might need this anyway for an error message */
+ vacstmt.relation = &rangevar;
vacstmt.va_cols = NIL;
/* Let pgstat know what we're doing */
VACOPT_ANALYZE = 1 << 1, /* do ANALYZE */
VACOPT_VERBOSE = 1 << 2, /* print progress info */
VACOPT_FREEZE = 1 << 3, /* FREEZE option */
- VACOPT_FULL = 1 << 4 /* FULL (non-concurrent) vacuum */
+ VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */
+ VACOPT_NOWAIT = 1 << 5
} VacuumOption;
typedef struct VacuumStmt