aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/cache
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/cache')
-rw-r--r--src/backend/utils/cache/relcache.c46
1 files changed, 36 insertions, 10 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index d47d2d37fcb..2810b35eea1 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1601,6 +1601,7 @@ RelationIdGetRelation(Oid relationId)
RelationReloadIndexInfo(rd);
else
RelationClearRelation(rd, true);
+ Assert(rd->rd_isvalid);
}
return rd;
}
@@ -1712,8 +1713,9 @@ RelationReloadIndexInfo(Relation relation)
/* Should be called only for invalidated indexes */
Assert(relation->rd_rel->relkind == RELKIND_INDEX &&
!relation->rd_isvalid);
- /* Should be closed at smgr level */
- Assert(relation->rd_smgr == NULL);
+
+ /* Ensure it's closed at smgr level */
+ RelationCloseSmgr(relation);
/* Must free any AM cached data upon relcache flush */
if (relation->rd_amcache)
@@ -1892,12 +1894,11 @@ RelationClearRelation(Relation relation, bool rebuild)
* be unable to recover. However, we must redo RelationInitPhysicalAddr
* in case it is a mapped relation whose mapping changed.
*
- * If it's a nailed index, then we need to re-read the pg_class row to see
- * if its relfilenode changed. We can't necessarily do that here, because
- * we might be in a failed transaction. We assume it's okay to do it if
- * there are open references to the relcache entry (cf notes for
- * AtEOXact_RelationCache). Otherwise just mark the entry as possibly
- * invalid, and it'll be fixed when next opened.
+ * If it's a nailed-but-not-mapped index, then we need to re-read the
+ * pg_class row to see if its relfilenode changed. We do that immediately
+ * if we're inside a valid transaction and the relation is open (not
+ * counting the nailed refcount). Otherwise just mark the entry as
+ * possibly invalid, and it'll be fixed when next opened.
*/
if (relation->rd_isnailed)
{
@@ -1906,7 +1907,7 @@ RelationClearRelation(Relation relation, bool rebuild)
if (relation->rd_rel->relkind == RELKIND_INDEX)
{
relation->rd_isvalid = false; /* needs to be revalidated */
- if (relation->rd_refcnt > 1)
+ if (relation->rd_refcnt > 1 && IsTransactionState())
RelationReloadIndexInfo(relation);
}
return;
@@ -1924,7 +1925,8 @@ RelationClearRelation(Relation relation, bool rebuild)
relation->rd_indexcxt != NULL)
{
relation->rd_isvalid = false; /* needs to be revalidated */
- RelationReloadIndexInfo(relation);
+ if (IsTransactionState())
+ RelationReloadIndexInfo(relation);
return;
}
@@ -1945,6 +1947,29 @@ RelationClearRelation(Relation relation, bool rebuild)
/* And release storage */
RelationDestroyRelation(relation);
}
+ else if (!IsTransactionState())
+ {
+ /*
+ * If we're not inside a valid transaction, we can't do any catalog
+ * access so it's not possible to rebuild yet. Just exit, leaving
+ * rd_isvalid = false so that the rebuild will occur when the entry is
+ * next opened.
+ *
+ * Note: it's possible that we come here during subtransaction abort,
+ * and the reason for wanting to rebuild is that the rel is open in
+ * the outer transaction. In that case it might seem unsafe to not
+ * rebuild immediately, since whatever code has the rel already open
+ * will keep on using the relcache entry as-is. However, in such a
+ * case the outer transaction should be holding a lock that's
+ * sufficient to prevent any significant change in the rel's schema,
+ * so the existing entry contents should be good enough for its
+ * purposes; at worst we might be behind on statistics updates or the
+ * like. (See also CheckTableNotInUse() and its callers.) These same
+ * remarks also apply to the cases above where we exit without having
+ * done RelationReloadIndexInfo() yet.
+ */
+ return;
+ }
else
{
/*
@@ -2057,6 +2082,7 @@ RelationClearRelation(Relation relation, bool rebuild)
* RelationFlushRelation
*
* Rebuild the relation if it is open (refcount > 0), else blow it away.
+ * This is used when we receive a cache invalidation event for the rel.
*/
static void
RelationFlushRelation(Relation relation)