77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.68 1999/09/02 02:57:50 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.69 1999/09/04 18:42:13 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
6161static void RelationFlushRelation (Relation * relationPtr ,
6262bool onlyFlushReferenceCountZero );
6363static Relation RelationNameCacheGetRelation (char * relationName );
64+ static void RelationCacheAbortWalker (Relation * relationPtr ,
65+ int dummy );
6466static void init_irels (void );
6567static void write_irels (void );
6668
@@ -213,14 +215,16 @@ static void RelationFlushIndexes(Relation *r, Oid accessMethodId);
213215static HeapTuple ScanPgRelation (RelationBuildDescInfo buildinfo );
214216static HeapTuple scan_pg_rel_seq (RelationBuildDescInfo buildinfo );
215217static HeapTuple scan_pg_rel_ind (RelationBuildDescInfo buildinfo );
216- static Relation AllocateRelationDesc (u_int natts ,Form_pg_class relp );
218+ static Relation AllocateRelationDesc (Relation relation ,u_int natts ,
219+ Form_pg_class relp );
217220static void RelationBuildTupleDesc (RelationBuildDescInfo buildinfo ,
218221Relation relation ,u_int natts );
219222static void build_tupdesc_seq (RelationBuildDescInfo buildinfo ,
220223Relation relation ,u_int natts );
221224static void build_tupdesc_ind (RelationBuildDescInfo buildinfo ,
222225Relation relation ,u_int natts );
223- static Relation RelationBuildDesc (RelationBuildDescInfo buildinfo );
226+ static Relation RelationBuildDesc (RelationBuildDescInfo buildinfo ,
227+ Relation oldrelation );
224228static void IndexedAccessMethodInitialize (Relation relation );
225229static void AttrDefaultFetch (Relation relation );
226230static void RelCheckFetch (Relation relation );
@@ -405,12 +409,16 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
405409 *
406410 *This is used to allocate memory for a new relation descriptor
407411 *and initialize the rd_rel field.
412+ *
413+ *If 'relation' is NULL, allocate a new RelationData object.
414+ *If not, reuse the given object (that path is taken only when
415+ *we have to rebuild a relcache entry during RelationFlushRelation).
408416 * ----------------
409417 */
410418static Relation
411- AllocateRelationDesc (u_int natts ,Form_pg_class relp )
419+ AllocateRelationDesc (Relation relation ,u_int natts ,
420+ Form_pg_class relp )
412421{
413- Relation relation ;
414422Size len ;
415423Form_pg_class relationForm ;
416424
@@ -424,18 +432,22 @@ AllocateRelationDesc(u_int natts, Form_pg_class relp)
424432memmove ((char * )relationForm , (char * )relp ,CLASS_TUPLE_SIZE );
425433
426434/* ----------------
427- *allocate space for new relation descriptor
435+ *allocate space for new relation descriptor, if needed
428436 */
429- len = sizeof (RelationData )+ 10 ; /* + 10 is voodoo XXX mao */
437+ len = sizeof (RelationData );
430438
431- relation = (Relation )palloc (len );
439+ if (relation == NULL )
440+ relation = (Relation )palloc (len );
432441
433442/* ----------------
434443 *clear new reldesc
435444 * ----------------
436445 */
437446MemSet ((char * )relation ,0 ,len );
438447
448+ /* make sure relation is marked as having no open file yet */
449+ relation -> rd_fd = -1 ;
450+
439451/* initialize attribute tuple form */
440452relation -> rd_att = CreateTemplateTupleDesc (natts );
441453
@@ -737,6 +749,11 @@ RelationBuildRuleLock(Relation relation)
737749/* --------------------------------
738750 *RelationBuildDesc
739751 *
752+ *Build a relation descriptor --- either a new one, or by
753+ *recycling the given old relation object. The latter case
754+ *supports rebuilding a relcache entry without invalidating
755+ *pointers to it.
756+ *
740757 *To build a relation descriptor, we have to allocate space,
741758 *open the underlying unix file and initialize the following
742759 *fields:
@@ -758,7 +775,8 @@ RelationBuildRuleLock(Relation relation)
758775 * --------------------------------
759776 */
760777static Relation
761- RelationBuildDesc (RelationBuildDescInfo buildinfo )
778+ RelationBuildDesc (RelationBuildDescInfo buildinfo ,
779+ Relation oldrelation )
762780{
763781File fd ;
764782Relation relation ;
@@ -803,7 +821,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo)
803821 *initialize relation->rd_rel and get the access method id.
804822 * ----------------
805823 */
806- relation = AllocateRelationDesc (natts ,relp );
824+ relation = AllocateRelationDesc (oldrelation , natts ,relp );
807825relam = relation -> rd_rel -> relam ;
808826
809827/* ----------------
@@ -833,9 +851,6 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo)
833851
834852/* ----------------
835853 *initialize the tuple descriptor (relation->rd_att).
836- *remember, rd_att is an array of attribute pointers that lives
837- *off the end of the relation descriptor structure so space was
838- *already allocated for it by AllocateRelationDesc.
839854 * ----------------
840855 */
841856RelationBuildTupleDesc (buildinfo ,relation ,natts );
@@ -1153,7 +1168,7 @@ RelationIdGetRelation(Oid relationId)
11531168buildinfo .infotype = INFO_RELID ;
11541169buildinfo .i .info_id = relationId ;
11551170
1156- rd = RelationBuildDesc (buildinfo );
1171+ rd = RelationBuildDesc (buildinfo , NULL );
11571172return rd ;
11581173}
11591174
@@ -1193,7 +1208,7 @@ RelationNameGetRelation(char *relationName)
11931208buildinfo .infotype = INFO_RELNAME ;
11941209buildinfo .i .info_name = relationName ;
11951210
1196- rd = RelationBuildDesc (buildinfo );
1211+ rd = RelationBuildDesc (buildinfo , NULL );
11971212return rd ;
11981213}
11991214
@@ -1236,58 +1251,82 @@ RelationClose(Relation relation)
12361251/* --------------------------------
12371252 * RelationFlushRelation
12381253 *
1239- * Actually blows away a relation... RelationFree doesn't do
1254+ * Actually blows away a relation cache entry ... RelationFree doesn't do
12401255 * anything anymore.
12411256 * --------------------------------
12421257 */
12431258static void
12441259RelationFlushRelation (Relation * relationPtr ,
12451260bool onlyFlushReferenceCountZero )
12461261{
1247- MemoryContext oldcxt ;
12481262Relation relation = * relationPtr ;
1263+ MemoryContext oldcxt ;
1264+
1265+ /*
1266+ * Make sure smgr and lower levels close the relation's files,
1267+ * if they weren't closed already. We do this unconditionally;
1268+ * if the relation is not deleted, the next smgr access should
1269+ * reopen the files automatically. This ensures that the low-level
1270+ * file access state is updated after, say, a vacuum truncation.
1271+ * NOTE: this call is a no-op if the relation's smgr file is already
1272+ * closed or unlinked.
1273+ */
1274+ smgrclose (DEFAULT_SMGR ,relation );
12491275
12501276if (relation -> rd_isnailed )
12511277{
1252- /* this is a nailed special relation forbootstraping */
1278+ /* this is a nailed special relation forbootstrapping */
12531279return ;
12541280}
12551281
1256- if (!onlyFlushReferenceCountZero ||
1257- RelationHasReferenceCountZero (relation ))
1258- {
1259- oldcxt = MemoryContextSwitchTo ((MemoryContext )CacheCxt );
1282+ oldcxt = MemoryContextSwitchTo ((MemoryContext )CacheCxt );
12601283
1261- /* make sure smgr and lower levels close the relation's files,
1262- * if they weren't closed already
1263- */
1264- smgrclose (DEFAULT_SMGR ,relation );
1284+ /* Remove relation from hash tables
1285+ *
1286+ * Note: we might be reinserting it momentarily, but we must not have it
1287+ * visible in the hash tables until it's valid again, so don't try to
1288+ * optimize this away...
1289+ */
1290+ RelationCacheDelete (relation );
1291+
1292+ /* Clear out catcache's entries for this relation */
1293+ SystemCacheRelationFlushed (RelationGetRelid (relation ));
12651294
1266- RelationCacheDelete (relation );
1295+ /* Free all the subsidiary data structures of the relcache entry */
1296+ FreeTupleDesc (relation -> rd_att );
1297+ FreeTriggerDesc (relation );
1298+ pfree (RelationGetLockInfo (relation ));
1299+ pfree (RelationGetForm (relation ));
12671300
1268- FreeTupleDesc (relation -> rd_att );
1269- SystemCacheRelationFlushed (RelationGetRelid (relation ));
1301+ /* If we're really done with the relcache entry, blow it away.
1302+ * But if someone is still using it, reconstruct the whole deal
1303+ * without moving the physical RelationData record (so that the
1304+ * someone's pointer is still valid). Preserve ref count, too.
1305+ */
1306+ if (!onlyFlushReferenceCountZero ||
1307+ RelationHasReferenceCountZero (relation ))
1308+ {
1309+ pfree (relation );
1310+ }
1311+ else
1312+ {
1313+ uint16 old_refcnt = relation -> rd_refcnt ;
1314+ RelationBuildDescInfo buildinfo ;
12701315
1271- FreeTriggerDesc (relation );
1316+ buildinfo .infotype = INFO_RELID ;
1317+ buildinfo .i .info_id = RelationGetRelid (relation );
12721318
1273- #ifdef NOT_USED
1274- if (relation -> rd_rules )
1319+ if (RelationBuildDesc (buildinfo ,relation )!= relation )
12751320{
1276- int j ;
1277-
1278- for (j = 0 ;j < relation -> rd_rules -> numLocks ;j ++ )
1279- pfree (relation -> rd_rules -> rules [j ]);
1280- pfree (relation -> rd_rules -> rules );
1281- pfree (relation -> rd_rules );
1321+ /* Should only get here if relation was deleted */
1322+ pfree (relation );
1323+ elog (ERROR ,"RelationFlushRelation: relation %u deleted while still in use" ,
1324+ buildinfo .i .info_id );
12821325}
1283- #endif
1284-
1285- pfree (RelationGetLockInfo (relation ));
1286- pfree (RelationGetForm (relation ));
1287- pfree (relation );
1288-
1289- MemoryContextSwitchTo (oldcxt );
1326+ RelationSetReferenceCount (relation ,old_refcnt );
12901327}
1328+
1329+ MemoryContextSwitchTo (oldcxt );
12911330}
12921331
12931332/* --------------------------------
@@ -1442,6 +1481,36 @@ RelationCacheInvalidate(bool onlyFlushReferenceCountZero)
14421481}
14431482}
14441483
1484+ /*
1485+ * RelationCacheAbort
1486+ *
1487+ *Clean up the relcache at transaction abort.
1488+ *
1489+ *What we need to do here is reset relcache entry ref counts to
1490+ *their normal not-in-a-transaction state. A ref count may be
1491+ *too high because some routine was exited by elog() between
1492+ *incrementing and decrementing the count.
1493+ *
1494+ *XXX Maybe we should do this at transaction commit, too, in case
1495+ *someone forgets to decrement a refcount in a non-error path?
1496+ */
1497+ void
1498+ RelationCacheAbort (void )
1499+ {
1500+ HashTableWalk (RelationNameCache , (HashtFunc )RelationCacheAbortWalker ,
1501+ 0 );
1502+ }
1503+
1504+ static void
1505+ RelationCacheAbortWalker (Relation * relationPtr ,int dummy )
1506+ {
1507+ Relation relation = * relationPtr ;
1508+
1509+ if (relation -> rd_isnailed )
1510+ RelationSetReferenceCount (relation ,1 );
1511+ else
1512+ RelationSetReferenceCount (relation ,0 );
1513+ }
14451514
14461515/* --------------------------------
14471516 *RelationRegisterRelation -
@@ -1523,7 +1592,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
15231592reln -> rd_myxactonly = FALSE;
15241593
15251594if (!IsBootstrapProcessingMode ())
1526- RelationFlushRelation (& reln ,FALSE );
1595+ RelationFlushRelation (& reln ,false );
15271596
15281597newlyCreatedRelns = lnext (newlyCreatedRelns );
15291598pfree (l );
@@ -2010,15 +2079,15 @@ write_irels(void)
20102079
20112080bi .infotype = INFO_RELNAME ;
20122081bi .i .info_name = AttributeNumIndex ;
2013- irel [0 ]= RelationBuildDesc (bi );
2082+ irel [0 ]= RelationBuildDesc (bi , NULL );
20142083irel [0 ]-> rd_isnailed = true;
20152084
20162085bi .i .info_name = ClassNameIndex ;
2017- irel [1 ]= RelationBuildDesc (bi );
2086+ irel [1 ]= RelationBuildDesc (bi , NULL );
20182087irel [1 ]-> rd_isnailed = true;
20192088
20202089bi .i .info_name = ClassOidIndex ;
2021- irel [2 ]= RelationBuildDesc (bi );
2090+ irel [2 ]= RelationBuildDesc (bi , NULL );
20222091irel [2 ]-> rd_isnailed = true;
20232092
20242093SetProcessingMode (oldmode );