summaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2011-02-07 22:04:29 -0500
committerRobert Haas <rhaas@postgresql.org>2011-02-07 22:04:29 -0500
commit32896c40ca766146312b28a5a0eb3f66ca0300ed (patch)
tree88596b8de0a3d0f57beaf994ff8ace6eda6fd9ba /src/backend/commands
parent47082fa875179ae629edb26807ab3f38a775280b (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.c15
-rw-r--r--src/backend/commands/vacuum.c39
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;
}