* 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.
Bitmapset *uindexattrs; /* columns in unique indexes */
Bitmapset *idindexattrs; /* columns in the replica identity */
List *indexoidlist;
+ List *newindexoidlist;
Oid relreplindex;
ListCell *l;
MemoryContext oldcxt;
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) */
* 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;
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);