diff options
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 196 |
1 files changed, 74 insertions, 122 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index f1ed253d711..f6c11206bd8 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.170 2002/08/04 18:12:15 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.171 2002/08/06 02:36:35 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,6 +39,7 @@ #include "catalog/catalog.h" #include "catalog/catname.h" #include "catalog/indexing.h" +#include "catalog/namespace.h" #include "catalog/pg_amop.h" #include "catalog/pg_amproc.h" #include "catalog/pg_attrdef.h" @@ -95,13 +96,6 @@ static HTAB *RelationSysNameCache; static HTAB *RelationNodeCache; /* - * newlyCreatedRelns - - * relations created during this transaction. We need to keep track of - * these. - */ -static List *newlyCreatedRelns = NIL; - -/* * This flag is false until we have prepared the critical relcache entries * that are needed to do indexscans on the tables read by relcache building. */ @@ -865,9 +859,12 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, RelationSetReferenceCount(relation, 1); /* - * normal relations are not nailed into the cache + * normal relations are not nailed into the cache; nor can a pre-existing + * relation be new or temp. */ relation->rd_isnailed = false; + relation->rd_isnew = false; + relation->rd_istemp = false; /* * initialize the tuple descriptor (relation->rd_att). @@ -957,9 +954,6 @@ RelationInitIndexAccessInfo(Relation relation) ReleaseSysCache(tuple); relation->rd_index = iform; - /* this field is now kinda redundant... */ - relation->rd_uniqueindex = iform->indisunique; - /* * Make a copy of the pg_am entry for the index's access method */ @@ -1359,9 +1353,12 @@ formrdesc(const char *relationName, RelationSetReferenceCount(relation, 1); /* - * all entries built with this routine are nailed-in-cache + * all entries built with this routine are nailed-in-cache; none are + * for new or temp relations. */ relation->rd_isnailed = true; + relation->rd_isnew = false; + relation->rd_istemp = false; /* * initialize relation tuple form @@ -1603,7 +1600,9 @@ RelationClose(Relation relation) RelationDecrementReferenceCount(relation); #ifdef RELCACHE_FORCE_RELEASE - if (RelationHasReferenceCountZero(relation) && !relation->rd_myxactonly) + if (RelationHasReferenceCountZero(relation) && + !relation->rd_isnew && + !relation->rd_istemp) RelationClearRelation(relation, false); #endif } @@ -1734,13 +1733,14 @@ RelationClearRelation(Relation relation, bool rebuild) { /* * When rebuilding an open relcache entry, must preserve ref count - * and myxactonly flag. Also attempt to preserve the tupledesc, + * and new/temp flags. Also attempt to preserve the tupledesc, * rewrite rules, and trigger substructures in place. Furthermore - * we save/restore rd_nblocks (in case it is a local relation) + * we save/restore rd_nblocks (in case it is a new/temp relation) * *and* call RelationGetNumberOfBlocks (in case it isn't). */ int old_refcnt = relation->rd_refcnt; - bool old_myxactonly = relation->rd_myxactonly; + bool old_isnew = relation->rd_isnew; + bool old_istemp = relation->rd_istemp; TupleDesc old_att = relation->rd_att; RuleLock *old_rules = relation->rd_rules; MemoryContext old_rulescxt = relation->rd_rulescxt; @@ -1763,7 +1763,8 @@ RelationClearRelation(Relation relation, bool rebuild) buildinfo.i.info_id); } RelationSetReferenceCount(relation, old_refcnt); - relation->rd_myxactonly = old_myxactonly; + relation->rd_isnew = old_isnew; + relation->rd_istemp = old_istemp; if (equalTupleDescs(old_att, relation->rd_att)) { FreeTupleDesc(relation->rd_att); @@ -1810,11 +1811,11 @@ RelationFlushRelation(Relation relation) { bool rebuild; - if (relation->rd_myxactonly) + if (relation->rd_isnew || relation->rd_istemp) { /* - * Local rels should always be rebuilt, not flushed; the relcache - * entry must live until RelationPurgeLocalRelation(). + * New and temp relcache entries must always be rebuilt, not + * flushed; else we'd forget those two important status bits. */ rebuild = true; } @@ -1830,11 +1831,10 @@ RelationFlushRelation(Relation relation) } /* - * RelationForgetRelation - + * RelationForgetRelation - unconditionally remove a relcache entry * - * RelationClearRelation + if the relation is myxactonly then - * remove the relation descriptor from the newly created - * relation list. + * External interface for destroying a relcache entry when we + * drop the relation. */ void RelationForgetRelation(Oid rid) @@ -1849,31 +1849,6 @@ RelationForgetRelation(Oid rid) if (!RelationHasReferenceCountZero(relation)) elog(ERROR, "RelationForgetRelation: relation %u is still open", rid); - /* If local, remove from list */ - if (relation->rd_myxactonly) - { - List *curr; - List *prev = NIL; - - foreach(curr, newlyCreatedRelns) - { - Relation reln = lfirst(curr); - - Assert(reln != NULL && reln->rd_myxactonly); - if (RelationGetRelid(reln) == rid) - break; - prev = curr; - } - if (curr == NIL) - elog(ERROR, "Local relation %s not found in list", - RelationGetRelationName(relation)); - if (prev == NIL) - newlyCreatedRelns = lnext(newlyCreatedRelns); - else - lnext(prev) = lnext(curr); - pfree(curr); - } - /* Unconditionally destroy the relcache entry */ RelationClearRelation(relation, false); } @@ -1909,7 +1884,7 @@ RelationIdInvalidateRelationCacheByRelationId(Oid relationId) * and rebuild those with positive reference counts. * * This is currently used only to recover from SI message buffer overflow, - * so we do not touch transaction-local relations; they cannot be targets + * so we do not touch new-in-transaction relations; they cannot be targets * of cross-backend SI updates (and our own updates now go through a * separate linked list that isn't limited by the SI message buffer size). * @@ -1940,13 +1915,13 @@ RelationCacheInvalidate(void) { relation = idhentry->reldesc; - /* Ignore xact-local relations, since they are never SI targets */ - if (relation->rd_myxactonly) + /* Ignore new relations, since they are never SI targets */ + if (relation->rd_isnew) continue; relcacheInvalsReceived++; - if (RelationHasReferenceCountZero(relation)) + if (RelationHasReferenceCountZero(relation) && !relation->rd_istemp) { /* Delete this entry immediately */ RelationClearRelation(relation, false); @@ -1968,37 +1943,16 @@ RelationCacheInvalidate(void) } /* - * AtEOXactRelationCache + * AtEOXact_RelationCache * * Clean up the relcache at transaction commit or abort. - * - * During transaction abort, we must reset relcache entry ref counts - * to their normal not-in-a-transaction state. A ref count may be - * too high because some routine was exited by elog() between - * incrementing and decrementing the count. - * - * During commit, we should not have to do this, but it's useful to - * check that the counts are correct to catch missed relcache closes. - * Since that's basically a debugging thing, only pay the cost when - * assert checking is enabled. - * - * In bootstrap mode, forget the debugging checks --- the bootstrap code - * expects relations to stay open across start/commit transaction calls. */ void -AtEOXactRelationCache(bool commit) +AtEOXact_RelationCache(bool commit) { HASH_SEQ_STATUS status; RelIdCacheEnt *idhentry; -#ifdef USE_ASSERT_CHECKING - if (commit && IsBootstrapProcessingMode()) - return; -#else - if (commit) - return; -#endif - hash_seq_init(&status, RelationIdCache); while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL) @@ -2006,11 +1960,45 @@ AtEOXactRelationCache(bool commit) Relation relation = idhentry->reldesc; int expected_refcnt; + /* + * Is it a relation created in the current transaction? + * + * During commit, reset the flag to false, since we are now out of the + * creating transaction. During abort, simply delete the relcache + * entry --- it isn't interesting any longer. + */ + if (relation->rd_isnew) + { + if (commit) + relation->rd_isnew = false; + else + { + RelationClearRelation(relation, false); + continue; + } + } + + /* + * During transaction abort, we must also reset relcache entry ref + * counts to their normal not-in-a-transaction state. A ref count may + * be too high because some routine was exited by elog() between + * incrementing and decrementing the count. + * + * During commit, we should not have to do this, but it's still useful + * to check that the counts are correct to catch missed relcache + * closes. + * + * In bootstrap mode, do NOT reset the refcnt nor complain that it's + * nonzero --- the bootstrap code expects relations to stay open + * across start/commit transaction calls. (That seems bogus, but it's + * not worth fixing.) + */ expected_refcnt = relation->rd_isnailed ? 1 : 0; if (commit) { - if (relation->rd_refcnt != expected_refcnt) + if (relation->rd_refcnt != expected_refcnt && + !IsBootstrapProcessingMode()) { elog(WARNING, "Relcache reference leak: relation \"%s\" has refcnt %d instead of %d", RelationGetRelationName(relation), @@ -2055,10 +2043,11 @@ RelationBuildLocalRelation(const char *relname, oldcxt = MemoryContextSwitchTo(CacheMemoryContext); /* - * allocate a new relation descriptor. + * allocate a new relation descriptor and fill in basic state fields. */ rel = (Relation) palloc(sizeof(RelationData)); MemSet((char *) rel, 0, sizeof(RelationData)); + rel->rd_targblock = InvalidBlockNumber; /* make sure relation is marked as having no open file yet */ @@ -2066,6 +2055,12 @@ RelationBuildLocalRelation(const char *relname, RelationSetReferenceCount(rel, 1); + /* it's being created in this transaction */ + rel->rd_isnew = true; + + /* is it a temporary relation? */ + rel->rd_istemp = isTempNamespace(relnamespace); + /* * nail the reldesc if this is a bootstrap create reln and we may need * it in the cache later on in the bootstrap process so we don't ever @@ -2122,17 +2117,6 @@ RelationBuildLocalRelation(const char *relname, RelationCacheInsert(rel); /* - * we've just created the relation. It is invisible to anyone else - * before the transaction is committed. Setting rd_myxactonly allows - * us to use the local buffer manager for select/insert/etc before the - * end of transaction. (We also need to keep track of relations - * created during a transaction and do the necessary clean up at the - * end of the transaction.) - ay 3/95 - */ - rel->rd_myxactonly = true; - newlyCreatedRelns = lcons(rel, newlyCreatedRelns); - - /* * done building relcache entry. */ MemoryContextSwitchTo(oldcxt); @@ -2141,38 +2125,6 @@ RelationBuildLocalRelation(const char *relname, } /* - * RelationPurgeLocalRelation - - * find all the Relation descriptors marked rd_myxactonly and reset them. - * This should be called at the end of a transaction (commit/abort) when - * the "local" relations will become visible to others and the multi-user - * buffer pool should be used. - */ -void -RelationPurgeLocalRelation(bool xactCommitted) -{ - while (newlyCreatedRelns) - { - List *l = newlyCreatedRelns; - Relation reln = lfirst(l); - - newlyCreatedRelns = lnext(newlyCreatedRelns); - pfree(l); - - Assert(reln != NULL && reln->rd_myxactonly); - - reln->rd_myxactonly = false; /* mark it not on list anymore */ - - /* - * XXX while we clearly must throw out new Relation entries at - * xact abort, it's not clear why we need to do it at commit. - * Could this be improved? - */ - if (!IsBootstrapProcessingMode()) - RelationClearRelation(reln, false); - } -} - -/* * RelationCacheInitialize * * This initializes the relation descriptor cache. At the time |