diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 2d8396e4e9..5a43774b33 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -4080,7 +4080,10 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; all autovacuum actions. Minus-one (the default) disables logging autovacuum actions. For example, if you set this to 250ms 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 -1, 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 postgresql.conf file or on the server command line. diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 7bc5f111f4..4c106dd8c5 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -36,6 +36,7 @@ #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" @@ -148,7 +149,19 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, * 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; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 5663711674..1651aa94dc 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -61,7 +61,7 @@ static BufferAccessStrategy vac_strategy; /* 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); @@ -226,8 +226,11 @@ vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, 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) { @@ -764,7 +767,7 @@ vac_truncate_clog(TransactionId frozenXID) * * 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) { @@ -835,14 +838,29 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, * * 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; } /* @@ -873,7 +891,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, relation_close(onerel, lmode); PopActiveSnapshot(); CommitTransactionCommand(); - return; + return false; } /* @@ -890,7 +908,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, relation_close(onerel, lmode); PopActiveSnapshot(); CommitTransactionCommand(); - return; + return false; } /* @@ -905,7 +923,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, relation_close(onerel, lmode); PopActiveSnapshot(); CommitTransactionCommand(); - return; + return false; } /* @@ -989,6 +1007,9 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, * Now release the session-level lock on the master table. */ UnlockRelationIdForSession(&onerelid, lmode); + + /* Report that we really did it. */ + return true; } diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 7bacf9b2de..7307c4177c 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2671,19 +2671,27 @@ autovacuum_do_vac_analyze(autovac_table *tab, 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 */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 483f22591e..d7d1b0a6fd 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2332,7 +2332,8 @@ typedef enum VacuumOption 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