invalidate_indexattr_v2.patch
application/octet-stream
Filename: invalidate_indexattr_v2.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/utils/cache/relcache.c | 36 | 8 |
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 8a7c560..f06d345 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -4745,9 +4745,11 @@ RelationGetIndexPredicate(Relation relation)
* Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
* 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.
+ * While all callers should at least RowExclusiveLock on the target relation,
+ * we still can't guarantee a stable set of indexes because CREATE INDEX
+ * CONCURRENTLY and DROP INDEX CONCURRENTLY can change set of indexes, without
+ * taking any conflicting lock. So we must be prepared to handle changes in the
+ * set of indexes and recompute bitmaps, when necessary.
*
* The returned result is palloc'd in the caller's memory context and should
* be bms_free'd when not needed anymore.
@@ -4787,6 +4789,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
if (!RelationGetForm(relation)->relhasindex)
return NULL;
+recheck:
/*
* Get cached list of index OIDs
*/
@@ -4798,15 +4801,16 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
/*
* Copy the rd_pkindex and 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.)
+ * RelationGetIndexList before proceeding. If a relcache flush could occur
+ * inside index_open below, resetting the fields managed by
+ * RelationGetIndexList, we compare the old and new values and recompute
+ * attribute maps again.
*/
relpkindex = relation->rd_pkindex;
relreplindex = relation->rd_replidindex;
+ Assert(relation->rd_indexvalid != 0);
+
/*
* For each index, add referenced attributes to indexattrs.
*
@@ -4882,6 +4886,30 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
list_free(indexoidlist);
+ /*
+ * If a relcache flush happened during index_open, we may have computed
+ * stale values of the bitmaps since we used the old information. Since all
+ * these bitmaps are closely tied with the index list as well as other
+ * information such as the primary index and the replica identity, we must
+ * recompute everything. Otherwise we could be end up with a wrongly cached
+ * values of these bitmaps.
+ *
+ * Note that a subsequent call to RelationGetIndexList() will reload the
+ * new list of indexes, but that does not invalidate the cached attribute
+ * bitmaps. So we handle that here itself.
+ */
+ if (relpkindex != relation->rd_pkindex ||
+ relreplindex != relation->rd_replidindex ||
+ relation->rd_indexvalid == 0)
+ {
+ bms_free(uindexattrs);
+ bms_free(pkindexattrs);
+ bms_free(idindexattrs);
+ bms_free(indexattrs);
+
+ goto recheck;
+ }
+
/* Don't leak the old values of these bitmaps, if any */
bms_free(relation->rd_indexattr);
relation->rd_indexattr = NULL;