aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache/relcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r--src/backend/utils/cache/relcache.c118
1 files changed, 82 insertions, 36 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 5ff0d9e4fdf..1ffa24356b3 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1901,6 +1901,8 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc)
}
list_free(relation->rd_indexlist);
bms_free(relation->rd_indexattr);
+ bms_free(relation->rd_keyattr);
+ bms_free(relation->rd_idattr);
FreeTriggerDesc(relation->trigdesc);
if (relation->rd_options)
pfree(relation->rd_options);
@@ -2547,6 +2549,7 @@ AtEOXact_cleanup(Relation relation, bool isCommit)
list_free(relation->rd_indexlist);
relation->rd_indexlist = NIL;
relation->rd_oidindex = InvalidOid;
+ relation->rd_replidindex = InvalidOid;
relation->rd_indexvalid = 0;
}
}
@@ -2645,6 +2648,7 @@ AtEOSubXact_cleanup(Relation relation, bool isCommit,
list_free(relation->rd_indexlist);
relation->rd_indexlist = NIL;
relation->rd_oidindex = InvalidOid;
+ relation->rd_replidindex = InvalidOid;
relation->rd_indexvalid = 0;
}
}
@@ -3596,6 +3600,10 @@ CheckConstraintFetch(Relation relation)
* of the index list. rd_oidindex is valid when rd_indexvalid isn't zero;
* it is the pg_class OID of a unique index on OID when the relation has one,
* and InvalidOid if there is no such index.
+ *
+ * In exactly the same way, we update rd_replidindex, which is the pg_class
+ * OID of an index to be used as the relation's replication identity index,
+ * or InvalidOid if there is no such index.
*/
List *
RelationGetIndexList(Relation relation)
@@ -3667,8 +3675,8 @@ RelationGetIndexList(Relation relation)
/*
* Invalid, non-unique, non-immediate or predicate indexes aren't
- * interesting for neither oid indexes nor replication identity
- * indexes, so don't check them.
+ * interesting for either oid indexes or replication identity indexes,
+ * so don't check them.
*/
if (!IndexIsValid(index) || !index->indisunique ||
!index->indimmediate ||
@@ -3681,35 +3689,29 @@ RelationGetIndexList(Relation relation)
indclass->values[0] == OID_BTREE_OPS_OID)
oidIndex = index->indexrelid;
- /* always prefer primary keys */
+ /* remember primary key index if any */
if (index->indisprimary)
pkeyIndex = index->indexrelid;
- /* explicitly chosen index */
+ /* remember explicitly chosen replica index */
if (index->indisreplident)
candidateIndex = index->indexrelid;
}
systable_endscan(indscan);
- /* primary key */
- if (replident == REPLICA_IDENTITY_DEFAULT &&
- OidIsValid(pkeyIndex))
- relation->rd_replidindex = pkeyIndex;
- /* explicitly chosen index */
- else if (replident == REPLICA_IDENTITY_INDEX &&
- OidIsValid(candidateIndex))
- relation->rd_replidindex = candidateIndex;
- /* nothing */
- else
- relation->rd_replidindex = InvalidOid;
-
heap_close(indrel, AccessShareLock);
/* Now save a copy of the completed list in the relcache entry. */
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
relation->rd_indexlist = list_copy(result);
relation->rd_oidindex = oidIndex;
+ if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex))
+ relation->rd_replidindex = pkeyIndex;
+ else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
+ relation->rd_replidindex = candidateIndex;
+ else
+ relation->rd_replidindex = InvalidOid;
relation->rd_indexvalid = 1;
MemoryContextSwitchTo(oldcxt);
@@ -3767,7 +3769,8 @@ insert_ordered_oid(List *list, Oid datum)
* correctly with respect to the full index set. It is up to the caller
* to ensure that a correct rd_indexattr set has been cached before first
* calling RelationSetIndexList; else a subsequent inquiry might cause a
- * wrong rd_indexattr set to get computed and cached.
+ * wrong rd_indexattr set to get computed and cached. Likewise, we do not
+ * touch rd_keyattr or rd_idattr.
*/
void
RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex)
@@ -3783,6 +3786,8 @@ RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex)
list_free(relation->rd_indexlist);
relation->rd_indexlist = indexIds;
relation->rd_oidindex = oidIndex;
+ /* For the moment, assume the target rel hasn't got a replica index */
+ relation->rd_replidindex = InvalidOid;
relation->rd_indexvalid = 2; /* mark list as forced */
/* Flag relation as needing eoxact cleanup (to reset the list) */
EOXactListAdd(relation);
@@ -3817,6 +3822,27 @@ RelationGetOidIndex(Relation relation)
}
/*
+ * RelationGetReplicaIndex -- get OID of the relation's replica identity index
+ *
+ * Returns InvalidOid if there is no such index.
+ */
+Oid
+RelationGetReplicaIndex(Relation relation)
+{
+ List *ilist;
+
+ if (relation->rd_indexvalid == 0)
+ {
+ /* RelationGetIndexList does the heavy lifting. */
+ ilist = RelationGetIndexList(relation);
+ list_free(ilist);
+ Assert(relation->rd_indexvalid != 0);
+ }
+
+ return relation->rd_replidindex;
+}
+
+/*
* RelationGetIndexExpressions -- get the index expressions for an index
*
* We cache the result of transforming pg_index.indexprs into a node tree.
@@ -3954,8 +3980,8 @@ RelationGetIndexPredicate(Relation relation)
* predicates.)
*
* Depending on attrKind, a bitmap covering the attnums for all index columns,
- * for all key columns or for all the columns the configured replica identity
- * are returned.
+ * for all potential foreign key columns, or for all columns in the configured
+ * replica identity index is returned.
*
* Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
* we can include system attributes (e.g., OID) in the bitmap representation.
@@ -3974,22 +4000,25 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Bitmapset *uindexattrs; /* columns in unique indexes */
Bitmapset *idindexattrs; /* columns in the replica identity */
List *indexoidlist;
+ Oid relreplindex;
ListCell *l;
MemoryContext oldcxt;
/* Quick exit if we already computed the result. */
if (relation->rd_indexattr != NULL)
+ {
switch (attrKind)
{
- case INDEX_ATTR_BITMAP_IDENTITY_KEY:
- return bms_copy(relation->rd_idattr);
- case INDEX_ATTR_BITMAP_KEY:
- return bms_copy(relation->rd_keyattr);
case INDEX_ATTR_BITMAP_ALL:
return bms_copy(relation->rd_indexattr);
+ case INDEX_ATTR_BITMAP_KEY:
+ return bms_copy(relation->rd_keyattr);
+ case INDEX_ATTR_BITMAP_IDENTITY_KEY:
+ return bms_copy(relation->rd_idattr);
default:
elog(ERROR, "unknown attrKind %u", attrKind);
}
+ }
/* Fast path if definitely no indexes */
if (!RelationGetForm(relation)->relhasindex)
@@ -4005,6 +4034,15 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
return NULL;
/*
+ * 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.)
+ */
+ relreplindex = relation->rd_replidindex;
+
+ /*
* For each index, add referenced attributes to indexattrs.
*
* Note: we consider all indexes returned by RelationGetIndexList, even if
@@ -4026,7 +4064,6 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
bool isKey; /* candidate key */
bool isIDKey; /* replica identity index */
-
indexDesc = index_open(indexOid, AccessShareLock);
/* Extract index key information from the index's pg_index row */
@@ -4038,7 +4075,7 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
indexInfo->ii_Predicate == NIL;
/* Is this index the configured (or default) replica identity? */
- isIDKey = indexOid == relation->rd_replidindex;
+ isIDKey = (indexOid == relreplindex);
/* Collect simple attribute references */
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
@@ -4050,13 +4087,13 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
indexattrs = bms_add_member(indexattrs,
attrnum - FirstLowInvalidHeapAttributeNumber);
- if (isIDKey)
- idindexattrs = bms_add_member(idindexattrs,
- attrnum - FirstLowInvalidHeapAttributeNumber);
-
if (isKey)
uindexattrs = bms_add_member(uindexattrs,
attrnum - FirstLowInvalidHeapAttributeNumber);
+
+ if (isIDKey)
+ idindexattrs = bms_add_member(idindexattrs,
+ attrnum - FirstLowInvalidHeapAttributeNumber);
}
}
@@ -4071,22 +4108,28 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
list_free(indexoidlist);
- /* Now save a copy of the bitmap in the relcache entry. */
+ /*
+ * Now save copies of the bitmaps in the relcache entry. We intentionally
+ * set rd_indexattr last, because that's the one that signals validity of
+ * the values; if we run out of memory before making that copy, we won't
+ * leave the relcache entry looking like the other ones are valid but
+ * empty.
+ */
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
- relation->rd_indexattr = bms_copy(indexattrs);
relation->rd_keyattr = bms_copy(uindexattrs);
relation->rd_idattr = bms_copy(idindexattrs);
+ relation->rd_indexattr = bms_copy(indexattrs);
MemoryContextSwitchTo(oldcxt);
/* We return our original working copy for caller to play with */
switch (attrKind)
{
- case INDEX_ATTR_BITMAP_IDENTITY_KEY:
- return idindexattrs;
- case INDEX_ATTR_BITMAP_KEY:
- return uindexattrs;
case INDEX_ATTR_BITMAP_ALL:
return indexattrs;
+ case INDEX_ATTR_BITMAP_KEY:
+ return uindexattrs;
+ case INDEX_ATTR_BITMAP_IDENTITY_KEY:
+ return idindexattrs;
default:
elog(ERROR, "unknown attrKind %u", attrKind);
return NULL;
@@ -4630,8 +4673,11 @@ load_relcache_init_file(bool shared)
rel->rd_refcnt = 0;
rel->rd_indexvalid = 0;
rel->rd_indexlist = NIL;
- rel->rd_indexattr = NULL;
rel->rd_oidindex = InvalidOid;
+ rel->rd_replidindex = InvalidOid;
+ rel->rd_indexattr = NULL;
+ rel->rd_keyattr = NULL;
+ rel->rd_idattr = NULL;
rel->rd_createSubid = InvalidSubTransactionId;
rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;
rel->rd_amcache = NULL;