Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcbfbb14

Browse files
committed
Avoid deadlock during orphan temp table removal.
If temp tables have dependencies (such as sequences) then it'spossible for autovacuum's cleanup of orphan temp tables to deadlockagainst an incoming backend that's trying to clean out the tempnamespace for its own use. That can happen because RemoveTempRelations'performDeletion call can visit objects within the namespace inan order different from the order in which a per-table deletionwill visit them.To fix, observe that performDeletion will begin by taking an exclusivelock on the temp namespace (even though it won't actually delete it).So, if we can get a shared lock on the namespace, we can be sure we'renot running concurrently with RemoveTempRelations, while also notconflicting with ordinary use of the namespace. This requiresintroducing a conditional version of LockDatabaseObject, but that's nobig deal. (It's surprising we've got along without that this long.)Report and patch by Mikhail Zhilin. Back-patch to all supportedbranches.Discussion:https://postgr.es/m/c43ce028-2bc2-4865-9b89-3f706246eed5@postgrespro.ru
1 parent3235a11 commitcbfbb14

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

‎src/backend/postmaster/autovacuum.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#include"catalog/dependency.h"
7777
#include"catalog/namespace.h"
7878
#include"catalog/pg_database.h"
79+
#include"catalog/pg_namespace.h"
7980
#include"commands/dbcommands.h"
8081
#include"commands/vacuum.h"
8182
#include"lib/ilist.h"
@@ -2329,6 +2330,24 @@ do_autovacuum(void)
23292330
continue;
23302331
}
23312332

2333+
/*
2334+
* Try to lock the temp namespace, too. Even though we have lock on
2335+
* the table itself, there's a risk of deadlock against an incoming
2336+
* backend trying to clean out the temp namespace, in case this table
2337+
* has dependencies (such as sequences) that the backend's
2338+
* performDeletion call might visit in a different order. If we can
2339+
* get AccessShareLock on the namespace, that's sufficient to ensure
2340+
* we're not running concurrently with RemoveTempRelations. If we
2341+
* can't, back off and let RemoveTempRelations do its thing.
2342+
*/
2343+
if (!ConditionalLockDatabaseObject(NamespaceRelationId,
2344+
classForm->relnamespace,0,
2345+
AccessShareLock))
2346+
{
2347+
UnlockRelationOid(relid,AccessExclusiveLock);
2348+
continue;
2349+
}
2350+
23322351
/* OK, let's delete it */
23332352
ereport(LOG,
23342353
(errmsg("autovacuum: dropping orphan temp table \"%s.%s.%s\"",
@@ -2346,7 +2365,7 @@ do_autovacuum(void)
23462365

23472366
/*
23482367
* To commit the deletion, end current transaction and start a new
2349-
* one. Note this also releases thelock we took.
2368+
* one. Note this also releases thelocks we took.
23502369
*/
23512370
CommitTransactionCommand();
23522371
StartTransactionCommand();

‎src/backend/storage/lmgr/lmgr.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,44 @@ LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
10191019
AcceptInvalidationMessages();
10201020
}
10211021

1022+
/*
1023+
*ConditionalLockDatabaseObject
1024+
*
1025+
* As above, but only lock if we can get the lock without blocking.
1026+
* Returns true iff the lock was acquired.
1027+
*/
1028+
bool
1029+
ConditionalLockDatabaseObject(Oidclassid,Oidobjid,uint16objsubid,
1030+
LOCKMODElockmode)
1031+
{
1032+
LOCKTAGtag;
1033+
LOCALLOCK*locallock;
1034+
LockAcquireResultres;
1035+
1036+
SET_LOCKTAG_OBJECT(tag,
1037+
MyDatabaseId,
1038+
classid,
1039+
objid,
1040+
objsubid);
1041+
1042+
res=LockAcquireExtended(&tag,lockmode, false, true, true,&locallock);
1043+
1044+
if (res==LOCKACQUIRE_NOT_AVAIL)
1045+
return false;
1046+
1047+
/*
1048+
* Now that we have the lock, check for invalidation messages; see notes
1049+
* in LockRelationOid.
1050+
*/
1051+
if (res!=LOCKACQUIRE_ALREADY_CLEAR)
1052+
{
1053+
AcceptInvalidationMessages();
1054+
MarkLockClear(locallock);
1055+
}
1056+
1057+
return true;
1058+
}
1059+
10221060
/*
10231061
*UnlockDatabaseObject
10241062
*/

‎src/include/storage/lmgr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ extern void SpeculativeInsertionWait(TransactionId xid, uint32 token);
9393
/* Lock a general object (other than a relation) of the current database */
9494
externvoidLockDatabaseObject(Oidclassid,Oidobjid,uint16objsubid,
9595
LOCKMODElockmode);
96+
externboolConditionalLockDatabaseObject(Oidclassid,Oidobjid,
97+
uint16objsubid,LOCKMODElockmode);
9698
externvoidUnlockDatabaseObject(Oidclassid,Oidobjid,uint16objsubid,
9799
LOCKMODElockmode);
98100

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp