diff options
-rw-r--r-- | src/backend/utils/cache/relcache.c | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 8e25616174f..eede904f506 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -4191,8 +4191,10 @@ RelationGetIndexPredicate(Relation relation) * we can include system attributes (e.g., OID) in the bitmap representation. * * Caller had better hold at least RowExclusiveLock on the target relation - * to ensure that it has a stable set of indexes. This also makes it safe - * (deadlock-free) for us to take locks on the relation's indexes. + * to ensure it is safe (deadlock-free) for us to take locks on the relation's + * indexes. Note that since the introduction of CREATE INDEX CONCURRENTLY, + * that lock level doesn't guarantee a stable set of indexes, so we have to + * be prepared to retry here in case of a change in the set of indexes. * * The returned result is palloc'd in the caller's memory context and should * be bms_free'd when not needed anymore. @@ -4204,6 +4206,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) Bitmapset *uindexattrs; /* columns in unique indexes */ Bitmapset *idindexattrs; /* columns in the replica identity */ List *indexoidlist; + List *newindexoidlist; Oid relreplindex; ListCell *l; MemoryContext oldcxt; @@ -4229,8 +4232,9 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) return NULL; /* - * Get cached list of index OIDs + * Get cached list of index OIDs. If we have to start over, we do so here. */ +restart: indexoidlist = RelationGetIndexList(relation); /* Fall out if no indexes (but relhasindex was set) */ @@ -4241,8 +4245,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) * Copy the rd_replidindex value computed by RelationGetIndexList before * proceeding. This is needed because a relcache flush could occur inside * index_open below, resetting the fields managed by RelationGetIndexList. - * (The values we're computing will still be valid, assuming that caller - * has a sufficient lock on the relation.) + * We need to do the work with a stable value for relreplindex. */ relreplindex = relation->rd_replidindex; @@ -4310,7 +4313,31 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) index_close(indexDesc, AccessShareLock); } - list_free(indexoidlist); + /* + * During one of the index_opens in the above loop, we might have received + * a relcache flush event on this relcache entry, which might have been + * signaling a change in the rel's index list. If so, we'd better start + * over to ensure we deliver up-to-date attribute bitmaps. + */ + newindexoidlist = RelationGetIndexList(relation); + if (equal(indexoidlist, newindexoidlist) && + relreplindex == relation->rd_replidindex) + { + /* Still the same index set, so proceed */ + list_free(newindexoidlist); + list_free(indexoidlist); + } + else + { + /* Gotta do it over ... might as well not leak memory */ + list_free(newindexoidlist); + list_free(indexoidlist); + bms_free(uindexattrs); + bms_free(idindexattrs); + bms_free(indexattrs); + + goto restart; + } /* Don't leak the old values of these bitmaps, if any */ bms_free(relation->rd_indexattr); |