summaryrefslogtreecommitdiff
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.c207
1 files changed, 56 insertions, 151 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 23428992724..c4787042c08 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.206 2004/07/01 00:51:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.207 2004/07/17 03:29:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -62,6 +62,7 @@
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/relcache.h"
+#include "utils/resowner.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
@@ -273,8 +274,6 @@ static void IndexSupportInitialize(Form_pg_index iform,
static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
StrategyNumber numStrats,
StrategyNumber numSupport);
-static inline void RelationPushReferenceCount(Relation rel);
-static inline void RelationPopReferenceCount(Relation rel);
/*
@@ -830,16 +829,12 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
RelationGetRelid(relation) = relid;
/*
- * initialize relation->rd_refcnt
- */
- RelationSetReferenceCount(relation, 1);
-
- /*
* normal relations are not nailed into the cache; nor can a
* pre-existing relation be new. It could be temp though. (Actually,
* it could be new too, but it's okay to forget that fact if forced to
* flush the entry.)
*/
+ relation->rd_refcnt = 0;
relation->rd_isnailed = 0;
relation->rd_isnew = false;
relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace);
@@ -1280,9 +1275,9 @@ formrdesc(const char *relationName,
relation->rd_smgr = NULL;
/*
- * initialize reference count
+ * initialize reference count: 1 because it is nailed in cache
*/
- RelationSetReferenceCount(relation, 1);
+ relation->rd_refcnt = 1;
/*
* all entries built with this routine are nailed-in-cache; none are
@@ -1487,6 +1482,8 @@ RelationIdGetRelation(Oid relationId)
buildinfo.i.info_id = relationId;
rd = RelationBuildDesc(buildinfo, NULL);
+ if (RelationIsValid(rd))
+ RelationIncrementReferenceCount(rd);
return rd;
}
@@ -1516,6 +1513,8 @@ RelationSysNameGetRelation(const char *relationName)
buildinfo.i.info_name = (char *) relationName;
rd = RelationBuildDesc(buildinfo, NULL);
+ if (RelationIsValid(rd))
+ RelationIncrementReferenceCount(rd);
return rd;
}
@@ -1525,6 +1524,36 @@ RelationSysNameGetRelation(const char *relationName)
*/
/*
+ * RelationIncrementReferenceCount
+ * Increments relation reference count.
+ *
+ * Note: bootstrap mode has its own weird ideas about relation refcount
+ * behavior; we ought to fix it someday, but for now, just disable
+ * reference count ownership tracking in bootstrap mode.
+ */
+void
+RelationIncrementReferenceCount(Relation rel)
+{
+ ResourceOwnerEnlargeRelationRefs(CurrentResourceOwner);
+ rel->rd_refcnt += 1;
+ if (!IsBootstrapProcessingMode())
+ ResourceOwnerRememberRelationRef(CurrentResourceOwner, rel);
+}
+
+/*
+ * RelationDecrementReferenceCount
+ * Decrements relation reference count.
+ */
+void
+RelationDecrementReferenceCount(Relation rel)
+{
+ Assert(rel->rd_refcnt > 0);
+ rel->rd_refcnt -= 1;
+ if (!IsBootstrapProcessingMode())
+ ResourceOwnerForgetRelationRef(CurrentResourceOwner, rel);
+}
+
+/*
* RelationClose - close an open relation
*
* Actually, we just decrement the refcount.
@@ -1680,8 +1709,6 @@ RelationClearRelation(Relation relation, bool rebuild)
list_free(relation->rd_indexlist);
if (relation->rd_indexcxt)
MemoryContextDelete(relation->rd_indexcxt);
- if (relation->rd_prevrefcnt)
- pfree(relation->rd_prevrefcnt);
/*
* If we're really done with the relcache entry, blow it away. But if
@@ -1704,6 +1731,10 @@ RelationClearRelation(Relation relation, bool rebuild)
* When rebuilding an open relcache entry, must preserve ref count
* and rd_isnew flag. Also attempt to preserve the tupledesc and
* rewrite-rule substructures in place.
+ *
+ * Note that this process does not touch CurrentResourceOwner;
+ * which is good because whatever ref counts the entry may have
+ * do not necessarily belong to that resource owner.
*/
int old_refcnt = relation->rd_refcnt;
bool old_isnew = relation->rd_isnew;
@@ -1726,7 +1757,7 @@ RelationClearRelation(Relation relation, bool rebuild)
elog(ERROR, "relation %u deleted while still in use",
buildinfo.i.info_id);
}
- RelationSetReferenceCount(relation, old_refcnt);
+ relation->rd_refcnt = old_refcnt;
relation->rd_isnew = old_isnew;
if (equalTupleDescs(old_att, relation->rd_att))
{
@@ -1964,7 +1995,7 @@ RelationCacheInvalidate(void)
/*
* AtEOXact_RelationCache
*
- * Clean up the relcache at transaction commit or abort.
+ * Clean up the relcache at main-transaction commit or abort.
*
* Note: this must be called *before* processing invalidation messages.
* In the case of abort, we don't want to try to rebuild any invalidated
@@ -2031,22 +2062,16 @@ AtEOXact_RelationCache(bool isCommit)
elog(WARNING, "relcache reference leak: relation \"%s\" has refcnt %d instead of %d",
RelationGetRelationName(relation),
relation->rd_refcnt, expected_refcnt);
- RelationSetReferenceCount(relation, expected_refcnt);
+ relation->rd_refcnt = expected_refcnt;
}
}
else
{
/* abort case, just reset it quietly */
- RelationSetReferenceCount(relation, expected_refcnt);
+ relation->rd_refcnt = expected_refcnt;
}
/*
- * Reset the refcount stack. Just drop the item count; don't deallocate
- * the stack itself so it can be reused by future subtransactions.
- */
- relation->rd_numpushed = 0;
-
- /*
* Flush any temporary index list.
*/
if (relation->rd_indexvalid == 2)
@@ -2059,131 +2084,6 @@ AtEOXact_RelationCache(bool isCommit)
}
/*
- * RelationPushReferenceCount
- *
- * Push the current reference count into the stack. Don't modify the
- * reference count itself.
- */
-static inline void
-RelationPushReferenceCount(Relation rel)
-{
- /* Enlarge the stack if we run out of space. */
- if (rel->rd_numpushed == rel->rd_numalloc)
- {
- MemoryContext old_cxt = MemoryContextSwitchTo(CacheMemoryContext);
-
- if (rel->rd_numalloc == 0)
- {
- rel->rd_numalloc = 8;
- rel->rd_prevrefcnt = palloc(rel->rd_numalloc * sizeof(int));
- }
- else
- {
- rel->rd_numalloc *= 2;
- rel->rd_prevrefcnt = repalloc(rel->rd_prevrefcnt, rel->rd_numalloc * sizeof(int));
- }
-
- MemoryContextSwitchTo(old_cxt);
- }
-
- rel->rd_prevrefcnt[rel->rd_numpushed++] = rel->rd_refcnt;
-}
-
-/*
- * RelationPopReferenceCount
- *
- * Pop the latest stored reference count. If there is none, drop it
- * to zero; the entry was created in the current subtransaction.
- */
-static inline void
-RelationPopReferenceCount(Relation rel)
-{
- if (rel->rd_numpushed == 0)
- {
- rel->rd_refcnt = rel->rd_isnailed ? 1 : 0;
- return;
- }
-
- rel->rd_refcnt = rel->rd_prevrefcnt[--rel->rd_numpushed];
-}
-
-/*
- * AtEOSubXact_RelationCache
- */
-void
-AtEOSubXact_RelationCache(bool isCommit)
-{
- HASH_SEQ_STATUS status;
- RelIdCacheEnt *idhentry;
-
- /* We'd better not be bootstrapping. */
- Assert(!IsBootstrapProcessingMode());
-
- hash_seq_init(&status, RelationIdCache);
-
- while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
- {
- Relation relation = idhentry->reldesc;
-
- /*
- * During subtransaction commit, we first check whether the
- * current refcount is correct: if there is no item in the stack,
- * the relcache entry was created during this subtransaction, it should
- * be 0 (or 1 for nailed relations). If the stack has at least one
- * item, the expected count is whatever that item is.
- */
- if (isCommit)
- {
- int expected_refcnt;
-
- if (relation->rd_numpushed == 0)
- expected_refcnt = relation->rd_isnailed ? 1 : 0;
- else
- expected_refcnt = relation->rd_prevrefcnt[relation->rd_numpushed - 1];
-
- if (relation->rd_refcnt != expected_refcnt)
- {
- elog(WARNING, "relcache reference leak: relation \"%s\" has refcnt %d instead of %d",
- RelationGetRelationName(relation),
- relation->rd_refcnt, expected_refcnt);
- }
- }
-
- /*
- * On commit, the expected count is stored so there's no harm in
- * popping it (and we may need to fix if there was a leak); and during
- * abort, the correct refcount has to be restored.
- */
- RelationPopReferenceCount(relation);
- }
-}
-
-/*
- * AtSubStart_RelationCache
- *
- * At subtransaction start, we push the current reference count into
- * the refcount stack, so it can be restored if the subtransaction aborts.
- */
-void
-AtSubStart_RelationCache(void)
-{
- HASH_SEQ_STATUS status;
- RelIdCacheEnt *idhentry;
-
- /* We'd better not be bootstrapping. */
- Assert(!IsBootstrapProcessingMode());
-
- hash_seq_init(&status, RelationIdCache);
-
- while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
- {
- Relation relation = idhentry->reldesc;
-
- RelationPushReferenceCount(relation);
- }
-}
-
-/*
* RelationBuildLocalRelation
* Build a relcache entry for an about-to-be-created relation,
* and enter it into the relcache.
@@ -2223,7 +2123,7 @@ RelationBuildLocalRelation(const char *relname,
/* make sure relation is marked as having no open file yet */
rel->rd_smgr = NULL;
- RelationSetReferenceCount(rel, 1);
+ rel->rd_refcnt = nailit ? 1 : 0;
/* it's being created in this transaction */
rel->rd_isnew = true;
@@ -2305,6 +2205,11 @@ RelationBuildLocalRelation(const char *relname,
*/
MemoryContextSwitchTo(oldcxt);
+ /*
+ * Caller expects us to pin the returned entry.
+ */
+ RelationIncrementReferenceCount(rel);
+
return rel;
}
@@ -2422,7 +2327,7 @@ RelationCacheInitializePhase2(void)
buildinfo.i.info_name = (indname); \
ird = RelationBuildDesc(buildinfo, NULL); \
ird->rd_isnailed = 1; \
- RelationSetReferenceCount(ird, 1); \
+ ird->rd_refcnt = 1; \
} while (0)
LOAD_CRIT_INDEX(ClassNameNspIndex);
@@ -3201,9 +3106,9 @@ load_relcache_init_file(void)
rel->rd_smgr = NULL;
rel->rd_targblock = InvalidBlockNumber;
if (rel->rd_isnailed)
- RelationSetReferenceCount(rel, 1);
+ rel->rd_refcnt = 1;
else
- RelationSetReferenceCount(rel, 0);
+ rel->rd_refcnt = 0;
rel->rd_indexvalid = 0;
rel->rd_indexlist = NIL;
MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));