diff options
author | Robert Haas <rhaas@postgresql.org> | 2011-02-07 22:04:29 -0500 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2011-02-07 22:04:29 -0500 |
commit | 32896c40ca766146312b28a5a0eb3f66ca0300ed (patch) | |
tree | 88596b8de0a3d0f57beaf994ff8ace6eda6fd9ba /src/backend/commands | |
parent | 47082fa875179ae629edb26807ab3f38a775280b (diff) |
Avoid having autovacuum workers wait for relation locks.
Waiting for relation locks can lead to starvation - it pins down an
autovacuum worker for as long as the lock is held. But if we're doing
an anti-wraparound vacuum, then we still wait; maintenance can no longer
be put off.
To assist with troubleshooting, if log_autovacuum_min_duration >= 0,
we log whenever an autovacuum or autoanalyze is skipped for this reason.
Per a gripe by Josh Berkus, and ensuing discussion.
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/analyze.c | 15 | ||||
-rw-r--r-- | src/backend/commands/vacuum.c | 39 |
2 files changed, 44 insertions, 10 deletions
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 7bc5f111f4d..4c106dd8c57 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 56637116745..1651aa94dc2 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; } |