diff options
-rw-r--r-- | src/backend/utils/cache/inval.c | 7 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 57 | ||||
-rw-r--r-- | src/backend/utils/cache/syscache.c | 75 | ||||
-rw-r--r-- | src/include/utils/relcache.h | 1 | ||||
-rw-r--r-- | src/include/utils/syscache.h | 2 |
5 files changed, 95 insertions, 47 deletions
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 396cc0bea69..59851ef02c9 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -455,10 +455,13 @@ RegisterRelcacheInvalidation(Oid dbId, Oid relId) (void) GetCurrentCommandId(true); /* - * If the relation being invalidated is one of those cached in the + * If the relation being invalidated is one of those cached in the local * relcache init file, mark that we need to zap that file at commit. + * (Note: perhaps it would be better if this code were a bit more + * decoupled from the knowledge that the init file contains exactly those + * non-shared rels used in catalog caches.) */ - if (RelationIdIsInInitFile(relId)) + if (OidIsValid(dbId) && RelationSupportsSysCache(relId)) transInvalInfo->RelcacheInitFileInval = true; } diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 7aaa3fb802f..5d748914f90 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -131,14 +131,6 @@ bool criticalSharedRelcachesBuilt = false; static long relcacheInvalsReceived = 0L; /* - * This list remembers the OIDs of the non-shared relations cached in the - * database's local relcache init file. Note that there is no corresponding - * list for the shared relcache init file, for reasons explained in the - * comments for RelationCacheInitFileRemove. - */ -static List *initFileRelationIds = NIL; - -/* * This flag lets us optimize away work in AtEO(Sub)Xact_RelationCache(). */ static bool need_eoxact_work = false; @@ -3083,9 +3075,6 @@ RelationCacheInitializePhase3(void) */ InitCatalogCachePhase2(); - /* reset initFileRelationIds list; we'll fill it during write */ - initFileRelationIds = NIL; - /* now write the files */ write_relcache_init_file(true); write_relcache_init_file(false); @@ -4248,10 +4237,6 @@ load_relcache_init_file(bool shared) for (relno = 0; relno < num_rels; relno++) { RelationCacheInsert(rels[relno]); - /* also make a list of their OIDs, for RelationIdIsInInitFile */ - if (!shared) - initFileRelationIds = lcons_oid(RelationGetRelid(rels[relno]), - initFileRelationIds); } pfree(rels); @@ -4288,10 +4273,16 @@ write_relcache_init_file(bool shared) int magic; HASH_SEQ_STATUS status; RelIdCacheEnt *idhentry; - MemoryContext oldcxt; int i; /* + * If we have already received any relcache inval events, there's no + * chance of succeeding so we may as well skip the whole thing. + */ + if (relcacheInvalsReceived != 0L) + return; + + /* * We must write a temporary file and rename it into place. Otherwise, * another backend starting at about the same time might crash trying to * read the partially-complete file. @@ -4350,6 +4341,16 @@ write_relcache_init_file(bool shared) if (relform->relisshared != shared) continue; + /* + * Ignore if not supposed to be in init file. We can allow any shared + * relation that's been loaded so far to be in the shared init file, + * but unshared relations must be used for catalog caches. (Note: if + * you want to change the criterion for rels to be kept in the init + * file, see also inval.c.) + */ + if (!shared && !RelationSupportsSysCache(RelationGetRelid(rel))) + continue; + /* first write the relcache entry proper */ write_item(rel, sizeof(RelationData), fp); @@ -4406,15 +4407,6 @@ write_relcache_init_file(bool shared) relform->relnatts * sizeof(int16), fp); } - - /* also make a list of their OIDs, for RelationIdIsInInitFile */ - if (!shared) - { - oldcxt = MemoryContextSwitchTo(CacheMemoryContext); - initFileRelationIds = lcons_oid(RelationGetRelid(rel), - initFileRelationIds); - MemoryContextSwitchTo(oldcxt); - } } if (FreeFile(fp)) @@ -4474,21 +4466,6 @@ write_item(const void *data, Size len, FILE *fp) } /* - * Detect whether a given relation (identified by OID) is one of the ones - * we store in the local relcache init file. - * - * Note that we effectively assume that all backends running in a database - * would choose to store the same set of relations in the init file; - * otherwise there are cases where we'd fail to detect the need for an init - * file invalidation. This does not seem likely to be a problem in practice. - */ -bool -RelationIdIsInInitFile(Oid relationId) -{ - return list_member_oid(initFileRelationIds, relationId); -} - -/* * Invalidate (remove) the init file during commit of a transaction that * changed one or more of the relation cache entries that are kept in the * local init file. diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 55d852e95e4..f82d49af0ea 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -754,11 +754,18 @@ static const struct cachedesc cacheinfo[] = { } }; -static CatCache *SysCache[ - lengthof(cacheinfo)]; -static int SysCacheSize = lengthof(cacheinfo); +#define SysCacheSize ((int) lengthof(cacheinfo)) + +static CatCache *SysCache[SysCacheSize]; + static bool CacheInitialized = false; +/* Sorted array of OIDs of tables and indexes used by caches */ +static Oid SysCacheSupportingRelOid[SysCacheSize * 2]; +static int SysCacheSupportingRelOidSize; + +static int oid_compare(const void *a, const void *b); + /* * InitCatalogCache - initialize the caches @@ -772,10 +779,12 @@ void InitCatalogCache(void) { int cacheId; + int i, + j; Assert(!CacheInitialized); - MemSet(SysCache, 0, sizeof(SysCache)); + SysCacheSupportingRelOidSize = 0; for (cacheId = 0; cacheId < SysCacheSize; cacheId++) { @@ -788,7 +797,25 @@ InitCatalogCache(void) if (!PointerIsValid(SysCache[cacheId])) elog(ERROR, "could not initialize cache %u (%d)", cacheinfo[cacheId].reloid, cacheId); + /* Accumulate data for OID lists, too */ + SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] = + cacheinfo[cacheId].reloid; + SysCacheSupportingRelOid[SysCacheSupportingRelOidSize++] = + cacheinfo[cacheId].indoid; + } + + Assert(SysCacheSupportingRelOidSize <= lengthof(SysCacheSupportingRelOid)); + + /* Sort and de-dup OID arrays, so we can use binary search. */ + pg_qsort(SysCacheSupportingRelOid, SysCacheSupportingRelOidSize, + sizeof(Oid), oid_compare); + for (i = 1, j = 0; i < SysCacheSupportingRelOidSize; i++) + { + if (SysCacheSupportingRelOid[i] != SysCacheSupportingRelOid[j]) + SysCacheSupportingRelOid[++j] = SysCacheSupportingRelOid[i]; } + SysCacheSupportingRelOidSize = j + 1; + CacheInitialized = true; } @@ -1052,3 +1079,43 @@ SearchSysCacheList(int cacheId, int nkeys, return SearchCatCacheList(SysCache[cacheId], nkeys, key1, key2, key3, key4); } + +/* + * Test whether a relation supports a system cache, ie it is either a + * cached table or the index used for a cache. + */ +bool +RelationSupportsSysCache(Oid relid) +{ + int low = 0, + high = SysCacheSupportingRelOidSize - 1; + + while (low <= high) + { + int middle = low + (high - low) / 2; + + if (SysCacheSupportingRelOid[middle] == relid) + return true; + if (SysCacheSupportingRelOid[middle] < relid) + low = middle + 1; + else + high = middle - 1; + } + + return false; +} + + +/* + * OID comparator for pg_qsort + */ +static int +oid_compare(const void *a, const void *b) +{ + Oid oa = *((const Oid *) a); + Oid ob = *((const Oid *) b); + + if (oa == ob) + return 0; + return (oa > ob) ? 1 : -1; +} diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 9e2ea8ce060..e9bd87d5c53 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -96,7 +96,6 @@ extern void AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid, /* * Routines to help manage rebuilding of relcache init files */ -extern bool RelationIdIsInInitFile(Oid relationId); extern void RelationCacheInitFilePreInvalidate(void); extern void RelationCacheInitFilePostInvalidate(void); extern void RelationCacheInitFileRemove(void); diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 55d22303a7a..804c04c0967 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -116,6 +116,8 @@ extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup, extern struct catclist *SearchSysCacheList(int cacheId, int nkeys, Datum key1, Datum key2, Datum key3, Datum key4); +extern bool RelationSupportsSysCache(Oid relid); + /* * The use of the macros below rather than direct calls to the corresponding * functions is encouraged, as it insulates the caller from changes in the |