Skip to content

Commit 0f45d1e

Browse files
committed
Fix LOAD_CRIT_INDEX() macro to take out AccessShareLock on the system index
it is trying to build a relcache entry for. This is an oversight in my 8.2 patch that tried to ensure we always took a lock on a relation before trying to build its relcache entry. The implication is that if someone committed a reindex of a critical system index at about the same time that some other backend were starting up without a valid pg_internal.init file, the second one might PANIC due to not seeing any valid version of the index's pg_class row. Improbable case, but definitely not impossible.
1 parent a9b3e4f commit 0f45d1e

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

src/backend/utils/cache/relcache.c

Lines changed: 18 additions & 6 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.270 2008/04/01 00:48:33 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.271 2008/04/16 18:23:04 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -220,8 +220,11 @@ static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
220220
/*
221221
* ScanPgRelation
222222
*
223-
* this is used by RelationBuildDesc to find a pg_class
224-
* tuple matching targetRelId.
223+
* This is used by RelationBuildDesc to find a pg_class
224+
* tuple matching targetRelId. The caller must hold at least
225+
* AccessShareLock on the target relid to prevent concurrent-update
226+
* scenarios --- else our SnapshotNow scan might fail to find any
227+
* version that it thinks is live.
225228
*
226229
* NB: the returned tuple has been copied into palloc'd storage
227230
* and must eventually be freed with heap_freetuple.
@@ -773,18 +776,18 @@ equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
773776
}
774777

775778

776-
/* ----------------------------------
779+
/*
777780
* RelationBuildDesc
778781
*
779782
* Build a relation descriptor --- either a new one, or by
780783
* recycling the given old relation object. The latter case
781784
* supports rebuilding a relcache entry without invalidating
782-
* pointers to it.
785+
* pointers to it. The caller must hold at least
786+
* AccessShareLock on the target relid.
783787
*
784788
* Returns NULL if no pg_class row could be found for the given relid
785789
* (suggesting we are trying to access a just-deleted relation).
786790
* Any other error is reported via elog.
787-
* --------------------------------
788791
*/
789792
static Relation
790793
RelationBuildDesc(Oid targetRelId, Relation oldrelation)
@@ -1608,6 +1611,10 @@ RelationClose(Relation relation)
16081611
* RelationClearRelation just marks the entry as invalid by setting
16091612
* rd_isvalid to false. This routine is called to fix the entry when it
16101613
* is next needed.
1614+
*
1615+
* We assume that at the time we are called, we have at least AccessShareLock
1616+
* on the target index. (Note: in the calls from RelationClearRelation,
1617+
* this is legitimate because we know the rel has positive refcount.)
16111618
*/
16121619
static void
16131620
RelationReloadIndexInfo(Relation relation)
@@ -1692,6 +1699,9 @@ RelationReloadIndexInfo(Relation relation)
16921699
* usually used when we are notified of a change to an open relation
16931700
* (one with refcount > 0). However, this routine just does whichever
16941701
* it's told to do; callers must determine which they want.
1702+
*
1703+
* NB: when rebuilding, we'd better hold some lock on the relation.
1704+
* In current usages this is presumed true because it has refcnt > 0.
16951705
*/
16961706
static void
16971707
RelationClearRelation(Relation relation, bool rebuild)
@@ -2542,12 +2552,14 @@ RelationCacheInitializePhase2(void)
25422552

25432553
#define LOAD_CRIT_INDEX(indexoid) \
25442554
do { \
2555+
LockRelationOid(indexoid, AccessShareLock); \
25452556
ird = RelationBuildDesc(indexoid, NULL); \
25462557
if (ird == NULL) \
25472558
elog(PANIC, "could not open critical system index %u", \
25482559
indexoid); \
25492560
ird->rd_isnailed = true; \
25502561
ird->rd_refcnt = 1; \
2562+
UnlockRelationOid(indexoid, AccessShareLock); \
25512563
} while (0)
25522564

25532565
LOAD_CRIT_INDEX(ClassOidIndexId);

0 commit comments

Comments
 (0)