@@ -250,6 +250,7 @@ static void RelationDestroyRelation(Relation relation, bool remember_tupdesc);
250250static void RelationClearRelation (Relation relation ,bool rebuild );
251251
252252static void RelationReloadIndexInfo (Relation relation );
253+ static void RelationReloadNailed (Relation relation );
253254static void RelationFlushRelation (Relation relation );
254255static void RememberToFreeTupleDescAtEOX (TupleDesc td );
255256static void AtEOXact_cleanup (Relation relation ,bool isCommit );
@@ -286,7 +287,7 @@ static void IndexSupportInitialize(oidvector *indclass,
286287static OpClassCacheEnt * LookupOpclassInfo (Oid operatorClassOid ,
287288StrategyNumber numSupport );
288289static void RelationCacheInitFileRemoveInDir (const char * tblspcpath );
289- static void unlink_initfile (const char * initfilename );
290+ static void unlink_initfile (const char * initfilename , int elevel );
290291static bool equalPartitionDescs (PartitionKey key ,PartitionDesc partdesc1 ,
291292PartitionDesc partdesc2 );
292293
@@ -1931,7 +1932,16 @@ RelationIdGetRelation(Oid relationId)
19311932RelationReloadIndexInfo (rd );
19321933else
19331934RelationClearRelation (rd , true);
1934- Assert (rd -> rd_isvalid );
1935+
1936+ /*
1937+ * Normally entries need to be valid here, but before the relcache
1938+ * has been initialized, not enough infrastructure exists to
1939+ * perform pg_class lookups. The structure of such entries doesn't
1940+ * change, but we still want to update the rd_rel entry. So
1941+ * rd_isvalid = false is left in place for a later lookup.
1942+ */
1943+ Assert (rd -> rd_isvalid ||
1944+ (rd -> rd_isnailed && !criticalRelcachesBuilt ));
19351945}
19361946return rd ;
19371947}
@@ -2135,6 +2145,81 @@ RelationReloadIndexInfo(Relation relation)
21352145relation -> rd_isvalid = true;
21362146}
21372147
2148+ /*
2149+ * RelationReloadNailed - reload minimal information for nailed relations.
2150+ *
2151+ * The structure of a nailed relation can never change (which is good, because
2152+ * we rely on knowing their structure to be able to read catalog content). But
2153+ * some parts, e.g. pg_class.relfrozenxid, are still important to have
2154+ * accurate content for. Therefore those need to be reloaded after the arrival
2155+ * of invalidations.
2156+ */
2157+ static void
2158+ RelationReloadNailed (Relation relation )
2159+ {
2160+ Assert (relation -> rd_isnailed );
2161+
2162+ /*
2163+ * Redo RelationInitPhysicalAddr in case it is a mapped relation whose
2164+ * mapping changed.
2165+ */
2166+ RelationInitPhysicalAddr (relation );
2167+
2168+ /* flag as needing to be revalidated */
2169+ relation -> rd_isvalid = false;
2170+
2171+ /*
2172+ * Can only reread catalog contents if in a transaction. If the relation
2173+ * is currently open (not counting the nailed refcount), do so
2174+ * immediately. Otherwise we've already marked the entry as possibly
2175+ * invalid, and it'll be fixed when next opened.
2176+ */
2177+ if (!IsTransactionState ()|| relation -> rd_refcnt <=1 )
2178+ return ;
2179+
2180+ if (relation -> rd_rel -> relkind == RELKIND_INDEX )
2181+ {
2182+ /*
2183+ * If it's a nailed-but-not-mapped index, then we need to re-read the
2184+ * pg_class row to see if its relfilenode changed.
2185+ */
2186+ RelationReloadIndexInfo (relation );
2187+ }
2188+ else
2189+ {
2190+ /*
2191+ * Reload a non-index entry. We can't easily do so if relcaches
2192+ * aren't yet built, but that's fine because at that stage the
2193+ * attributes that need to be current (like relfrozenxid) aren't yet
2194+ * accessed. To ensure the entry will later be revalidated, we leave
2195+ * it in invalid state, but allow use (cf. RelationIdGetRelation()).
2196+ */
2197+ if (criticalRelcachesBuilt )
2198+ {
2199+ HeapTuple pg_class_tuple ;
2200+ Form_pg_class relp ;
2201+
2202+ /*
2203+ * NB: Mark the entry as valid before starting to scan, to avoid
2204+ * self-recursion when re-building pg_class.
2205+ */
2206+ relation -> rd_isvalid = true;
2207+
2208+ pg_class_tuple = ScanPgRelation (RelationGetRelid (relation ),
2209+ true, false);
2210+ relp = (Form_pg_class )GETSTRUCT (pg_class_tuple );
2211+ memcpy (relation -> rd_rel ,relp ,CLASS_TUPLE_SIZE );
2212+ heap_freetuple (pg_class_tuple );
2213+
2214+ /*
2215+ * Again mark as valid, to protect against concurrently arriving
2216+ * invalidations.
2217+ */
2218+ relation -> rd_isvalid = true;
2219+ }
2220+ }
2221+ }
2222+
21382223/*
21392224 * RelationDestroyRelation
21402225 *
@@ -2250,27 +2335,12 @@ RelationClearRelation(Relation relation, bool rebuild)
22502335RelationCloseSmgr (relation );
22512336
22522337/*
2253- * Never, never ever blow away a nailed-in system relation, because we'd
2254- * be unable to recover. However, we must redo RelationInitPhysicalAddr
2255- * in case it is a mapped relation whose mapping changed.
2256- *
2257- * If it's a nailed-but-not-mapped index, then we need to re-read the
2258- * pg_class row to see if its relfilenode changed. We do that immediately
2259- * if we're inside a valid transaction and the relation is open (not
2260- * counting the nailed refcount). Otherwise just mark the entry as
2261- * possibly invalid, and it'll be fixed when next opened.
2338+ * Treat nailed-in system relations separately, they always need to be
2339+ * accessible, so we can't blow them away.
22622340 */
22632341if (relation -> rd_isnailed )
22642342{
2265- RelationInitPhysicalAddr (relation );
2266-
2267- if (relation -> rd_rel -> relkind == RELKIND_INDEX ||
2268- relation -> rd_rel -> relkind == RELKIND_PARTITIONED_INDEX )
2269- {
2270- relation -> rd_isvalid = false;/* needs to be revalidated */
2271- if (relation -> rd_refcnt > 1 && IsTransactionState ())
2272- RelationReloadIndexInfo (relation );
2273- }
2343+ RelationReloadNailed (relation );
22742344return ;
22752345}
22762346
@@ -5907,24 +5977,26 @@ write_item(const void *data, Size len, FILE *fp)
59075977
59085978/*
59095979 * Determine whether a given relation (identified by OID) is one of the ones
5910- * we should store inthe local relcache init file.
5980+ * we should store ina relcache init file.
59115981 *
59125982 * We must cache all nailed rels, and for efficiency we should cache every rel
59135983 * that supports a syscache. The former set is almost but not quite a subset
5914- * of the latter. Currently, we must special-case TriggerRelidNameIndexId,
5915- * which RelationCacheInitializePhase3 chooses to nail for efficiency reasons,
5916- * but which does not support any syscache.
5917- *
5918- * Note: this function is currently never called for shared rels. If it were,
5919- * we'd probably also need a special case for DatabaseNameIndexId, which is
5920- * critical but does not support a syscache.
5984+ * of the latter. The special cases are relations where
5985+ * RelationCacheInitializePhase2/3 chooses to nail for efficiency reasons, but
5986+ * which do not support any syscache.
59215987 */
59225988bool
59235989RelationIdIsInInitFile (Oid relationId )
59245990{
5925- if (relationId == TriggerRelidNameIndexId )
5991+ if (relationId == SharedSecLabelRelationId ||
5992+ relationId == TriggerRelidNameIndexId ||
5993+ relationId == DatabaseNameIndexId ||
5994+ relationId == SharedSecLabelObjectIndexId )
59265995{
5927- /* If this Assert fails, we don't need this special case anymore. */
5996+ /*
5997+ * If this Assert fails, we don't need the applicable special case
5998+ * anymore.
5999+ */
59286000Assert (!RelationSupportsSysCache (relationId ));
59296001return true;
59306002}
@@ -5994,38 +6066,30 @@ RelationHasUnloggedIndex(Relation rel)
59946066 * We take the lock and do the unlink in RelationCacheInitFilePreInvalidate,
59956067 * then release the lock in RelationCacheInitFilePostInvalidate. Caller must
59966068 * send any pending SI messages between those calls.
5997- *
5998- * Notice this deals only with the local init file, not the shared init file.
5999- * The reason is that there can never be a "significant" change to the
6000- * relcache entry of a shared relation; the most that could happen is
6001- * updates of noncritical fields such as relpages/reltuples. So, while
6002- * it's worth updating the shared init file from time to time, it can never
6003- * be invalid enough to make it necessary to remove it.
60046069 */
60056070void
60066071RelationCacheInitFilePreInvalidate (void )
60076072{
6008- char initfilename [MAXPGPATH ];
6073+ char localinitfname [MAXPGPATH ];
6074+ char sharedinitfname [MAXPGPATH ];
60096075
6010- snprintf (initfilename ,sizeof (initfilename ),"%s/%s" ,
6011- DatabasePath ,RELCACHE_INIT_FILENAME );
6076+ if (DatabasePath )
6077+ snprintf (localinitfname ,sizeof (localinitfname ),"%s/%s" ,
6078+ DatabasePath ,RELCACHE_INIT_FILENAME );
6079+ snprintf (sharedinitfname ,sizeof (sharedinitfname ),"global/%s" ,
6080+ RELCACHE_INIT_FILENAME );
60126081
60136082LWLockAcquire (RelCacheInitLock ,LW_EXCLUSIVE );
60146083
6015- if (unlink (initfilename )< 0 )
6016- {
6017- /*
6018- * The file might not be there if no backend has been started since
6019- * the last removal. But complain about failures other than ENOENT.
6020- * Fortunately, it's not too late to abort the transaction if we can't
6021- * get rid of the would-be-obsolete init file.
6022- */
6023- if (errno != ENOENT )
6024- ereport (ERROR ,
6025- (errcode_for_file_access (),
6026- errmsg ("could not remove cache file \"%s\": %m" ,
6027- initfilename )));
6028- }
6084+ /*
6085+ * The files might not be there if no backend has been started since the
6086+ * last removal. But complain about failures other than ENOENT with
6087+ * ERROR. Fortunately, it's not too late to abort the transaction if we
6088+ * can't get rid of the would-be-obsolete init file.
6089+ */
6090+ if (DatabasePath )
6091+ unlink_initfile (localinitfname ,ERROR );
6092+ unlink_initfile (sharedinitfname ,ERROR );
60296093}
60306094
60316095void
@@ -6051,13 +6115,9 @@ RelationCacheInitFileRemove(void)
60516115struct dirent * de ;
60526116char path [MAXPGPATH + 10 + sizeof (TABLESPACE_VERSION_DIRECTORY )];
60536117
6054- /*
6055- * We zap the shared cache file too. In theory it can't get out of sync
6056- * enough to be a problem, but in data-corruption cases, who knows ...
6057- */
60586118snprintf (path ,sizeof (path ),"global/%s" ,
60596119RELCACHE_INIT_FILENAME );
6060- unlink_initfile (path );
6120+ unlink_initfile (path , LOG );
60616121
60626122/* Scan everything in the default tablespace */
60636123RelationCacheInitFileRemoveInDir ("base" );
@@ -6097,20 +6157,23 @@ RelationCacheInitFileRemoveInDir(const char *tblspcpath)
60976157/* Try to remove the init file in each database */
60986158snprintf (initfilename ,sizeof (initfilename ),"%s/%s/%s" ,
60996159tblspcpath ,de -> d_name ,RELCACHE_INIT_FILENAME );
6100- unlink_initfile (initfilename );
6160+ unlink_initfile (initfilename , LOG );
61016161}
61026162}
61036163
61046164FreeDir (dir );
61056165}
61066166
61076167static void
6108- unlink_initfile (const char * initfilename )
6168+ unlink_initfile (const char * initfilename , int elevel )
61096169{
61106170if (unlink (initfilename )< 0 )
61116171{
61126172/* It might not be there, but log any error other than ENOENT */
61136173if (errno != ENOENT )
6114- elog (LOG ,"could not remove cache file \"%s\": %m" ,initfilename );
6174+ ereport (elevel ,
6175+ (errcode_for_file_access (),
6176+ errmsg ("could not remove cache file \"%s\": %m" ,
6177+ initfilename )));
61156178}
61166179}