Attached is a patch that reorganizes CacheMemoryContext to be mostly a
parent context, with child contexts such as CatCacheContext,
RelCacheContext, PlanCacheContext, etc.

The goal is to better account for specific caches, which will hopefully
lead to optimizations or other improvements.

Regards,
        Jeff Davis

From 80febd60550d1710186a111d95659d0f80cece4e Mon Sep 17 00:00:00 2001
From: Jeff Davis <j...@j-davis.com>
Date: Tue, 29 Oct 2024 10:32:38 -0700
Subject: [PATCH v1] Reorganize cache memory contexts.

Create new memory contexts such as CatCacheContext, RelCacheContext,
etc. as children of CacheMemoryContext. Also, place other assorted
cache contexts, such as CollationCacheContext, under
CacheMemoryContext instead of TopMemoryContext.

This improves accounting, and may lead to optimizations for specific
caches.
---
 src/backend/catalog/namespace.c             |  5 +-
 src/backend/commands/policy.c               |  4 +-
 src/backend/commands/tablecmds.c            |  2 +-
 src/backend/commands/trigger.c              |  2 +-
 src/backend/executor/spi.c                  | 21 ++++-
 src/backend/foreign/foreign.c               |  4 +-
 src/backend/partitioning/partdesc.c         |  2 +-
 src/backend/replication/pgoutput/pgoutput.c | 14 ++-
 src/backend/utils/adt/pg_locale.c           |  6 +-
 src/backend/utils/cache/attoptcache.c       |  6 +-
 src/backend/utils/cache/catcache.c          | 36 +++++---
 src/backend/utils/cache/partcache.c         | 10 +--
 src/backend/utils/cache/plancache.c         | 36 +++++---
 src/backend/utils/cache/relcache.c          | 95 ++++++++++++---------
 src/backend/utils/cache/spccache.c          |  7 +-
 src/backend/utils/cache/ts_cache.c          | 47 ++++++----
 src/backend/utils/cache/typcache.c          | 62 ++++++++------
 src/include/utils/relcache.h                |  3 +
 18 files changed, 230 insertions(+), 132 deletions(-)

diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 30807f9190..f582325ac1 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -321,8 +321,11 @@ spcache_init(void)
 
 	if (SearchPathCacheContext == NULL)
 	{
+		if (!CacheMemoryContext)
+			CreateCacheMemoryContext();
+
 		/* Make the context we'll keep search path cache hashtable in */
-		SearchPathCacheContext = AllocSetContextCreate(TopMemoryContext,
+		SearchPathCacheContext = AllocSetContextCreate(CacheMemoryContext,
 													   "search_path processing cache",
 													   ALLOCSET_DEFAULT_SIZES);
 	}
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 6ff3eba824..f83dc4c153 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -313,10 +313,10 @@ RelationBuildRowSecurity(Relation relation)
 
 	/*
 	 * Success.  Reparent the descriptor's memory context under
-	 * CacheMemoryContext so that it will live indefinitely, then attach the
+	 * RelCacheContext so that it will live indefinitely, then attach the
 	 * policy descriptor to the relcache entry.
 	 */
-	MemoryContextSetParent(rscxt, CacheMemoryContext);
+	MemoryContextSetParent(rscxt, RelCacheContext);
 
 	relation->rd_rsdesc = rsdesc;
 }
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e14bc0c054..a45f6b73d6 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -17615,7 +17615,7 @@ register_on_commit_action(Oid relid, OnCommitAction action)
 	if (action == ONCOMMIT_NOOP || action == ONCOMMIT_PRESERVE_ROWS)
 		return;
 
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 
 	oc = (OnCommitItem *) palloc(sizeof(OnCommitItem));
 	oc->relid = relid;
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 09356e46d1..2ebbd38390 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -1994,7 +1994,7 @@ RelationBuildTriggers(Relation relation)
 		SetTriggerFlags(trigdesc, &(triggers[i]));
 
 	/* Copy completed trigdesc into cache storage */
-	oldContext = MemoryContextSwitchTo(CacheMemoryContext);
+	oldContext = MemoryContextSwitchTo(RelCacheContext);
 	relation->trigdesc = CopyTriggerDesc(trigdesc);
 	MemoryContextSwitchTo(oldContext);
 
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 2fb2e73604..f8e120f367 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -50,6 +50,8 @@ static _SPI_connection *_SPI_current = NULL;
 static int	_SPI_stack_depth = 0;	/* allocated size of _SPI_stack */
 static int	_SPI_connected = -1;	/* current stack index */
 
