Skip to content

Commit 715120e

Browse files
committed
When loading critical system indexes into the relcache, ensure we lock the
underlying catalog not only the index itself. Otherwise, if the cache load process touches the catalog (which will happen for many though not all of these indexes), we are locking index before parent table, which can result in a deadlock against processes that are trying to lock them in the normal order. Per today's failure on buildfarm member gothic_moth; it's surprising the problem hadn't been identified before. Back-patch to 8.2. Earlier releases didn't have the issue because they didn't try to lock these indexes during load (instead assuming that they couldn't change schema at all during multiuser operation).
1 parent dbba3a1 commit 715120e

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

src/backend/utils/cache/relcache.c

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.299 2010/01/12 18:12:18 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.300 2010/01/13 23:07:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -46,9 +46,11 @@
4646
#include "catalog/pg_database.h"
4747
#include "catalog/pg_namespace.h"
4848
#include "catalog/pg_opclass.h"
49+
#include "catalog/pg_operator.h"
4950
#include "catalog/pg_proc.h"
5051
#include "catalog/pg_rewrite.h"
5152
#include "catalog/pg_tablespace.h"
53+
#include "catalog/pg_trigger.h"
5254
#include "catalog/pg_type.h"
5355
#include "catalog/schemapg.h"
5456
#include "commands/trigger.h"
@@ -217,7 +219,7 @@ static void RelationParseRelOptions(Relation relation, HeapTuple tuple);
217219
static void RelationBuildTupleDesc(Relation relation);
218220
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt);
219221
static void RelationInitPhysicalAddr(Relation relation);
220-
static void load_critical_index(Oid indexoid);
222+
static void load_critical_index(Oid indexoid, Oid heapoid);
221223
static TupleDesc GetPgClassDescriptor(void);
222224
static TupleDesc GetPgIndexDescriptor(void);
223225
static void AttrDefaultFetch(Relation relation);
@@ -2719,15 +2721,24 @@ RelationCacheInitializePhase3(void)
27192721
*/
27202722
if (!criticalRelcachesBuilt)
27212723
{
2722-
load_critical_index(ClassOidIndexId);
2723-
load_critical_index(AttributeRelidNumIndexId);
2724-
load_critical_index(IndexRelidIndexId);
2725-
load_critical_index(OpclassOidIndexId);
2726-
load_critical_index(AccessMethodStrategyIndexId);
2727-
load_critical_index(AccessMethodProcedureIndexId);
2728-
load_critical_index(OperatorOidIndexId);
2729-
load_critical_index(RewriteRelRulenameIndexId);
2730-
load_critical_index(TriggerRelidNameIndexId);
2724+
load_critical_index(ClassOidIndexId,
2725+
RelationRelationId);
2726+
load_critical_index(AttributeRelidNumIndexId,
2727+
AttributeRelationId);
2728+
load_critical_index(IndexRelidIndexId,
2729+
IndexRelationId);
2730+
load_critical_index(OpclassOidIndexId,
2731+
OperatorClassRelationId);
2732+
load_critical_index(AccessMethodStrategyIndexId,
2733+
AccessMethodOperatorRelationId);
2734+
load_critical_index(AccessMethodProcedureIndexId,
2735+
AccessMethodProcedureRelationId);
2736+
load_critical_index(OperatorOidIndexId,
2737+
OperatorRelationId);
2738+
load_critical_index(RewriteRelRulenameIndexId,
2739+
RewriteRelationId);
2740+
load_critical_index(TriggerRelidNameIndexId,
2741+
TriggerRelationId);
27312742

27322743
#define NUM_CRITICAL_LOCAL_INDEXES 9 /* fix if you change list above */
27332744

@@ -2744,8 +2755,10 @@ RelationCacheInitializePhase3(void)
27442755
*/
27452756
if (!criticalSharedRelcachesBuilt)
27462757
{
2747-
load_critical_index(DatabaseNameIndexId);
2748-
load_critical_index(DatabaseOidIndexId);
2758+
load_critical_index(DatabaseNameIndexId,
2759+
DatabaseRelationId);
2760+
load_critical_index(DatabaseOidIndexId,
2761+
DatabaseRelationId);
27492762

27502763
#define NUM_CRITICAL_SHARED_INDEXES 2 /* fix if you change list above */
27512764

@@ -2886,19 +2899,30 @@ RelationCacheInitializePhase3(void)
28862899

28872900
/*
28882901
* Load one critical system index into the relcache
2902+
*
2903+
* indexoid is the OID of the target index, heapoid is the OID of the catalog
2904+
* it belongs to.
28892905
*/
28902906
static void
2891-
load_critical_index(Oid indexoid)
2907+
load_critical_index(Oid indexoid, Oid heapoid)
28922908
{
28932909
Relation ird;
28942910

2911+
/*
2912+
* We must lock the underlying catalog before locking the index to avoid
2913+
* deadlock, since RelationBuildDesc might well need to read the catalog,
2914+
* and if anyone else is exclusive-locking this catalog and index they'll
2915+
* be doing it in that order.
2916+
*/
2917+
LockRelationOid(heapoid, AccessShareLock);
28952918
LockRelationOid(indexoid, AccessShareLock);
28962919
ird = RelationBuildDesc(indexoid, true);
28972920
if (ird == NULL)
28982921
elog(PANIC, "could not open critical system index %u", indexoid);
28992922
ird->rd_isnailed = true;
29002923
ird->rd_refcnt = 1;
29012924
UnlockRelationOid(indexoid, AccessShareLock);
2925+
UnlockRelationOid(heapoid, AccessShareLock);
29022926
}
29032927

29042928
/*

0 commit comments

Comments
 (0)