diff options
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 171 |
1 files changed, 91 insertions, 80 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index afba41db108..fab04036d2e 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.73 1999/09/18 19:07:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.74 1999/10/03 23:55:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,7 @@ * RelationIdGetRelation - get a reldesc by relation id * RelationNameGetRelation - get a reldesc by relation name * RelationClose - close an open relation - * RelationFlushRelation - flush relation information + * RelationRebuildRelation - rebuild relation information * * NOTES * This file is in the process of being cleaned up @@ -59,8 +59,9 @@ #include "utils/temprel.h" +static void RelationClearRelation(Relation relation, bool rebuildIt); static void RelationFlushRelation(Relation *relationPtr, - bool onlyFlushReferenceCountZero); + bool onlyFlushReferenceCountZero); static Relation RelationNameCacheGetRelation(char *relationName); static void RelationCacheAbortWalker(Relation *relationPtr, int dummy); @@ -247,34 +248,6 @@ static List *newlyCreatedRelns = NULL; */ -#if NOT_USED /* XXX This doesn't seem to be used - * anywhere */ -/* -------------------------------- - * BuildDescInfoError returns a string appropriate to - * the buildinfo passed to it - * -------------------------------- - */ -static char * -BuildDescInfoError(RelationBuildDescInfo buildinfo) -{ - static char errBuf[64]; - - MemSet(errBuf, 0, (int) sizeof(errBuf)); - switch (buildinfo.infotype) - { - case INFO_RELID: - sprintf(errBuf, "(relation id %u)", buildinfo.i.info_id); - break; - case INFO_RELNAME: - sprintf(errBuf, "(relation name %s)", buildinfo.i.info_name); - break; - } - - return errBuf; -} - -#endif - /* -------------------------------- * ScanPgRelation * @@ -403,7 +376,7 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo) * * If 'relation' is NULL, allocate a new RelationData object. * If not, reuse the given object (that path is taken only when - * we have to rebuild a relcache entry during RelationFlushRelation). + * we have to rebuild a relcache entry during RelationClearRelation). * ---------------- */ static Relation @@ -578,11 +551,14 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo, if (attp->atthasdef) { if (attrdef == NULL) + { attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts * sizeof(AttrDefault)); + MemSet(attrdef, 0, + relation->rd_rel->relnatts * sizeof(AttrDefault)); + } attrdef[ndef].adnum = i; attrdef[ndef].adbin = NULL; - attrdef[ndef].adsrc = NULL; ndef++; } } @@ -1231,7 +1207,9 @@ RelationNameGetRelation(char *relationName) */ /* -------------------------------- - * RelationClose - close an open relation + * RelationClose - close an open relation + * + * Actually, we just decrement the refcount. * -------------------------------- */ void @@ -1242,17 +1220,18 @@ RelationClose(Relation relation) } /* -------------------------------- - * RelationFlushRelation + * RelationClearRelation * - * Actually blows away a relation cache entry... RelationFree doesn't do - * anything anymore. + * Physically blow away a relation cache entry, or reset it and rebuild + * it from scratch (that is, from catalog entries). The latter path is + * usually used when we are notified of a change to an open relation + * (one with refcount > 0). However, this routine just does whichever + * it's told to do; callers must determine which they want. * -------------------------------- */ static void -RelationFlushRelation(Relation *relationPtr, - bool onlyFlushReferenceCountZero) +RelationClearRelation(Relation relation, bool rebuildIt) { - Relation relation = *relationPtr; MemoryContext oldcxt; /* @@ -1261,19 +1240,18 @@ RelationFlushRelation(Relation *relationPtr, * if the relation is not deleted, the next smgr access should * reopen the files automatically. This ensures that the low-level * file access state is updated after, say, a vacuum truncation. + * * NOTE: this call is a no-op if the relation's smgr file is already * closed or unlinked. */ smgrclose(DEFAULT_SMGR, relation); - if (relation->rd_isnailed || relation->rd_myxactonly) - { - /* Do not flush relation cache entry if it is a nailed-in system - * relation or it is marked transaction-local. - * (To delete a local relation, caller must clear rd_myxactonly!) - */ + /* + * Never, never ever blow away a nailed-in system relation, + * because we'd be unable to recover. + */ + if (relation->rd_isnailed) return; - } oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); @@ -1293,19 +1271,21 @@ RelationFlushRelation(Relation *relationPtr, FreeTriggerDesc(relation); pfree(RelationGetForm(relation)); - /* If we're really done with the relcache entry, blow it away. + /* + * If we're really done with the relcache entry, blow it away. * But if someone is still using it, reconstruct the whole deal * without moving the physical RelationData record (so that the - * someone's pointer is still valid). Preserve ref count, too. + * someone's pointer is still valid). Must preserve ref count + * and myxactonly flag, too. */ - if (!onlyFlushReferenceCountZero || - RelationHasReferenceCountZero(relation)) + if (! rebuildIt) { pfree(relation); } else { uint16 old_refcnt = relation->rd_refcnt; + bool old_myxactonly = relation->rd_myxactonly; RelationBuildDescInfo buildinfo; buildinfo.infotype = INFO_RELID; @@ -1315,19 +1295,53 @@ RelationFlushRelation(Relation *relationPtr, { /* Should only get here if relation was deleted */ pfree(relation); - elog(ERROR, "RelationFlushRelation: relation %u deleted while still in use", + elog(ERROR, "RelationClearRelation: relation %u deleted while still in use", buildinfo.i.info_id); } RelationSetReferenceCount(relation, old_refcnt); + relation->rd_myxactonly = old_myxactonly; } MemoryContextSwitchTo(oldcxt); } /* -------------------------------- - * RelationForgetRelation - - * RelationFlushRelation + if the relation is myxactonly then - * get rid of the relation descriptor from the newly created + * RelationFlushRelation + * + * Rebuild the relation if it is open (refcount > 0), else blow it away. + * Setting onlyFlushReferenceCountZero to FALSE overrides refcount check. + * This is currently only used to process SI invalidation notifications. + * The peculiar calling convention (pointer to pointer to relation) + * is needed so that we can use this routine as a hash table walker. + * -------------------------------- + */ +static void +RelationFlushRelation(Relation *relationPtr, + bool onlyFlushReferenceCountZero) +{ + Relation relation = *relationPtr; + + /* + * Do nothing to transaction-local relations, since they cannot be + * subjects of SI notifications from other backends. + */ + if (relation->rd_myxactonly) + return; + + /* + * Zap it. Rebuild if it has nonzero ref count and we did not get + * the override flag. + */ + RelationClearRelation(relation, + (onlyFlushReferenceCountZero && + ! RelationHasReferenceCountZero(relation))); +} + +/* -------------------------------- + * RelationForgetRelation - + * + * RelationClearRelation + if the relation is myxactonly then + * remove the relation descriptor from the newly created * relation list. * -------------------------------- */ @@ -1368,13 +1382,25 @@ RelationForgetRelation(Oid rid) MemoryContextSwitchTo(oldcxt); } - relation->rd_myxactonly = false; /* so it can be flushed */ - - RelationFlushRelation(&relation, false); + /* Unconditionally destroy the relcache entry */ + RelationClearRelation(relation, false); } } /* -------------------------------- + * RelationRebuildRelation - + * + * Force a relcache entry to be rebuilt from catalog entries. + * This is needed, eg, after modifying an attribute of the rel. + * -------------------------------- + */ +void +RelationRebuildRelation(Relation relation) +{ + RelationClearRelation(relation, true); +} + +/* -------------------------------- * RelationIdInvalidateRelationCacheByRelationId * -------------------------------- */ @@ -1573,6 +1599,11 @@ RelationPurgeLocalRelation(bool xactCommitted) Assert(reln != NULL && reln->rd_myxactonly); + reln->rd_myxactonly = false; /* mark it not on list anymore */ + + newlyCreatedRelns = lnext(newlyCreatedRelns); + pfree(l); + if (!xactCommitted) { @@ -1592,13 +1623,8 @@ RelationPurgeLocalRelation(bool xactCommitted) smgrunlink(DEFAULT_SMGR, reln); } - reln->rd_myxactonly = false; /* so it can be flushed */ - if (!IsBootstrapProcessingMode()) - RelationFlushRelation(&reln, false); - - newlyCreatedRelns = lnext(newlyCreatedRelns); - pfree(l); + RelationClearRelation(reln, false); } MemoryContextSwitchTo(oldcxt); @@ -1717,7 +1743,7 @@ AttrDefaultFetch(Relation relation) { if (adform->adnum != attrdef[i].adnum) continue; - if (attrdef[i].adsrc != NULL) + if (attrdef[i].adbin != NULL) elog(ERROR, "AttrDefaultFetch: second record found for attr %s in rel %s", relation->rd_att->attrs[adform->adnum - 1]->attname.data, relation->rd_rel->relname.data); @@ -1730,14 +1756,6 @@ AttrDefaultFetch(Relation relation) relation->rd_att->attrs[adform->adnum - 1]->attname.data, relation->rd_rel->relname.data); attrdef[i].adbin = textout(val); - val = (struct varlena *) fastgetattr(&tuple, - Anum_pg_attrdef_adsrc, - adrel->rd_att, &isnull); - if (isnull) - elog(ERROR, "AttrDefaultFetch: adsrc IS NULL for attr %s in rel %s", - relation->rd_att->attrs[adform->adnum - 1]->attname.data, - relation->rd_rel->relname.data); - attrdef[i].adsrc = textout(val); break; } ReleaseBuffer(buffer); @@ -1816,13 +1834,6 @@ RelCheckFetch(Relation relation) elog(ERROR, "RelCheckFetch: rcbin IS NULL for rel %s", relation->rd_rel->relname.data); check[found].ccbin = textout(val); - val = (struct varlena *) fastgetattr(&tuple, - Anum_pg_relcheck_rcsrc, - rcrel->rd_att, &isnull); - if (isnull) - elog(ERROR, "RelCheckFetch: rcsrc IS NULL for rel %s", - relation->rd_rel->relname.data); - check[found].ccsrc = textout(val); found++; ReleaseBuffer(buffer); } |