diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 7bc5f11..618051a 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -148,7 +148,18 @@ 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; + 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 5663711..7ac073b 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,28 @@ 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; + 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 +890,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, relation_close(onerel, lmode); PopActiveSnapshot(); CommitTransactionCommand(); - return; + return false; } /* @@ -890,7 +907,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, relation_close(onerel, lmode); PopActiveSnapshot(); CommitTransactionCommand(); - return; + return false; } /* @@ -905,7 +922,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound, relation_close(onerel, lmode); PopActiveSnapshot(); CommitTransactionCommand(); - return; + return false; } /* @@ -989,6 +1006,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 7bacf9b..b030b42 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2671,19 +2671,26 @@ 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; + 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 483f225..d7d1b0a 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