aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/cache/inval.c7
-rw-r--r--src/backend/utils/cache/relcache.c57
-rw-r--r--src/backend/utils/cache/syscache.c75
-rw-r--r--src/include/utils/relcache.h1
-rw-r--r--src/include/utils/syscache.h2
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