Skip to content

Commit 45c6917

Browse files
committed
Fix the logic for putting relations into the relcache init file.
Commit f3b5565 was a couple of bricks shy of a load; specifically, it missed putting pg_trigger_tgrelid_tgname_index into the relcache init file, because that index is not used by any syscache. However, we have historically nailed that index into cache for performance reasons. The upshot was that load_relcache_init_file always decided that the init file was busted and silently ignored it, resulting in a significant hit to backend startup speed. To fix, reinstantiate RelationIdIsInInitFile() as a wrapper around RelationSupportsSysCache(), which can know about additional relations that should be in the init file despite being unknown to syscache.c. Also install some guards against future mistakes of this type: make write_relcache_init_file Assert that all nailed relations get written to the init file, and make load_relcache_init_file emit a WARNING if it takes the "wrong number of nailed relations" exit path. Now that we remove the init files during postmaster startup, that case should never occur in the field, even if we are starting a minor-version update that added or removed rels from the nailed set. So the warning shouldn't ever be seen by end users, but it will show up in the regression tests if somebody breaks this logic. Back-patch to all supported branches, like the previous commit.
1 parent 2c652c3 commit 45c6917

File tree

3 files changed

+53
-11
lines changed

3 files changed

+53
-11
lines changed

src/backend/utils/cache/inval.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -456,11 +456,8 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId)
456456
/*
457457
* If the relation being invalidated is one of those cached in the local
458458
* relcache init file, mark that we need to zap that file at commit.
459-
* (Note: perhaps it would be better if this code were a bit more
460-
* decoupled from the knowledge that the init file contains exactly those
461-
* non-shared rels used in catalog caches.)
462459
*/
463-
if (OidIsValid(dbId) && RelationSupportsSysCache(relId))
460+
if (OidIsValid(dbId) && RelationIdIsInInitFile(relId))
464461
transInvalInfo->RelcacheInitFileInval = true;
465462
}
466463

src/backend/utils/cache/relcache.c

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4219,21 +4219,32 @@ load_relcache_init_file(bool shared)
42194219
}
42204220

42214221
/*
4222-
* We reached the end of the init file without apparent problem. Did we
4223-
* get the right number of nailed items? (This is a useful crosscheck in
4224-
* case the set of critical rels or indexes changes.)
4222+
* We reached the end of the init file without apparent problem. Did we
4223+
* get the right number of nailed items? This is a useful crosscheck in
4224+
* case the set of critical rels or indexes changes. However, that should
4225+
* not happen in a normally-running system, so let's bleat if it does.
42254226
*/
42264227
if (shared)
42274228
{
42284229
if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
42294230
nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
4231+
{
4232+
elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
4233+
nailed_rels, nailed_indexes,
4234+
NUM_CRITICAL_SHARED_RELS, NUM_CRITICAL_SHARED_INDEXES);
42304235
goto read_failed;
4236+
}
42314237
}
42324238
else
42334239
{
42344240
if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
42354241
nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
4242+
{
4243+
elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
4244+
nailed_rels, nailed_indexes,
4245+
NUM_CRITICAL_LOCAL_RELS, NUM_CRITICAL_LOCAL_INDEXES);
42364246
goto read_failed;
4247+
}
42374248
}
42384249

42394250
/*
@@ -4351,12 +4362,19 @@ write_relcache_init_file(bool shared)
43514362
/*
43524363
* Ignore if not supposed to be in init file. We can allow any shared
43534364
* relation that's been loaded so far to be in the shared init file,
4354-
* but unshared relations must be used for catalog caches. (Note: if
4355-
* you want to change the criterion for rels to be kept in the init
4356-
* file, see also inval.c.)
4365+
* but unshared relations must be ones that should be in the local
4366+
* file per RelationIdIsInInitFile. (Note: if you want to change the
4367+
* criterion for rels to be kept in the init file, see also inval.c.
4368+
* The reason for filtering here is to be sure that we don't put
4369+
* anything into the local init file for which a relcache inval would
4370+
* not cause invalidation of that init file.)
43574371
*/
4358-
if (!shared && !RelationSupportsSysCache(RelationGetRelid(rel)))
4372+
if (!shared && !RelationIdIsInInitFile(RelationGetRelid(rel)))
4373+
{
4374+
/* Nailed rels had better get stored. */
4375+
Assert(!rel->rd_isnailed);
43594376
continue;
4377+
}
43604378

43614379
/* first write the relcache entry proper */
43624380
write_item(rel, sizeof(RelationData), fp);
@@ -4472,6 +4490,32 @@ write_item(const void *data, Size len, FILE *fp)
44724490
elog(FATAL, "could not write init file");
44734491
}
44744492

4493+
/*
4494+
* Determine whether a given relation (identified by OID) is one of the ones
4495+
* we should store in the local relcache init file.
4496+
*
4497+
* We must cache all nailed rels, and for efficiency we should cache every rel
4498+
* that supports a syscache. The former set is almost but not quite a subset
4499+
* of the latter. Currently, we must special-case TriggerRelidNameIndexId,
4500+
* which RelationCacheInitializePhase3 chooses to nail for efficiency reasons,
4501+
* but which does not support any syscache.
4502+
*
4503+
* Note: this function is currently never called for shared rels. If it were,
4504+
* we'd probably also need a special case for DatabaseNameIndexId, which is
4505+
* critical but does not support a syscache.
4506+
*/
4507+
bool
4508+
RelationIdIsInInitFile(Oid relationId)
4509+
{
4510+
if (relationId == TriggerRelidNameIndexId)
4511+
{
4512+
/* If this Assert fails, we don't need this special case anymore. */
4513+
Assert(!RelationSupportsSysCache(relationId));
4514+
return true;
4515+
}
4516+
return RelationSupportsSysCache(relationId);
4517+
}
4518+
44754519
/*
44764520
* Invalidate (remove) the init file during commit of a transaction that
44774521
* changed one or more of the relation cache entries that are kept in the

src/include/utils/relcache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ extern void AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
9595
/*
9696
* Routines to help manage rebuilding of relcache init files
9797
*/
98+
extern bool RelationIdIsInInitFile(Oid relationId);
9899
extern void RelationCacheInitFilePreInvalidate(void);
99100
extern void RelationCacheInitFilePostInvalidate(void);
100101
extern void RelationCacheInitFileRemove(void);

0 commit comments

Comments
 (0)