+static MemoryContext SPICacheContext = NULL;
+
 typedef struct SPICallbackArg
 {
 	const char *query;
@@ -972,6 +974,15 @@ SPI_prepare_params(const char *src,
 	return result;
 }
 
+static void
+CreateSPICacheContext(void)
+{
+	if (!SPICacheContext)
+		SPICacheContext = AllocSetContextCreate(CacheMemoryContext,
+												"SPICacheContext",
+												ALLOCSET_DEFAULT_SIZES);
+}
+
 int
 SPI_keepplan(SPIPlanPtr plan)
 {
@@ -981,13 +992,16 @@ SPI_keepplan(SPIPlanPtr plan)
 		plan->saved || plan->oneshot)
 		return SPI_ERROR_ARGUMENT;
 
+	if (!SPICacheContext)
+		CreateSPICacheContext();
+
 	/*
 	 * Mark it saved, reparent it under CacheMemoryContext, and mark all the
 	 * component CachedPlanSources as saved.  This sequence cannot fail
 	 * partway through, so there's no risk of long-term memory leakage.
 	 */
 	plan->saved = true;
-	MemoryContextSetParent(plan->plancxt, CacheMemoryContext);
+	MemoryContextSetParent(plan->plancxt, SPICacheContext);
 
 	foreach(lc, plan->plancache_list)
 	{
@@ -3255,13 +3269,16 @@ _SPI_save_plan(SPIPlanPtr plan)
 
 	MemoryContextSwitchTo(oldcxt);
 
+	if (!SPICacheContext)
+		CreateSPICacheContext();
+
 	/*
 	 * Mark it saved, reparent it under CacheMemoryContext, and mark all the
 	 * component CachedPlanSources as saved.  This sequence cannot fail
 	 * partway through, so there's no risk of long-term memory leakage.
 	 */
 	newplan->saved = true;
-	MemoryContextSetParent(newplan->plancxt, CacheMemoryContext);
+	MemoryContextSetParent(newplan->plancxt, SPICacheContext);
 
 	foreach(lc, newplan->plancache_list)
 	{
diff --git a/src/backend/foreign/foreign.c b/src/backend/foreign/foreign.c
index 4c06e1ff1c..dbc34dabd8 100644
--- a/src/backend/foreign/foreign.c
+++ b/src/backend/foreign/foreign.c
@@ -449,8 +449,8 @@ GetFdwRoutineForRelation(Relation relation, bool makecopy)
 		/* Get the info by consulting the catalogs and the FDW code */
 		fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(relation));
 
-		/* Save the data for later reuse in CacheMemoryContext */
-		cfdwroutine = (FdwRoutine *) MemoryContextAlloc(CacheMemoryContext,
+		/* Save the data for later reuse in RelCacheContext */
+		cfdwroutine = (FdwRoutine *) MemoryContextAlloc(RelCacheContext,
 														sizeof(FdwRoutine));
 		memcpy(cfdwroutine, fdwroutine, sizeof(FdwRoutine));
 		relation->rd_fdwroutine = cfdwroutine;
diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c
index b4e0ed0e71..e5830bd337 100644
--- a/src/backend/partitioning/partdesc.c
+++ b/src/backend/partitioning/partdesc.c
@@ -373,7 +373,7 @@ retry:
 	 * We have a fully valid partdesc.  Reparent it so that it has the right
 	 * lifespan.
 	 */
-	MemoryContextSetParent(new_pdcxt, CacheMemoryContext);
+	MemoryContextSetParent(new_pdcxt, RelCacheContext);
 
 	/*
 	 * Store it into relcache.
diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index 00e7024563..bb6f788e62 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -209,6 +209,8 @@ typedef struct PGOutputTxnData
 /* Map used to remember which relation schemas we sent. */
 static HTAB *RelationSyncCache = NULL;
 
+static MemoryContext PgOutputCacheContext = NULL;
+
 static void init_rel_sync_cache(MemoryContext cachectx);
 static void cleanup_rel_sync_cache(TransactionId xid, bool is_commit);
 static RelationSyncEntry *get_rel_sync_entry(PGOutputData *data,
@@ -435,6 +437,10 @@ pgoutput_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
 	/* This plugin uses binary protocol. */
 	opt->output_type = OUTPUT_PLUGIN_BINARY_OUTPUT;
 
+	PgOutputCacheContext = AllocSetContextCreate(CacheMemoryContext,
+												 "pgoutput cache context",
+												 ALLOCSET_DEFAULT_SIZES);
+
 	/*
 	 * This is replication start and not slot initialization.
 	 *
@@ -521,7 +527,7 @@ pgoutput_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
 		}
 
 		/* Initialize relation schema cache. */
-		init_rel_sync_cache(CacheMemoryContext);
+		init_rel_sync_cache(PgOutputCacheContext);
 	}
 	else
 	{
@@ -1159,7 +1165,7 @@ init_tuple_slot(PGOutputData *data, Relation relation,
 		TupleDesc	outdesc = RelationGetDescr(ancestor);
 
 		/* Map must live as long as the session does. */
-		oldctx = MemoryContextSwitchTo(CacheMemoryContext);
+		oldctx = MemoryContextSwitchTo(PgOutputCacheContext);
 
 		entry->attrmap = build_attrmap_by_name_if_req(indesc, outdesc, false);
 
@@ -1953,7 +1959,7 @@ set_schema_sent_in_streamed_txn(RelationSyncEntry *entry, TransactionId xid)
 {
 	MemoryContext oldctx;
 
-	oldctx = MemoryContextSwitchTo(CacheMemoryContext);
+	oldctx = MemoryContextSwitchTo(PgOutputCacheContext);
 
 	entry->streamed_txns = lappend_xid(entry->streamed_txns, xid);
 
@@ -2024,7 +2030,7 @@ get_rel_sync_entry(PGOutputData *data, Relation relation)
 		/* Reload publications if needed before use. */
 		if (!publications_valid)
 		{
-			oldctx = MemoryContextSwitchTo(CacheMemoryContext);
+			oldctx = MemoryContextSwitchTo(PgOutputCacheContext);
 			if (data->publications)
 			{
 				list_free_deep(data->publications);
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index d4e89663ec..3653d43c1d 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -62,6 +62,7 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "utils/builtins.h"
+#include "utils/catcache.h"
 #include "utils/formatting.h"
 #include "utils/guc_hooks.h"
 #include "utils/lsyscache.h"
@@ -1464,7 +1465,10 @@ pg_newlocale_from_collation(Oid collid)
 
 	if (CollationCache == NULL)
 	{
-		CollationCacheContext = AllocSetContextCreate(TopMemoryContext,
+		if (!CacheMemoryContext)
+			CreateCacheMemoryContext();
+
+		CollationCacheContext = AllocSetContextCreate(CacheMemoryContext,
 													  "collation cache",
 													  ALLOCSET_DEFAULT_SIZES);
 		CollationCache = collation_cache_create(CollationCacheContext,
diff --git a/src/backend/utils/cache/attoptcache.c b/src/backend/utils/cache/attoptcache.c
index 259865d5b3..01d9139174 100644
--- a/src/backend/utils/cache/attoptcache.c
+++ b/src/backend/utils/cache/attoptcache.c
@@ -114,8 +114,8 @@ InitializeAttoptCache(void)
 					HASH_ELEM | HASH_FUNCTION);
 
 	/* Make sure we've initialized CacheMemoryContext. */
-	if (!CacheMemoryContext)
-		CreateCacheMemoryContext();
+	if (!RelCacheContext)
+		CreateRelCacheContext();
 
 	/* Watch for invalidation events. */
 	CacheRegisterSyscacheCallback(ATTNUM,
@@ -178,7 +178,7 @@ get_attribute_options(Oid attrelid, int attnum)
 			{
 				bytea	   *bytea_opts = attribute_reloptions(datum, false);
 
-				opts = MemoryContextAlloc(CacheMemoryContext,
+				opts = MemoryContextAlloc(RelCacheContext,
 										  VARSIZE(bytea_opts));
 				memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
 			}
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index ee303dc501..9c7890ab03 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -62,6 +62,7 @@
 #endif
 
 /* Cache management header --- pointer is NULL until created */
+static MemoryContext CatCacheContext = NULL;
 static CatCacheHeader *CacheHdr = NULL;
 
 static inline HeapTuple SearchCatCacheInternal(CatCache *cache,
@@ -689,6 +690,17 @@ CreateCacheMemoryContext(void)
 												   ALLOCSET_DEFAULT_SIZES);
 }
 
+static void
+CreateCatCacheContext(void)
+{
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
+
+	if (!CatCacheContext)
+		CatCacheContext = AllocSetContextCreate(CacheMemoryContext,
+												"CatCacheContext",
+												ALLOCSET_DEFAULT_SIZES);
+}
 
 /*
  *		ResetCatalogCache
@@ -853,10 +865,10 @@ InitCatCache(int id,
 	 * first switch to the cache context so our allocations do not vanish at
 	 * the end of a transaction
 	 */
-	if (!CacheMemoryContext)
-		CreateCacheMemoryContext();
+	if (!CatCacheContext)
+		CreateCatCacheContext();
 
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(CatCacheContext);
 
 	/*
 	 * if first time through, initialize the cache group header
@@ -943,7 +955,7 @@ RehashCatCache(CatCache *cp)
 
 	/* Allocate a new, larger, hash table. */
 	newnbuckets = cp->cc_nbuckets * 2;
-	newbucket = (dlist_head *) MemoryContextAllocZero(CacheMemoryContext, newnbuckets * sizeof(dlist_head));
+	newbucket = (dlist_head *) MemoryContextAllocZero(CatCacheContext, newnbuckets * sizeof(dlist_head));
 
 	/* Move all entries from old hash table to new. */
 	for (i = 0; i < cp->cc_nbuckets; i++)
@@ -981,7 +993,7 @@ RehashCatCacheLists(CatCache *cp)
 
 	/* Allocate a new, larger, hash table. */
 	newnbuckets = cp->cc_nlbuckets * 2;
-	newbucket = (dlist_head *) MemoryContextAllocZero(CacheMemoryContext, newnbuckets * sizeof(dlist_head));
+	newbucket = (dlist_head *) MemoryContextAllocZero(CatCacheContext, newnbuckets * sizeof(dlist_head));
 
 	/* Move all entries from old hash table to new. */
 	for (i = 0; i < cp->cc_nlbuckets; i++)
@@ -1048,9 +1060,9 @@ CatalogCacheInitializeCache(CatCache *cache)
 	 * switch to the cache context so our allocations do not vanish at the end
 	 * of a transaction
 	 */
-	Assert(CacheMemoryContext != NULL);
+	Assert(CatCacheContext != NULL);
 
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(CatCacheContext);
 
 	/*
 	 * copy the relcache's tuple descriptor to permanent cache storage
@@ -1111,7 +1123,7 @@ CatalogCacheInitializeCache(CatCache *cache)
 		 */
 		fmgr_info_cxt(eqfunc,
 					  &cache->cc_skey[i].sk_func,
-					  CacheMemoryContext);
+					  CatCacheContext);
 
 		/* Initialize sk_attno suitably for HeapKeyTest() and heap scans */
 		cache->cc_skey[i].sk_attno = cache->cc_keyno[i];
@@ -1694,7 +1706,7 @@ SearchCatCacheList(CatCache *cache,
 		int			nbuckets = 16;
 
 		cache->cc_lbucket = (dlist_head *)
-			MemoryContextAllocZero(CacheMemoryContext,
+			MemoryContextAllocZero(CatCacheContext,
 								   nbuckets * sizeof(dlist_head));
 		/* Don't set cc_nlbuckets if we get OOM allocating cc_lbucket */
 		cache->cc_nlbuckets = nbuckets;
@@ -1896,7 +1908,7 @@ SearchCatCacheList(CatCache *cache,
 		ResourceOwnerEnlarge(CurrentResourceOwner);
 
 		/* Now we can build the CatCList entry. */
-		oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+		oldcxt = MemoryContextSwitchTo(CatCacheContext);
 		nmembers = list_length(ctlist);
 		cl = (CatCList *)
 			palloc(offsetof(CatCList, members) + nmembers * sizeof(CatCTup *));
@@ -2110,7 +2122,7 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, SysScanDesc scandesc,
 			dtp = ntp;
 
 		/* Allocate memory for CatCTup and the cached tuple in one go */
-		oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+		oldcxt = MemoryContextSwitchTo(CatCacheContext);
 
 		ct = (CatCTup *) palloc(sizeof(CatCTup) +
 								MAXIMUM_ALIGNOF + dtp->t_len);
@@ -2145,7 +2157,7 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, SysScanDesc scandesc,
 	else
 	{
 		/* Set up keys for a negative cache entry */
-		oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+		oldcxt = MemoryContextSwitchTo(CatCacheContext);
 		ct = (CatCTup *) palloc(sizeof(CatCTup));
 
 		/*
diff --git a/src/backend/utils/cache/partcache.c b/src/backend/utils/cache/partcache.c
index beec6cddbc..76b60c40f6 100644
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -65,11 +65,11 @@ RelationGetPartitionKey(Relation rel)
  *
  * Partitioning key data is a complex structure; to avoid complicated logic to
  * free individual elements whenever the relcache entry is flushed, we give it
- * its own memory context, a child of CacheMemoryContext, which can easily be
+ * its own memory context, a child of RelCacheContext, which can easily be
  * deleted on its own.  To avoid leaking memory in that context in case of an
  * error partway through this function, the context is initially created as a
- * child of CurTransactionContext and only re-parented to CacheMemoryContext
- * at the end, when no further errors are possible.  Also, we don't make this
+ * child of CurTransactionContext and only re-parented to RelCacheContext at
+ * the end, when no further errors are possible.  Also, we don't make this
  * context the current context except in very brief code sections, out of fear
  * that some of our callees allocate memory on their own which would be leaked
  * permanently.
@@ -263,7 +263,7 @@ RelationBuildPartitionKey(Relation relation)
 	 * Success --- reparent our context and make the relcache point to the
 	 * newly constructed key
 	 */
-	MemoryContextSetParent(partkeycxt, CacheMemoryContext);
+	MemoryContextSetParent(partkeycxt, RelCacheContext);
 	relation->rd_partkeycxt = partkeycxt;
 	relation->rd_partkey = key;
 }
@@ -411,7 +411,7 @@ generate_partition_qual(Relation rel)
 	 */
 	if (result != NIL)
 	{
-		rel->rd_partcheckcxt = AllocSetContextCreate(CacheMemoryContext,
+		rel->rd_partcheckcxt = AllocSetContextCreate(RelCacheContext,
 													 "partition constraint",
 													 ALLOCSET_SMALL_SIZES);
 		MemoryContextCopyAndSetIdentifier(rel->rd_partcheckcxt,
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 5af1a168ec..cebf4e9483 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -99,6 +99,8 @@ static dlist_head saved_plan_list = DLIST_STATIC_INIT(saved_plan_list);
  */
 static dlist_head cached_expression_list = DLIST_STATIC_INIT(cached_expression_list);
 
+static MemoryContext PlanCacheContext = NULL;
+
 static void ReleaseGenericPlan(CachedPlanSource *plansource);
 static List *RevalidateCachedQuery(CachedPlanSource *plansource,
 								   QueryEnvironment *queryEnv);
@@ -463,10 +465,19 @@ CompleteCachedPlan(CachedPlanSource *plansource,
 	plansource->is_valid = true;
 }
 
+static void
+CreatePlanCacheContext(void)
+{
+	if (!PlanCacheContext)
+		PlanCacheContext = AllocSetContextCreate(CacheMemoryContext,
+												 "PlanCacheContext",
+												 ALLOCSET_DEFAULT_SIZES);
+}
+
 /*
  * SaveCachedPlan: save a cached plan permanently
  *
- * This function moves the cached plan underneath CacheMemoryContext (making
+ * This function moves the cached plan underneath PlanCacheContext (making
  * it live for the life of the backend, unless explicitly dropped), and adds
  * it to the list of cached plans that are checked for invalidation when an
  * sinval event occurs.
@@ -493,18 +504,21 @@ SaveCachedPlan(CachedPlanSource *plansource)
 	/*
 	 * In typical use, this function would be called before generating any
 	 * plans from the CachedPlanSource.  If there is a generic plan, moving it
-	 * into CacheMemoryContext would be pretty risky since it's unclear
+	 * into PlanCacheContext would be pretty risky since it's unclear
 	 * whether the caller has taken suitable care with making references
 	 * long-lived.  Best thing to do seems to be to discard the plan.
 	 */
 	ReleaseGenericPlan(plansource);
 
+	if (!PlanCacheContext)
+		CreatePlanCacheContext();
+
 	/*
-	 * Reparent the source memory context under CacheMemoryContext so that it
+	 * Reparent the source memory context under PlanCacheContext so that it
 	 * will live indefinitely.  The query_context follows along since it's
 	 * already a child of the other one.
 	 */
-	MemoryContextSetParent(plansource->context, CacheMemoryContext);
+	MemoryContextSetParent(plansource->context, PlanCacheContext);
 
 	/*
 	 * Add the entry to the global list of cached plans.
@@ -1205,8 +1219,8 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
 			/* Immediately reparent into appropriate context */
 			if (plansource->is_saved)
 			{
-				/* saved plans all live under CacheMemoryContext */
-				MemoryContextSetParent(plan->context, CacheMemoryContext);
+				/* saved plans all live under PlanCacheContext */
+				MemoryContextSetParent(plan->context, PlanCacheContext);
 				plan->is_saved = true;
 			}
 			else
@@ -1262,14 +1276,14 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
 		ResourceOwnerRememberPlanCacheRef(owner, plan);
 
 	/*
-	 * Saved plans should be under CacheMemoryContext so they will not go away
+	 * Saved plans should be under PlanCacheContext so they will not go away
 	 * until their reference count goes to zero.  In the generic-plan cases we
 	 * already took care of that, but for a custom plan, do it as soon as we
 	 * have created a reference-counted link.
 	 */
 	if (customplan && plansource->is_saved)
 	{
-		MemoryContextSetParent(plan->context, CacheMemoryContext);
+		MemoryContextSetParent(plan->context, PlanCacheContext);
 		plan->is_saved = true;
 	}
 
@@ -1492,7 +1506,7 @@ CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan,
  * CachedPlanSetParentContext: move a CachedPlanSource to a new memory context
  *
  * This can only be applied to unsaved plans; once saved, a plan always
- * lives underneath CacheMemoryContext.
+ * lives underneath PlanCacheContext.
  */
 void
 CachedPlanSetParentContext(CachedPlanSource *plansource,
@@ -1713,10 +1727,10 @@ GetCachedExpression(Node *expr)
 	MemoryContextSwitchTo(oldcxt);
 
 	/*
-	 * Reparent the expr's memory context under CacheMemoryContext so that it
+	 * Reparent the expr's memory context under PlanCacheContext so that it
 	 * will live indefinitely.
 	 */
-	MemoryContextSetParent(cexpr_context, CacheMemoryContext);
+	MemoryContextSetParent(cexpr_context, PlanCacheContext);
 
 	/*
 	 * Add the entry to the global list of cached expressions.
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index c326f687eb..d2adf23d6f 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -145,6 +145,8 @@ bool		criticalRelcachesBuilt = false;
  */
 bool		criticalSharedRelcachesBuilt = false;
 
+MemoryContext RelCacheContext = NULL;
+
 /*
  * This counter counts relcache inval events received since backend startup
  * (but only for rels that are actually in cache).  Presently, we use it only
@@ -270,7 +272,6 @@ typedef struct opclasscacheent
 
 static HTAB *OpClassCache = NULL;
 
-
 /* non-export function prototypes */
 
 static void RelationCloseCleanup(Relation relation);
@@ -412,8 +413,8 @@ AllocateRelationDesc(Form_pg_class relp)
 	MemoryContext oldcxt;
 	Form_pg_class relationForm;
 
-	/* Relcache entries must live in CacheMemoryContext */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	/* Relcache entries must live in RelCacheContext */
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 
 	/*
 	 * allocate and zero space for new relation descriptor
@@ -497,14 +498,14 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
 	options = extractRelOptions(tuple, GetPgClassDescriptor(), amoptsfn);
 
 	/*
-	 * Copy parsed data into CacheMemoryContext.  To guard against the
+	 * Copy parsed data into RelCacheContext.  To guard against the
 	 * possibility of leaks in the reloptions code, we want to do the actual
 	 * parsing in the caller's memory context and copy the results into
-	 * CacheMemoryContext after the fact.
+	 * RelCacheContext after the fact.
 	 */
 	if (options)
 	{
-		relation->rd_options = MemoryContextAlloc(CacheMemoryContext,
+		relation->rd_options = MemoryContextAlloc(RelCacheContext,
 												  VARSIZE(options));
 		memcpy(relation->rd_options, options, VARSIZE(options));
 		pfree(options);
@@ -534,7 +535,7 @@ RelationBuildTupleDesc(Relation relation)
 		relation->rd_rel->reltype ? relation->rd_rel->reltype : RECORDOID;
 	relation->rd_att->tdtypmod = -1;	/* just to be sure */
 
-	constr = (TupleConstr *) MemoryContextAllocZero(CacheMemoryContext,
+	constr = (TupleConstr *) MemoryContextAllocZero(RelCacheContext,
 													sizeof(TupleConstr));
 
 	/*
@@ -613,7 +614,7 @@ RelationBuildTupleDesc(Relation relation)
 
 				if (attrmiss == NULL)
 					attrmiss = (AttrMissing *)
-						MemoryContextAllocZero(CacheMemoryContext,
+						MemoryContextAllocZero(RelCacheContext,
 											   relation->rd_rel->relnatts *
 											   sizeof(AttrMissing));
 
@@ -634,7 +635,7 @@ RelationBuildTupleDesc(Relation relation)
 				else
 				{
 					/* otherwise copy in the correct context */
-					oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+					oldcxt = MemoryContextSwitchTo(RelCacheContext);
 					attrmiss[attnum - 1].am_value = datumCopy(missval,
 															  attp->attbyval,
 															  attp->attlen);
@@ -745,7 +746,7 @@ RelationBuildRuleLock(Relation relation)
 	/*
 	 * Make the private context.  Assume it'll not contain much data.
 	 */
-	rulescxt = AllocSetContextCreate(CacheMemoryContext,
+	rulescxt = AllocSetContextCreate(RelCacheContext,
 									 "relation rules",
 									 ALLOCSET_SMALL_SIZES);
 	relation->rd_rulescxt = rulescxt;
@@ -1448,7 +1449,7 @@ RelationInitIndexAccessInfo(Relation relation)
 	if (!HeapTupleIsValid(tuple))
 		elog(ERROR, "cache lookup failed for index %u",
 			 RelationGetRelid(relation));
-	oldcontext = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcontext = MemoryContextSwitchTo(RelCacheContext);
 	relation->rd_indextuple = heap_copytuple(tuple);
 	relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
 	MemoryContextSwitchTo(oldcontext);
@@ -1477,7 +1478,7 @@ RelationInitIndexAccessInfo(Relation relation)
 	 * a context, and not just a couple of pallocs, is so that we won't leak
 	 * any subsidiary info attached to fmgr lookup records.
 	 */
-	indexcxt = AllocSetContextCreate(CacheMemoryContext,
+	indexcxt = AllocSetContextCreate(RelCacheContext,
 									 "index info",
 									 ALLOCSET_SMALL_SIZES);
 	relation->rd_indexcxt = indexcxt;
@@ -1622,6 +1623,18 @@ IndexSupportInitialize(oidvector *indclass,
 	}
 }
 
+void
+CreateRelCacheContext(void)
+{
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
+
+	if (!RelCacheContext)
+		RelCacheContext = AllocSetContextCreate(CacheMemoryContext,
+												"RelCacheContext",
+												ALLOCSET_DEFAULT_SIZES);
+}
+
 /*
  * LookupOpclassInfo
  *
@@ -1659,9 +1672,9 @@ LookupOpclassInfo(Oid operatorClassOid,
 		/* First time through: initialize the opclass cache */
 		HASHCTL		ctl;
 
-		/* Also make sure CacheMemoryContext exists */
-		if (!CacheMemoryContext)
-			CreateCacheMemoryContext();
+		/* Also make sure RelCacheContext exists */
+		if (!RelCacheContext)
+			CreateRelCacheContext();
 
 		ctl.keysize = sizeof(Oid);
 		ctl.entrysize = sizeof(OpClassCacheEnt);
@@ -1708,7 +1721,7 @@ LookupOpclassInfo(Oid operatorClassOid,
 	 */
 	if (opcentry->supportProcs == NULL && numSupport > 0)
 		opcentry->supportProcs = (RegProcedure *)
-			MemoryContextAllocZero(CacheMemoryContext,
+			MemoryContextAllocZero(RelCacheContext,
 								   numSupport * sizeof(RegProcedure));
 
 	/*
@@ -1867,7 +1880,7 @@ RelationInitTableAccessMethod(Relation relation)
  * during bootstrap or before RelationCacheInitializePhase3 runs, and none of
  * these properties matter then...)
  *
- * NOTE: we assume we are already switched into CacheMemoryContext.
+ * NOTE: we assume we are already switched into RelCacheContext.
  */
 static void
 formrdesc(const char *relationName, Oid relationReltype,
@@ -3116,7 +3129,7 @@ RememberToFreeTupleDescAtEOX(TupleDesc td)
 	{
 		MemoryContext oldcxt;
 
-		oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+		oldcxt = MemoryContextSwitchTo(RelCacheContext);
 
 		EOXactTupleDescArray = (TupleDesc *) palloc(16 * sizeof(TupleDesc));
 		EOXactTupleDescArrayLen = 16;
@@ -3580,10 +3593,10 @@ RelationBuildLocalRelation(const char *relname,
 	/*
 	 * switch to the cache context to create the relcache entry.
 	 */
-	if (!CacheMemoryContext)
-		CreateCacheMemoryContext();
+	if (!RelCacheContext)
+		CreateRelCacheContext();
 
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 
 	/*
 	 * allocate a new relation descriptor and fill in basic state fields.
@@ -3712,7 +3725,7 @@ RelationBuildLocalRelation(const char *relname,
 
 	/*
 	 * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
-	 * run it in CacheMemoryContext.  Fortunately, the remaining steps don't
+	 * run it in RelCacheContext.  Fortunately, the remaining steps don't
 	 * require a long-lived current context.
 	 */
 	MemoryContextSwitchTo(oldcxt);
@@ -4000,8 +4013,8 @@ RelationCacheInitialize(void)
 	/*
 	 * make sure cache memory context exists
 	 */
-	if (!CacheMemoryContext)
-		CreateCacheMemoryContext();
+	if (!RelCacheContext)
+		CreateRelCacheContext();
 
 	/*
 	 * create hashtable that indexes the relcache
@@ -4016,7 +4029,7 @@ RelationCacheInitialize(void)
 	 */
 	allocsize = 4;
 	in_progress_list =
-		MemoryContextAlloc(CacheMemoryContext,
+		MemoryContextAlloc(RelCacheContext,
 						   allocsize * sizeof(*in_progress_list));
 	in_progress_list_maxlen = allocsize;
 
@@ -4057,7 +4070,7 @@ RelationCacheInitializePhase2(void)
 	/*
 	 * switch to cache memory context
 	 */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 
 	/*
 	 * Try to load the shared relcache cache file.  If unsuccessful, bootstrap
@@ -4112,7 +4125,7 @@ RelationCacheInitializePhase3(void)
 	/*
 	 * switch to cache memory context
 	 */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 
 	/*
 	 * Try to load the local relcache cache file.  If unsuccessful, bootstrap
@@ -4426,7 +4439,7 @@ BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
 	MemoryContext oldcxt;
 	int			i;
 
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 
 	result = CreateTemplateTupleDesc(natts);
 	result->tdtypeid = RECORDOID;	/* not right, but we don't care */
@@ -4496,7 +4509,7 @@ AttrDefaultFetch(Relation relation, int ndef)
 
 	/* Allocate array with room for as many entries as expected */
 	attrdef = (AttrDefault *)
-		MemoryContextAllocZero(CacheMemoryContext,
+		MemoryContextAllocZero(RelCacheContext,
 							   ndef * sizeof(AttrDefault));
 
 	/* Search pg_attrdef for relevant entries */
@@ -4535,7 +4548,7 @@ AttrDefaultFetch(Relation relation, int ndef)
 			char	   *s = TextDatumGetCString(val);
 
 			attrdef[found].adnum = adform->adnum;
-			attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
+			attrdef[found].adbin = MemoryContextStrdup(RelCacheContext, s);
 			pfree(s);
 			found++;
 		}
@@ -4592,7 +4605,7 @@ CheckConstraintFetch(Relation relation)
 
 	/* Allocate array with room for as many entries as expected */
 	check = (ConstrCheck *)
-		MemoryContextAllocZero(CacheMemoryContext,
+		MemoryContextAllocZero(RelCacheContext,
 							   ncheck * sizeof(ConstrCheck));
 
 	/* Search pg_constraint for relevant entries */
@@ -4625,7 +4638,7 @@ CheckConstraintFetch(Relation relation)
 
 		check[found].ccvalid = conform->convalidated;
 		check[found].ccnoinherit = conform->connoinherit;
-		check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
+		check[found].ccname = MemoryContextStrdup(RelCacheContext,
 												  NameStr(conform->conname));
 
 		/* Grab and test conbin is actually set */
@@ -4640,7 +4653,7 @@ CheckConstraintFetch(Relation relation)
 			/* detoast and convert to cstring in caller's context */
 			char	   *s = TextDatumGetCString(val);
 
-			check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
+			check[found].ccbin = MemoryContextStrdup(RelCacheContext, s);
 			pfree(s);
 			found++;
 		}
@@ -4757,7 +4770,7 @@ RelationGetFKeyList(Relation relation)
 	table_close(conrel, AccessShareLock);
 
 	/* Now save a copy of the completed list in the relcache entry. */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 	oldlist = relation->rd_fkeylist;
 	relation->rd_fkeylist = copyObject(result);
 	relation->rd_fkeyvalid = true;
@@ -4880,7 +4893,7 @@ RelationGetIndexList(Relation relation)
 	list_sort(result, list_oid_cmp);
 
 	/* Now save a copy of the completed list in the relcache entry. */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 	oldlist = relation->rd_indexlist;
 	relation->rd_indexlist = list_copy(result);
 	relation->rd_pkindex = pkeyIndex;
@@ -4972,7 +4985,7 @@ RelationGetStatExtList(Relation relation)
 	list_sort(result, list_oid_cmp);
 
 	/* Now save a copy of the completed list in the relcache entry. */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 	oldlist = relation->rd_statlist;
 	relation->rd_statlist = list_copy(result);
 
@@ -5473,7 +5486,7 @@ restart:
 	 * leave the relcache entry looking like the other ones are valid but
 	 * empty.
 	 */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 	relation->rd_keyattr = bms_copy(uindexattrs);
 	relation->rd_pkattr = bms_copy(pkindexattrs);
 	relation->rd_idattr = bms_copy(idindexattrs);
@@ -5573,7 +5586,7 @@ RelationGetIdentityKeyBitmap(Relation relation)
 	relation->rd_idattr = NULL;
 
 	/* Now save copy of the bitmap in the relcache entry */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 	relation->rd_idattr = bms_copy(idindexattrs);
 	MemoryContextSwitchTo(oldcxt);
 
@@ -5870,7 +5883,7 @@ RelationBuildPublicationDesc(Relation relation, PublicationDesc *pubdesc)
 	}
 
 	/* Now save copy of the descriptor in the relcache entry. */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(RelCacheContext);
 	relation->rd_pubdesc = palloc(sizeof(PublicationDesc));
 	memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
 	MemoryContextSwitchTo(oldcxt);
@@ -6073,7 +6086,7 @@ errtableconstraint(Relation rel, const char *conname)
  * criticalSharedRelcachesBuilt to true.
  * If not successful, return false.
  *
- * NOTE: we assume we are already switched into CacheMemoryContext.
+ * NOTE: we assume we are already switched into RelCacheContext.
  */
 static bool
 load_relcache_init_file(bool shared)
@@ -6242,7 +6255,7 @@ load_relcache_init_file(bool shared)
 			 * prepare index info context --- parameters should match
 			 * RelationInitIndexAccessInfo
 			 */
-			indexcxt = AllocSetContextCreate(CacheMemoryContext,
+			indexcxt = AllocSetContextCreate(RelCacheContext,
 											 "index info",
 											 ALLOCSET_SMALL_SIZES);
 			rel->rd_indexcxt = indexcxt;
diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c
index ec63cdc8e5..2be8d4a792 100644
--- a/src/backend/utils/cache/spccache.c
+++ b/src/backend/utils/cache/spccache.c
@@ -86,9 +86,8 @@ InitializeTableSpaceCache(void)
 		hash_create("TableSpace cache", 16, &ctl,
 					HASH_ELEM | HASH_BLOBS);
 
-	/* Make sure we've initialized CacheMemoryContext. */
-	if (!CacheMemoryContext)
-		CreateCacheMemoryContext();
+	if (!RelCacheContext)
+		CreateRelCacheContext();
 
 	/* Watch for invalidation events. */
 	CacheRegisterSyscacheCallback(TABLESPACEOID,
@@ -151,7 +150,7 @@ get_tablespace(Oid spcid)
 		{
 			bytea	   *bytea_opts = tablespace_reloptions(datum, false);
 
-			opts = MemoryContextAlloc(CacheMemoryContext, VARSIZE(bytea_opts));
+			opts = MemoryContextAlloc(RelCacheContext, VARSIZE(bytea_opts));
 			memcpy(opts, bytea_opts, VARSIZE(bytea_opts));
 		}
 		ReleaseSysCache(tp);
diff --git a/src/backend/utils/cache/ts_cache.c b/src/backend/utils/cache/ts_cache.c
index 54de33eadd..4429bd9f2d 100644
--- a/src/backend/utils/cache/ts_cache.c
+++ b/src/backend/utils/cache/ts_cache.c
@@ -75,6 +75,7 @@ static TSConfigCacheEntry *lastUsedConfig = NULL;
  */
 char	   *TSCurrentConfig = NULL;
 
+static MemoryContext TextSearchCacheContext = NULL;
 static Oid	TSCurrentConfigCache = InvalidOid;
 
 
@@ -106,6 +107,18 @@ InvalidateTSCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
 		TSCurrentConfigCache = InvalidOid;
 }
 
+static void
+CreateTextSearchCacheContext(void)
+{
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
+
+	if (!TextSearchCacheContext)
+		TextSearchCacheContext = AllocSetContextCreate(CacheMemoryContext,
+													   "TextSearchCacheContext",
+													   ALLOCSET_DEFAULT_SIZES);
+}
+
 /*
  * Fetch parser cache entry
  */
@@ -127,9 +140,9 @@ lookup_ts_parser_cache(Oid prsId)
 		CacheRegisterSyscacheCallback(TSPARSEROID, InvalidateTSCacheCallBack,
 									  PointerGetDatum(TSParserCacheHash));
 
-		/* Also make sure CacheMemoryContext exists */
-		if (!CacheMemoryContext)
-			CreateCacheMemoryContext();
+		/* Also make sure TextSearchCacheContext exists */
+		if (!TextSearchCacheContext)
+			CreateTextSearchCacheContext();
 	}
 
 	/* Check single-entry cache */
@@ -186,12 +199,12 @@ lookup_ts_parser_cache(Oid prsId)
 
 		ReleaseSysCache(tp);
 
-		fmgr_info_cxt(entry->startOid, &entry->prsstart, CacheMemoryContext);
-		fmgr_info_cxt(entry->tokenOid, &entry->prstoken, CacheMemoryContext);
-		fmgr_info_cxt(entry->endOid, &entry->prsend, CacheMemoryContext);
+		fmgr_info_cxt(entry->startOid, &entry->prsstart, TextSearchCacheContext);
+		fmgr_info_cxt(entry->tokenOid, &entry->prstoken, TextSearchCacheContext);
+		fmgr_info_cxt(entry->endOid, &entry->prsend, TextSearchCacheContext);
 		if (OidIsValid(entry->headlineOid))
 			fmgr_info_cxt(entry->headlineOid, &entry->prsheadline,
-						  CacheMemoryContext);
+						  TextSearchCacheContext);
 
 		entry->isvalid = true;
 	}
@@ -224,9 +237,9 @@ lookup_ts_dictionary_cache(Oid dictId)
 		CacheRegisterSyscacheCallback(TSTEMPLATEOID, InvalidateTSCacheCallBack,
 									  PointerGetDatum(TSDictionaryCacheHash));
 
-		/* Also make sure CacheMemoryContext exists */
-		if (!CacheMemoryContext)
-			CreateCacheMemoryContext();
+		/* Also make sure TextSearchCacheContext exists */
+		if (!TextSearchCacheContext)
+			CreateTextSearchCacheContext();
 	}
 
 	/* Check single-entry cache */
@@ -291,7 +304,7 @@ lookup_ts_dictionary_cache(Oid dictId)
 			Assert(!found);		/* it wasn't there a moment ago */
 
 			/* Create private memory context the first time through */
-			saveCtx = AllocSetContextCreate(CacheMemoryContext,
+			saveCtx = AllocSetContextCreate(TextSearchCacheContext,
 											"TS dictionary",
 											ALLOCSET_SMALL_SIZES);
 			MemoryContextCopyAndSetIdentifier(saveCtx, NameStr(dict->dictname));
@@ -373,9 +386,9 @@ init_ts_config_cache(void)
 	CacheRegisterSyscacheCallback(TSCONFIGMAP, InvalidateTSCacheCallBack,
 								  PointerGetDatum(TSConfigCacheHash));
 
-	/* Also make sure CacheMemoryContext exists */
-	if (!CacheMemoryContext)
-		CreateCacheMemoryContext();
+	/* Also make sure TextSearchCacheContext exists */
+	if (!TextSearchCacheContext)
+		CreateTextSearchCacheContext();
 }
 
 /*
@@ -498,7 +511,7 @@ lookup_ts_config_cache(Oid cfgId)
 				{
 					maplists[maxtokentype].len = ndicts;
 					maplists[maxtokentype].dictIds = (Oid *)
-						MemoryContextAlloc(CacheMemoryContext,
+						MemoryContextAlloc(TextSearchCacheContext,
 										   sizeof(Oid) * ndicts);
 					memcpy(maplists[maxtokentype].dictIds, mapdicts,
 						   sizeof(Oid) * ndicts);
@@ -525,14 +538,14 @@ lookup_ts_config_cache(Oid cfgId)
 			/* save the last token type's dictionaries */
 			maplists[maxtokentype].len = ndicts;
 			maplists[maxtokentype].dictIds = (Oid *)
-				MemoryContextAlloc(CacheMemoryContext,
+				MemoryContextAlloc(TextSearchCacheContext,
 								   sizeof(Oid) * ndicts);
 			memcpy(maplists[maxtokentype].dictIds, mapdicts,
 				   sizeof(Oid) * ndicts);
 			/* and save the overall map */
 			entry->lenmap = maxtokentype + 1;
 			entry->map = (ListDictionary *)
-				MemoryContextAlloc(CacheMemoryContext,
+				MemoryContextAlloc(TextSearchCacheContext,
 								   sizeof(ListDictionary) * entry->lenmap);
 			memcpy(entry->map, maplists,
 				   sizeof(ListDictionary) * entry->lenmap);
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index 1972bd1944..c80a3e1f20 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -78,6 +78,8 @@
 /* The main type cache hashtable searched by lookup_type_cache */
 static HTAB *TypeCacheHash = NULL;
 
+static MemoryContext TypCacheContext = NULL;
+
 /*
  * The mapping of relation's OID to the corresponding composite type OID.
  * We're keeping the map entry when the corresponding typentry has something
@@ -362,6 +364,18 @@ type_cache_syshash(const void *key, Size keysize)
 	return GetSysCacheHashValue1(TYPEOID, ObjectIdGetDatum(*(const Oid *) key));
 }
 
+static void
+CreateTypCacheContext(void)
+{
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
+
+	if (!TypCacheContext)
+		TypCacheContext = AllocSetContextCreate(CacheMemoryContext,
+												"TypCacheContext",
+												ALLOCSET_DEFAULT_SIZES);
+}
+
 /*
  * lookup_type_cache
  *
@@ -421,16 +435,16 @@ lookup_type_cache(Oid type_id, int flags)
 		CacheRegisterSyscacheCallback(CLAOID, TypeCacheOpcCallback, (Datum) 0);
 		CacheRegisterSyscacheCallback(CONSTROID, TypeCacheConstrCallback, (Datum) 0);
 
-		/* Also make sure CacheMemoryContext exists */
-		if (!CacheMemoryContext)
-			CreateCacheMemoryContext();
+		/* Also make sure TypCacheContext exists */
+		if (!TypCacheContext)
+			CreateTypCacheContext();
 
 		/*
 		 * reserve enough in_progress_list slots for many cases
 		 */
 		allocsize = 4;
 		in_progress_list =
-			MemoryContextAlloc(CacheMemoryContext,
+			MemoryContextAlloc(TypCacheContext,
 							   allocsize * sizeof(*in_progress_list));
 		in_progress_list_maxlen = allocsize;
 	}
@@ -854,7 +868,7 @@ lookup_type_cache(Oid type_id, int flags)
 	/*
 	 * Set up fmgr lookup info as requested
 	 *
-	 * Note: we tell fmgr the finfo structures live in CacheMemoryContext,
+	 * Note: we tell fmgr the finfo structures live in TypCacheContext,
 	 * which is not quite right (they're really in the hash table's private
 	 * memory context) but this will do for our purposes.
 	 *
@@ -872,21 +886,21 @@ lookup_type_cache(Oid type_id, int flags)
 		eq_opr_func = get_opcode(typentry->eq_opr);
 		if (eq_opr_func != InvalidOid)
 			fmgr_info_cxt(eq_opr_func, &typentry->eq_opr_finfo,
-						  CacheMemoryContext);
+						  TypCacheContext);
 	}
 	if ((flags & TYPECACHE_CMP_PROC_FINFO) &&
 		typentry->cmp_proc_finfo.fn_oid == InvalidOid &&
 		typentry->cmp_proc != InvalidOid)
 	{
 		fmgr_info_cxt(typentry->cmp_proc, &typentry->cmp_proc_finfo,
-					  CacheMemoryContext);
+					  TypCacheContext);
 	}
 	if ((flags & TYPECACHE_HASH_PROC_FINFO) &&
 		typentry->hash_proc_finfo.fn_oid == InvalidOid &&
 		typentry->hash_proc != InvalidOid)
 	{
 		fmgr_info_cxt(typentry->hash_proc, &typentry->hash_proc_finfo,
-					  CacheMemoryContext);
+					  TypCacheContext);
 	}
 	if ((flags & TYPECACHE_HASH_EXTENDED_PROC_FINFO) &&
 		typentry->hash_extended_proc_finfo.fn_oid == InvalidOid &&
@@ -894,7 +908,7 @@ lookup_type_cache(Oid type_id, int flags)
 	{
 		fmgr_info_cxt(typentry->hash_extended_proc,
 					  &typentry->hash_extended_proc_finfo,
-					  CacheMemoryContext);
+					  TypCacheContext);
 	}
 
 	/*
@@ -1039,13 +1053,13 @@ load_rangetype_info(TypeCacheEntry *typentry)
 
 	/* set up cached fmgrinfo structs */
 	fmgr_info_cxt(cmpFnOid, &typentry->rng_cmp_proc_finfo,
-				  CacheMemoryContext);
+				  TypCacheContext);
 	if (OidIsValid(canonicalOid))
 		fmgr_info_cxt(canonicalOid, &typentry->rng_canonical_finfo,
-					  CacheMemoryContext);
+					  TypCacheContext);
 	if (OidIsValid(subdiffOid))
 		fmgr_info_cxt(subdiffOid, &typentry->rng_subdiff_finfo,
-					  CacheMemoryContext);
+					  TypCacheContext);
 
 	/* Lastly, set up link to the element type --- this marks data valid */
 	typentry->rngelemtype = lookup_type_cache(subtypeOid, 0);
@@ -1074,7 +1088,7 @@ load_multirangetype_info(TypeCacheEntry *typentry)
  * Note: we assume we're called in a relatively short-lived context, so it's
  * okay to leak data into the current context while scanning pg_constraint.
  * We build the new DomainConstraintCache data in a context underneath
- * CurrentMemoryContext, and reparent it under CacheMemoryContext when
+ * CurrentMemoryContext, and reparent it under TypCacheContext when
  * complete.
  */
 static void
@@ -1296,12 +1310,12 @@ load_domaintype_info(TypeCacheEntry *typentry)
 	}
 
 	/*
-	 * If we made a constraint object, move it into CacheMemoryContext and
+	 * If we made a constraint object, move it into TypCacheContext and
 	 * attach it to the typcache entry.
 	 */
 	if (dcc)
 	{
-		MemoryContextSetParent(dcc->dccContext, CacheMemoryContext);
+		MemoryContextSetParent(dcc->dccContext, TypCacheContext);
 		typentry->domainData = dcc;
 		dcc->dccRefCount++;		/* count the typcache's reference */
 	}
@@ -1799,7 +1813,7 @@ ensure_record_cache_typmod_slot_exists(int32 typmod)
 	if (RecordCacheArray == NULL)
 	{
 		RecordCacheArray = (RecordCacheArrayEntry *)
-			MemoryContextAllocZero(CacheMemoryContext,
+			MemoryContextAllocZero(TypCacheContext,
 								   64 * sizeof(RecordCacheArrayEntry));
 		RecordCacheArrayLen = 64;
 	}
@@ -2059,9 +2073,9 @@ assign_record_type_typmod(TupleDesc tupDesc)
 									  &ctl,
 									  HASH_ELEM | HASH_FUNCTION | HASH_COMPARE);
 
-		/* Also make sure CacheMemoryContext exists */
-		if (!CacheMemoryContext)
-			CreateCacheMemoryContext();
+		/* Also make sure TypCacheContext exists */
+		if (!TypCacheContext)
+			CreateTypCacheContext();
 	}
 
 	/*
@@ -2079,7 +2093,7 @@ assign_record_type_typmod(TupleDesc tupDesc)
 	}
 
 	/* Not present, so need to manufacture an entry */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	oldcxt = MemoryContextSwitchTo(TypCacheContext);
 
 	/* Look in the SharedRecordTypmodRegistry, if attached */
 	entDesc = find_or_make_matching_shared_tupledesc(tupDesc);
@@ -2746,8 +2760,8 @@ load_enum_cache_data(TypeCacheEntry *tcache)
 	/*
 	 * Read all the information for members of the enum type.  We collect the
 	 * info in working memory in the caller's context, and then transfer it to
-	 * permanent memory in CacheMemoryContext.  This minimizes the risk of
-	 * leaking memory from CacheMemoryContext in the event of an error partway
+	 * permanent memory in TypCacheContext.  This minimizes the risk of
+	 * leaking memory from TypCacheContext in the event of an error partway
 	 * through.
 	 */
 	maxitems = 64;
@@ -2851,8 +2865,8 @@ load_enum_cache_data(TypeCacheEntry *tcache)
 			break;
 	}
 
-	/* OK, copy the data into CacheMemoryContext */
-	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+	/* OK, copy the data into TypCacheContext */
+	oldcxt = MemoryContextSwitchTo(TypCacheContext);
 	enumdata = (TypeCacheEnumData *)
 		palloc(offsetof(TypeCacheEnumData, enum_values) +
 			   numitems * sizeof(EnumItem));
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index 18c32ea700..ca089d3dbc 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -95,6 +95,7 @@ extern int	errtableconstraint(Relation rel, const char *conname);
 /*
  * Routines for backend startup
  */
+extern void CreateRelCacheContext(void);
 extern void RelationCacheInitialize(void);
 extern void RelationCacheInitializePhase2(void);
 extern void RelationCacheInitializePhase3(void);
@@ -152,4 +153,6 @@ extern PGDLLIMPORT bool criticalRelcachesBuilt;
 /* should be used only by relcache.c and postinit.c */
 extern PGDLLIMPORT bool criticalSharedRelcachesBuilt;
 
+extern PGDLLIMPORT MemoryContext RelCacheContext;
+
 #endif							/* RELCACHE_H */
-- 
2.34.1

Reply via email to