aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/partitioning/partdesc.c23
-rw-r--r--src/backend/utils/cache/relcache.c48
2 files changed, 52 insertions, 19 deletions
diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c
index 5f349ad46ad..a65cc526da5 100644
--- a/src/backend/partitioning/partdesc.c
+++ b/src/backend/partitioning/partdesc.c
@@ -67,20 +67,9 @@ RelationBuildPartitionDesc(Relation rel)
nparts;
PartitionKey key = RelationGetPartitionKey(rel);
MemoryContext oldcxt;
- MemoryContext rbcontext;
int *mapping;
/*
- * While building the partition descriptor, we create various temporary
- * data structures; in CLOBBER_CACHE_ALWAYS mode, at least, it's important
- * not to leak them, since this can get called a lot.
- */
- rbcontext = AllocSetContextCreate(CurrentMemoryContext,
- "RelationBuildPartitionDesc",
- ALLOCSET_DEFAULT_SIZES);
- oldcxt = MemoryContextSwitchTo(rbcontext);
-
- /*
* Get partition oids from pg_inherits. This uses a single snapshot to
* fetch the list of children, so while more children may be getting
* added concurrently, whatever this function returns will be accurate
@@ -197,14 +186,15 @@ RelationBuildPartitionDesc(Relation rel)
/* If there are no partitions, the rest of the partdesc can stay zero */
if (nparts > 0)
{
- /* Create PartitionBoundInfo, using the temporary context. */
+ /* Create PartitionBoundInfo, using the caller's context. */
boundinfo = partition_bounds_create(boundspecs, nparts, key, &mapping);
/* Now copy all info into relcache's partdesc. */
- MemoryContextSwitchTo(rel->rd_pdcxt);
+ oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
partdesc->boundinfo = partition_bounds_copy(boundinfo, key);
partdesc->oids = (Oid *) palloc(nparts * sizeof(Oid));
partdesc->is_leaf = (bool *) palloc(nparts * sizeof(bool));
+ MemoryContextSwitchTo(oldcxt);
/*
* Assign OIDs from the original array into mapped indexes of the
@@ -214,9 +204,8 @@ RelationBuildPartitionDesc(Relation rel)
*
* Also record leaf-ness of each partition. For this we use
* get_rel_relkind() which may leak memory, so be sure to run it in
- * the temporary context.
+ * the caller's context.
*/
- MemoryContextSwitchTo(rbcontext);
for (i = 0; i < nparts; i++)
{
int index = mapping[i];
@@ -228,10 +217,6 @@ RelationBuildPartitionDesc(Relation rel)
}
rel->rd_partdesc = partdesc;
-
- /* Return to caller's context, and blow away the temporary context. */
- MemoryContextSwitchTo(oldcxt);
- MemoryContextDelete(rbcontext);
}
/*
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index eba77491fd5..84609e07253 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -94,6 +94,19 @@
#define RELCACHE_INIT_FILEMAGIC 0x573266 /* version ID value */
/*
+ * Default policy for whether to apply RECOVER_RELATION_BUILD_MEMORY:
+ * do so in clobber-cache builds but not otherwise. This choice can be
+ * overridden at compile time with -DRECOVER_RELATION_BUILD_MEMORY=1 or =0.
+ */
+#ifndef RECOVER_RELATION_BUILD_MEMORY
+#if defined(CLOBBER_CACHE_ALWAYS) || defined(CLOBBER_CACHE_RECURSIVELY)
+#define RECOVER_RELATION_BUILD_MEMORY 1
+#else
+#define RECOVER_RELATION_BUILD_MEMORY 0
+#endif
+#endif
+
+/*
* hardcoded tuple descriptors, contents generated by genbki.pl
*/
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};
@@ -1015,6 +1028,28 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
Form_pg_class relp;
/*
+ * This function and its subroutines can allocate a good deal of transient
+ * data in CurrentMemoryContext. Traditionally we've just leaked that
+ * data, reasoning that the caller's context is at worst of transaction
+ * scope, and relcache loads shouldn't happen so often that it's essential
+ * to recover transient data before end of statement/transaction. However
+ * that's definitely not true in clobber-cache test builds, and perhaps
+ * it's not true in other cases. If RECOVER_RELATION_BUILD_MEMORY is not
+ * zero, arrange to allocate the junk in a temporary context that we'll
+ * free before returning. Make it a child of caller's context so that it
+ * will get cleaned up appropriately if we error out partway through.
+ */
+#if RECOVER_RELATION_BUILD_MEMORY
+ MemoryContext tmpcxt;
+ MemoryContext oldcxt;
+
+ tmpcxt = AllocSetContextCreate(CurrentMemoryContext,
+ "RelationBuildDesc workspace",
+ ALLOCSET_DEFAULT_SIZES);
+ oldcxt = MemoryContextSwitchTo(tmpcxt);
+#endif
+
+ /*
* find the tuple in pg_class corresponding to the given relation id
*/
pg_class_tuple = ScanPgRelation(targetRelId, true, false);
@@ -1023,7 +1058,14 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
* if no such tuple exists, return NULL
*/
if (!HeapTupleIsValid(pg_class_tuple))
+ {
+#if RECOVER_RELATION_BUILD_MEMORY
+ /* Return to caller's context, and blow away the temporary context */
+ MemoryContextSwitchTo(oldcxt);
+ MemoryContextDelete(tmpcxt);
+#endif
return NULL;
+ }
/*
* get information from the pg_class_tuple
@@ -1203,6 +1245,12 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
/* It's fully valid */
relation->rd_isvalid = true;
+#if RECOVER_RELATION_BUILD_MEMORY
+ /* Return to caller's context, and blow away the temporary context */
+ MemoryContextSwitchTo(oldcxt);
+ MemoryContextDelete(tmpcxt);
+#endif
+
return relation;
}