Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Overload index_form_tuple to allow the memory context to be supplied
authorDavid Rowley <drowley@postgresql.org>
Wed, 6 Jul 2022 20:14:00 +0000 (08:14 +1200)
committerDavid Rowley <drowley@postgresql.org>
Wed, 6 Jul 2022 20:14:00 +0000 (08:14 +1200)
40af10b57 changed things so we make use of a generation memory context for
storing tuples to be sorted by tuplesort.c. That change does not play
nicely with the changes made in 9f03ca915 (back in 2014). That commit
changed things so that index_form_tuple() is called while switched into
the tuplestore's tuplecontext. In order to fetch the tuple from the index,
index_form_tuple() must do various memory allocations which are unrelated
to the storage of the final returned tuple. Although all of these
allocations are pfree'd, the fact that we now use a generation context
means that the memory for these pfree'd allocations won't be used again by
any other allocation due to generation.c's lack of freelists.  This could
result in sorts used for building indexes exceeding maintenance_work_mem
by a very large amount.

Here we fix it so we no longer allocate anything apart from the tuple
itself into the generation context by adding a new version of
index_form_tuple named index_form_tuple_context, which can be called to
specify the MemoryContext to allocate the tuple into.

Discussion: https://postgr.es/m/CAApHDvrHQkiFRHiGiAS-LMOvJN-eK-s762=tVzBz8ZqUea-a_A@mail.gmail.com
Backpatch-through: 15, where 40af10b57 was added.

src/backend/access/common/indextuple.c
src/backend/utils/sort/tuplesort.c
src/include/access/itup.h

index 3065730bae066204a8c5b900ef61f9b3d7150c66..c0bad3cd9574e73b9f41e0445dbb0da380460285 100644 (file)
  * ----------------------------------------------------------------
  */
 
+ /* ----------------
+  *        index_form_tuple
+  *
+  *        As index_form_tuple_context, but allocates the returned tuple in the
+  *        CurrentMemoryContext.
+  * ----------------
+  */
+IndexTuple
+index_form_tuple(TupleDesc tupleDescriptor,
+                Datum *values,
+                bool *isnull)
+{
+   return index_form_tuple_context(tupleDescriptor, values, isnull,
+                                   CurrentMemoryContext);
+}
+
 /* ----------------
- *     index_form_tuple
+ *     index_form_tuple_context
  *
  *     This shouldn't leak any memory; otherwise, callers such as
  *     tuplesort_putindextuplevalues() will be very unhappy.
  *
  *     This shouldn't perform external table access provided caller
  *     does not pass values that are stored EXTERNAL.
+ *
+ *     Allocates returned tuple in provided 'context'.
  * ----------------
  */
 IndexTuple
-index_form_tuple(TupleDesc tupleDescriptor,
-                Datum *values,
-                bool *isnull)
+index_form_tuple_context(TupleDesc tupleDescriptor,
+                        Datum *values,
+                        bool *isnull,
+                        MemoryContext context)
 {
    char       *tp;             /* tuple pointer */
    IndexTuple  tuple;          /* return tuple */
@@ -143,7 +162,7 @@ index_form_tuple(TupleDesc tupleDescriptor,
    size = hoff + data_size;
    size = MAXALIGN(size);      /* be conservative */
 
-   tp = (char *) palloc0(size);
+   tp = (char *) MemoryContextAllocZero(context, size);
    tuple = (IndexTuple) tp;
 
    heap_fill_tuple(tupleDescriptor,
index 31554fd867dba3ae24e1067620f7a957a2517525..421afcf47d33443de798419ef503cdff90e0a1c4 100644 (file)
@@ -1884,12 +1884,13 @@ tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel,
                              ItemPointer self, Datum *values,
                              bool *isnull)
 {
-   MemoryContext oldcontext = MemoryContextSwitchTo(state->tuplecontext);
+   MemoryContext oldcontext;
    SortTuple   stup;
    Datum       original;
    IndexTuple  tuple;
 
-   stup.tuple = index_form_tuple(RelationGetDescr(rel), values, isnull);
+   stup.tuple = index_form_tuple_context(RelationGetDescr(rel), values,
+                                         isnull, state->tuplecontext);
    tuple = ((IndexTuple) stup.tuple);
    tuple->t_tid = *self;
    USEMEM(state, GetMemoryChunkSpace(stup.tuple));
@@ -1899,7 +1900,7 @@ tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel,
                             RelationGetDescr(state->indexRel),
                             &stup.isnull1);
 
-   MemoryContextSwitchTo(state->sortcontext);
+   oldcontext = MemoryContextSwitchTo(state->sortcontext);
 
    if (!state->sortKeys || !state->sortKeys->abbrev_converter || stup.isnull1)
    {
index 2c8877e9911c39cf00248654aef6c32e75f5213c..7458bc2fda60e4bb0cc0f614f937dee1a75dcafd 100644 (file)
@@ -150,6 +150,9 @@ typedef IndexAttributeBitMapData * IndexAttributeBitMap;
 /* routines in indextuple.c */
 extern IndexTuple index_form_tuple(TupleDesc tupleDescriptor,
                                   Datum *values, bool *isnull);
+extern IndexTuple index_form_tuple_context(TupleDesc tupleDescriptor,
+                                          Datum *values, bool *isnull,
+                                          MemoryContext context);
 extern Datum nocache_index_getattr(IndexTuple tup, int attnum,
                                   TupleDesc tupleDesc);
 extern void index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,