aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/postmaster/autovacuum.c21
-rw-r--r--src/backend/storage/lmgr/lmgr.c38
-rw-r--r--src/include/storage/lmgr.h2
3 files changed, 60 insertions, 1 deletions
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index ae9be9b9113..7dd9345c617 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -76,6 +76,7 @@
#include "catalog/dependency.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
#include "commands/vacuum.h"
#include "lib/ilist.h"
@@ -2329,6 +2330,24 @@ do_autovacuum(void)
continue;
}
+ /*
+ * Try to lock the temp namespace, too. Even though we have lock on
+ * the table itself, there's a risk of deadlock against an incoming
+ * backend trying to clean out the temp namespace, in case this table
+ * has dependencies (such as sequences) that the backend's
+ * performDeletion call might visit in a different order. If we can
+ * get AccessShareLock on the namespace, that's sufficient to ensure
+ * we're not running concurrently with RemoveTempRelations. If we
+ * can't, back off and let RemoveTempRelations do its thing.
+ */
+ if (!ConditionalLockDatabaseObject(NamespaceRelationId,
+ classForm->relnamespace, 0,
+ AccessShareLock))
+ {
+ UnlockRelationOid(relid, AccessExclusiveLock);
+ continue;
+ }
+
/* OK, let's delete it */
ereport(LOG,
(errmsg("autovacuum: dropping orphan temp table \"%s.%s.%s\"",
@@ -2346,7 +2365,7 @@ do_autovacuum(void)
/*
* To commit the deletion, end current transaction and start a new
- * one. Note this also releases the lock we took.
+ * one. Note this also releases the locks we took.
*/
CommitTransactionCommand();
StartTransactionCommand();
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index ee9b89a6726..2da91eb492d 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -1020,6 +1020,44 @@ LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
}
/*
+ * ConditionalLockDatabaseObject
+ *
+ * As above, but only lock if we can get the lock without blocking.
+ * Returns true iff the lock was acquired.
+ */
+bool
+ConditionalLockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
+ LOCKMODE lockmode)
+{
+ LOCKTAG tag;
+ LOCALLOCK *locallock;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_OBJECT(tag,
+ MyDatabaseId,
+ classid,
+ objid,
+ objsubid);
+
+ res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock);
+
+ if (res == LOCKACQUIRE_NOT_AVAIL)
+ return false;
+
+ /*
+ * Now that we have the lock, check for invalidation messages; see notes
+ * in LockRelationOid.
+ */
+ if (res != LOCKACQUIRE_ALREADY_CLEAR)
+ {
+ AcceptInvalidationMessages();
+ MarkLockClear(locallock);
+ }
+
+ return true;
+}
+
+/*
* UnlockDatabaseObject
*/
void
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 4ee91e3cf93..8ab833d1d4a 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -93,6 +93,8 @@ extern void SpeculativeInsertionWait(TransactionId xid, uint32 token);
/* Lock a general object (other than a relation) of the current database */
extern void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode);
+extern bool ConditionalLockDatabaseObject(Oid classid, Oid objid,
+ uint16 objsubid, LOCKMODE lockmode);
extern void UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
LOCKMODE lockmode);