diff options
Diffstat (limited to 'src/backend/utils/cache')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 113 |
1 files changed, 86 insertions, 27 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index c4787042c08..24e4ec04022 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.207 2004/07/17 03:29:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.208 2004/08/28 20:31:44 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -72,7 +72,7 @@ */ #define RELCACHE_INIT_FILENAME "pg_internal.init" -#define RELCACHE_INIT_FILEMAGIC 0x573261 /* version ID value */ +#define RELCACHE_INIT_FILEMAGIC 0x573262 /* version ID value */ /* * hardcoded tuple descriptors. see include/catalog/pg_attribute.h @@ -835,8 +835,8 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, * flush the entry.) */ relation->rd_refcnt = 0; - relation->rd_isnailed = 0; - relation->rd_isnew = false; + relation->rd_isnailed = false; + relation->rd_createxact = InvalidTransactionId; relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace); /* @@ -886,6 +886,9 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, RelationCacheInsert(relation); MemoryContextSwitchTo(oldcxt); + /* It's fully valid */ + relation->rd_isvalid = true; + return relation; } @@ -1283,8 +1286,8 @@ formrdesc(const char *relationName, * all entries built with this routine are nailed-in-cache; none are * for new or temp relations. */ - relation->rd_isnailed = 1; - relation->rd_isnew = false; + relation->rd_isnailed = true; + relation->rd_createxact = InvalidTransactionId; relation->rd_istemp = false; /* @@ -1385,6 +1388,9 @@ formrdesc(const char *relationName, * add new reldesc to relcache */ RelationCacheInsert(relation); + + /* It's fully valid */ + relation->rd_isvalid = true; } @@ -1416,7 +1422,7 @@ RelationIdCacheGetRelation(Oid relationId) { RelationIncrementReferenceCount(rd); /* revalidate nailed index if necessary */ - if (rd->rd_isnailed == 2) + if (!rd->rd_isvalid) RelationReloadClassinfo(rd); } @@ -1445,7 +1451,7 @@ RelationSysNameCacheGetRelation(const char *relationName) { RelationIncrementReferenceCount(rd); /* revalidate nailed index if necessary */ - if (rd->rd_isnailed == 2) + if (!rd->rd_isvalid) RelationReloadClassinfo(rd); } @@ -1572,7 +1578,7 @@ RelationClose(Relation relation) #ifdef RELCACHE_FORCE_RELEASE if (RelationHasReferenceCountZero(relation) && - !relation->rd_isnew) + !TransactionIdIsValid(relation->rd_createxact)) RelationClearRelation(relation, false); #endif } @@ -1589,7 +1595,7 @@ RelationClose(Relation relation) * We can't necessarily reread the pg_class row right away; we might be * in a failed transaction when we receive the SI notification. If so, * RelationClearRelation just marks the entry as invalid by setting - * rd_isnailed to 2. This routine is called to fix the entry when it + * rd_isvalid to false. This routine is called to fix the entry when it * is next needed. */ static void @@ -1601,7 +1607,7 @@ RelationReloadClassinfo(Relation relation) Form_pg_class relp; /* Should be called only for invalidated nailed indexes */ - Assert(relation->rd_isnailed == 2 && + Assert(relation->rd_isnailed && !relation->rd_isvalid && relation->rd_rel->relkind == RELKIND_INDEX); /* Read the pg_class row */ buildinfo.infotype = INFO_RELID; @@ -1622,7 +1628,7 @@ RelationReloadClassinfo(Relation relation) heap_freetuple(pg_class_tuple); relation->rd_targblock = InvalidBlockNumber; /* Okay, now it's valid again */ - relation->rd_isnailed = 1; + relation->rd_isvalid = true; } /* @@ -1671,7 +1677,7 @@ RelationClearRelation(Relation relation, bool rebuild) relation->rd_targblock = InvalidBlockNumber; if (relation->rd_rel->relkind == RELKIND_INDEX) { - relation->rd_isnailed = 2; /* needs to be revalidated */ + relation->rd_isvalid = false; /* needs to be revalidated */ if (relation->rd_refcnt > 1) RelationReloadClassinfo(relation); } @@ -1729,15 +1735,15 @@ 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. + * and rd_createxact state. 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; + TransactionId old_createxact = relation->rd_createxact; TupleDesc old_att = relation->rd_att; RuleLock *old_rules = relation->rd_rules; MemoryContext old_rulescxt = relation->rd_rulescxt; @@ -1758,7 +1764,7 @@ RelationClearRelation(Relation relation, bool rebuild) buildinfo.i.info_id); } relation->rd_refcnt = old_refcnt; - relation->rd_isnew = old_isnew; + relation->rd_createxact = old_createxact; if (equalTupleDescs(old_att, relation->rd_att)) { /* needn't flush typcache here */ @@ -1795,7 +1801,7 @@ RelationFlushRelation(Relation relation) { bool rebuild; - if (relation->rd_isnew) + if (TransactionIdIsValid(relation->rd_createxact)) { /* * New relcache entries are always rebuilt, not flushed; else we'd @@ -1941,7 +1947,7 @@ RelationCacheInvalidate(void) } /* Ignore new relations, since they are never SI targets */ - if (relation->rd_isnew) + if (TransactionIdIsValid(relation->rd_createxact)) continue; relcacheInvalsReceived++; @@ -2018,18 +2024,18 @@ AtEOXact_RelationCache(bool isCommit) /* * Is it a relation created in the current transaction? * - * During commit, reset the flag to false, since we are now out of + * During commit, reset the flag to zero, since we are now out of * the creating transaction. During abort, simply delete the * relcache entry --- it isn't interesting any longer. (NOTE: if - * we have forgotten the isnew state of a new relation due to a + * we have forgotten the new-ness of a new relation due to a * forced cache flush, the entry will get deleted anyway by * shared-cache-inval processing of the aborted pg_class * insertion.) */ - if (relation->rd_isnew) + if (TransactionIdIsValid(relation->rd_createxact)) { if (isCommit) - relation->rd_isnew = false; + relation->rd_createxact = InvalidTransactionId; else { RelationClearRelation(relation, false); @@ -2084,6 +2090,56 @@ AtEOXact_RelationCache(bool isCommit) } /* + * AtEOSubXact_RelationCache + * + * Clean up the relcache at sub-transaction commit or abort. + * + * Note: this must be called *before* processing invalidation messages. + */ +void +AtEOSubXact_RelationCache(bool isCommit, TransactionId myXid, + TransactionId parentXid) +{ + HASH_SEQ_STATUS status; + RelIdCacheEnt *idhentry; + + hash_seq_init(&status, RelationIdCache); + + while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL) + { + Relation relation = idhentry->reldesc; + + /* + * Is it a relation created in the current subtransaction? + * + * During subcommit, mark it as belonging to the parent, instead. + * During subabort, simply delete the relcache entry. + */ + if (TransactionIdEquals(relation->rd_createxact, myXid)) + { + if (isCommit) + relation->rd_createxact = parentXid; + else + { + Assert(RelationHasReferenceCountZero(relation)); + RelationClearRelation(relation, false); + continue; + } + } + + /* + * Flush any temporary index list. + */ + if (relation->rd_indexvalid == 2) + { + list_free(relation->rd_indexlist); + relation->rd_indexlist = NIL; + relation->rd_indexvalid = 0; + } + } +} + +/* * RelationBuildLocalRelation * Build a relcache entry for an about-to-be-created relation, * and enter it into the relcache. @@ -2126,7 +2182,7 @@ RelationBuildLocalRelation(const char *relname, rel->rd_refcnt = nailit ? 1 : 0; /* it's being created in this transaction */ - rel->rd_isnew = true; + rel->rd_createxact = GetCurrentTransactionId(); /* is it a temporary relation? */ rel->rd_istemp = isTempNamespace(relnamespace); @@ -2137,7 +2193,7 @@ RelationBuildLocalRelation(const char *relname, * want it kicked out. e.g. pg_attribute!!! */ if (nailit) - rel->rd_isnailed = 1; + rel->rd_isnailed = true; /* * create a new tuple descriptor from the one passed in. We do this @@ -2205,6 +2261,9 @@ RelationBuildLocalRelation(const char *relname, */ MemoryContextSwitchTo(oldcxt); + /* It's fully valid */ + rel->rd_isvalid = true; + /* * Caller expects us to pin the returned entry. */ @@ -2326,7 +2385,7 @@ RelationCacheInitializePhase2(void) buildinfo.infotype = INFO_RELNAME; \ buildinfo.i.info_name = (indname); \ ird = RelationBuildDesc(buildinfo, NULL); \ - ird->rd_isnailed = 1; \ + ird->rd_isnailed = true; \ ird->rd_refcnt = 1; \ } while (0) @@ -2677,7 +2736,7 @@ RelationSetIndexList(Relation relation, List *indexIds) { MemoryContext oldcxt; - Assert(relation->rd_isnailed == 1); + Assert(relation->rd_isnailed); /* Copy the list into the cache context (could fail for lack of mem) */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); indexIds = list_copy(indexIds); |