7
7
*
8
8
*
9
9
* 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 $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
61
61
static void RelationFlushRelation (Relation * relationPtr ,
62
62
bool onlyFlushReferenceCountZero );
63
63
static Relation RelationNameCacheGetRelation (char * relationName );
64
+ static void RelationCacheAbortWalker (Relation * relationPtr ,
65
+ int dummy );
64
66
static void init_irels (void );
65
67
static void write_irels (void );
66
68
@@ -213,14 +215,16 @@ static void RelationFlushIndexes(Relation *r, Oid accessMethodId);
213
215
static HeapTuple ScanPgRelation (RelationBuildDescInfo buildinfo );
214
216
static HeapTuple scan_pg_rel_seq (RelationBuildDescInfo buildinfo );
215
217
static 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 );
217
220
static void RelationBuildTupleDesc (RelationBuildDescInfo buildinfo ,
218
221
Relation relation , u_int natts );
219
222
static void build_tupdesc_seq (RelationBuildDescInfo buildinfo ,
220
223
Relation relation , u_int natts );
221
224
static void build_tupdesc_ind (RelationBuildDescInfo buildinfo ,
222
225
Relation relation , u_int natts );
223
- static Relation RelationBuildDesc (RelationBuildDescInfo buildinfo );
226
+ static Relation RelationBuildDesc (RelationBuildDescInfo buildinfo ,
227
+ Relation oldrelation );
224
228
static void IndexedAccessMethodInitialize (Relation relation );
225
229
static void AttrDefaultFetch (Relation relation );
226
230
static void RelCheckFetch (Relation relation );
@@ -405,12 +409,16 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
405
409
*
406
410
* This is used to allocate memory for a new relation descriptor
407
411
* 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).
408
416
* ----------------
409
417
*/
410
418
static Relation
411
- AllocateRelationDesc (u_int natts , Form_pg_class relp )
419
+ AllocateRelationDesc (Relation relation , u_int natts ,
420
+ Form_pg_class relp )
412
421
{
413
- Relation relation ;
414
422
Size len ;
415
423
Form_pg_class relationForm ;
416
424
@@ -424,18 +432,22 @@ AllocateRelationDesc(u_int natts, Form_pg_class relp)
424
432
memmove ((char * ) relationForm , (char * ) relp , CLASS_TUPLE_SIZE );
425
433
426
434
/* ----------------
427
- * allocate space for new relation descriptor
435
+ * allocate space for new relation descriptor, if needed
428
436
*/
429
- len = sizeof (RelationData ) + 10 ; /* + 10 is voodoo XXX mao */
437
+ len = sizeof (RelationData );
430
438
431
- relation = (Relation ) palloc (len );
439
+ if (relation == NULL )
440
+ relation = (Relation ) palloc (len );
432
441
433
442
/* ----------------
434
443
* clear new reldesc
435
444
* ----------------
436
445
*/
437
446
MemSet ((char * ) relation , 0 , len );
438
447
448
+ /* make sure relation is marked as having no open file yet */
449
+ relation -> rd_fd = -1 ;
450
+
439
451
/* initialize attribute tuple form */
440
452
relation -> rd_att = CreateTemplateTupleDesc (natts );
441
453
@@ -737,6 +749,11 @@ RelationBuildRuleLock(Relation relation)
737
749
/* --------------------------------
738
750
* RelationBuildDesc
739
751
*
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
+ *
740
757
* To build a relation descriptor, we have to allocate space,
741
758
* open the underlying unix file and initialize the following
742
759
* fields:
@@ -758,7 +775,8 @@ RelationBuildRuleLock(Relation relation)
758
775
* --------------------------------
759
776
*/
760
777
static Relation
761
- RelationBuildDesc (RelationBuildDescInfo buildinfo )
778
+ RelationBuildDesc (RelationBuildDescInfo buildinfo ,
779
+ Relation oldrelation )
762
780
{
763
781
File fd ;
764
782
Relation relation ;
@@ -803,7 +821,7 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo)
803
821
* initialize relation->rd_rel and get the access method id.
804
822
* ----------------
805
823
*/
806
- relation = AllocateRelationDesc (natts , relp );
824
+ relation = AllocateRelationDesc (oldrelation , natts , relp );
807
825
relam = relation -> rd_rel -> relam ;
808
826
809
827
/* ----------------
@@ -833,9 +851,6 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo)
833
851
834
852
/* ----------------
835
853
* 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.
839
854
* ----------------
840
855
*/
841
856
RelationBuildTupleDesc (buildinfo , relation , natts );
@@ -1153,7 +1168,7 @@ RelationIdGetRelation(Oid relationId)
1153
1168
buildinfo .infotype = INFO_RELID ;
1154
1169
buildinfo .i .info_id = relationId ;
1155
1170
1156
- rd = RelationBuildDesc (buildinfo );
1171
+ rd = RelationBuildDesc (buildinfo , NULL );
1157
1172
return rd ;
1158
1173
}
1159
1174
@@ -1193,7 +1208,7 @@ RelationNameGetRelation(char *relationName)
1193
1208
buildinfo .infotype = INFO_RELNAME ;
1194
1209
buildinfo .i .info_name = relationName ;
1195
1210
1196
- rd = RelationBuildDesc (buildinfo );
1211
+ rd = RelationBuildDesc (buildinfo , NULL );
1197
1212
return rd ;
1198
1213
}
1199
1214
@@ -1236,58 +1251,82 @@ RelationClose(Relation relation)
1236
1251
/* --------------------------------
1237
1252
* RelationFlushRelation
1238
1253
*
1239
- * Actually blows away a relation... RelationFree doesn't do
1254
+ * Actually blows away a relation cache entry ... RelationFree doesn't do
1240
1255
* anything anymore.
1241
1256
* --------------------------------
1242
1257
*/
1243
1258
static void
1244
1259
RelationFlushRelation (Relation * relationPtr ,
1245
1260
bool onlyFlushReferenceCountZero )
1246
1261
{
1247
- MemoryContext oldcxt ;
1248
1262
Relation 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 );
1249
1275
1250
1276
if (relation -> rd_isnailed )
1251
1277
{
1252
- /* this is a nailed special relation for bootstraping */
1278
+ /* this is a nailed special relation for bootstrapping */
1253
1279
return ;
1254
1280
}
1255
1281
1256
- if (!onlyFlushReferenceCountZero ||
1257
- RelationHasReferenceCountZero (relation ))
1258
- {
1259
- oldcxt = MemoryContextSwitchTo ((MemoryContext ) CacheCxt );
1282
+ oldcxt = MemoryContextSwitchTo ((MemoryContext ) CacheCxt );
1260
1283
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 ));
1265
1294
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 ));
1267
1300
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 ;
1270
1315
1271
- FreeTriggerDesc (relation );
1316
+ buildinfo .infotype = INFO_RELID ;
1317
+ buildinfo .i .info_id = RelationGetRelid (relation );
1272
1318
1273
- #ifdef NOT_USED
1274
- if (relation -> rd_rules )
1319
+ if (RelationBuildDesc (buildinfo , relation ) != relation )
1275
1320
{
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 );
1282
1325
}
1283
- #endif
1284
-
1285
- pfree (RelationGetLockInfo (relation ));
1286
- pfree (RelationGetForm (relation ));
1287
- pfree (relation );
1288
-
1289
- MemoryContextSwitchTo (oldcxt );
1326
+ RelationSetReferenceCount (relation , old_refcnt );
1290
1327
}
1328
+
1329
+ MemoryContextSwitchTo (oldcxt );
1291
1330
}
1292
1331
1293
1332
/* --------------------------------
@@ -1442,6 +1481,36 @@ RelationCacheInvalidate(bool onlyFlushReferenceCountZero)
1442
1481
}
1443
1482
}
1444
1483
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
+ }
1445
1514
1446
1515
/* --------------------------------
1447
1516
* RelationRegisterRelation -
@@ -1523,7 +1592,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
1523
1592
reln -> rd_myxactonly = FALSE;
1524
1593
1525
1594
if (!IsBootstrapProcessingMode ())
1526
- RelationFlushRelation (& reln , FALSE );
1595
+ RelationFlushRelation (& reln , false );
1527
1596
1528
1597
newlyCreatedRelns = lnext (newlyCreatedRelns );
1529
1598
pfree (l );
@@ -2010,15 +2079,15 @@ write_irels(void)
2010
2079
2011
2080
bi .infotype = INFO_RELNAME ;
2012
2081
bi .i .info_name = AttributeNumIndex ;
2013
- irel [0 ] = RelationBuildDesc (bi );
2082
+ irel [0 ] = RelationBuildDesc (bi , NULL );
2014
2083
irel [0 ]-> rd_isnailed = true;
2015
2084
2016
2085
bi .i .info_name = ClassNameIndex ;
2017
- irel [1 ] = RelationBuildDesc (bi );
2086
+ irel [1 ] = RelationBuildDesc (bi , NULL );
2018
2087
irel [1 ]-> rd_isnailed = true;
2019
2088
2020
2089
bi .i .info_name = ClassOidIndex ;
2021
- irel [2 ] = RelationBuildDesc (bi );
2090
+ irel [2 ] = RelationBuildDesc (bi , NULL );
2022
2091
irel [2 ]-> rd_isnailed = true;
2023
2092
2024
2093
SetProcessingMode (oldmode );
0 commit comments