sortmem_grow-v2.patch
application/octet-stream
Filename: sortmem_grow-v2.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/utils/sort/tuplesort.c | 45 | 7 |
diff src/backend/utils/sort/tuplesort.c
index d5a2003..27d833f
*** a/src/backend/utils/sort/tuplesort.c
--- b/src/backend/utils/sort/tuplesort.c
*************** struct Tuplesortstate
*** 275,280 ****
--- 275,281 ----
SortTuple *memtuples; /* array of SortTuple structs */
int memtupcount; /* number of tuples currently present */
int memtupsize; /* allocated length of memtuples array */
+ bool fin_growth; /* are we no longer growing memtupsize? */
/*
* While building initial runs, this is the current output run number
*************** tuplesort_begin_common(int workMem, bool
*** 569,574 ****
--- 570,576 ----
state->memtupcount = 0;
state->memtupsize = 1024; /* initial guess */
+ state->fin_growth = false;
state->memtuples = (SortTuple *) palloc(state->memtupsize * sizeof(SortTuple));
USEMEM(state, GetMemoryChunkSpace(state->memtuples));
*************** tuplesort_end(Tuplesortstate *state)
*** 956,965 ****
* Grow the memtuples[] array, if possible within our memory constraint.
* Return TRUE if able to enlarge the array, FALSE if not.
*
! * At each increment we double the size of the array. When we are short
! * on memory we could consider smaller increases, but because availMem
! * moves around with tuple addition/removal, this might result in thrashing.
! * Small increases in the array size are likely to be pretty inefficient.
*/
static bool
grow_memtuples(Tuplesortstate *state)
--- 958,968 ----
* Grow the memtuples[] array, if possible within our memory constraint.
* Return TRUE if able to enlarge the array, FALSE if not.
*
! * At each increment (except, possibly, the last) we double the size of the
! * array. When we are short on memory we consider smaller increases, but
! * because availMem moves around with tuple addition/removal, this might result
! * in thrashing, which is why it will only occur once at the most. Small
! * increases in the array size are likely to be pretty inefficient.
*/
static bool
grow_memtuples(Tuplesortstate *state)
*************** grow_memtuples(Tuplesortstate *state)
*** 973,990 ****
* enough to force palloc to treat it as a separate chunk, so this
* assumption should be good. But let's check it.)
*/
! if (state->availMem <= (long) (state->memtupsize * sizeof(SortTuple)))
return false;
/*
* On a 64-bit machine, allowedMem could be high enough to get us into
* trouble with MaxAllocSize, too.
*/
! if ((Size) (state->memtupsize * 2) >= MaxAllocSize / sizeof(SortTuple))
return false;
FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
! state->memtupsize *= 2;
state->memtuples = (SortTuple *)
repalloc(state->memtuples,
state->memtupsize * sizeof(SortTuple));
--- 976,1028 ----
* enough to force palloc to treat it as a separate chunk, so this
* assumption should be good. But let's check it.)
*/
! int newmemtupsize;
!
! if (state->fin_growth)
! {
return false;
+ }
+ else if (state->availMem < state->allowedMem / 2)
+ {
+ /*
+ * Make a last-ditch effort to avoid exceeding allowedMem - abandon
+ * doubling strategy.
+ *
+ * Once we are approaching the final growth of memtuples, use the known
+ * size of the tuples seen so far to estimate final growth size. This
+ * should be on average more space-efficient, which is particularly
+ * important here.
+ *
+ * N.B. We rely on the assumption that nothing other than memtuples and
+ * individual tuple storage has been deducted from availMem.
+ */
+ float oldmemtupsize = (float) state->memtupsize;
+ float allowedMem = (float) state->allowedMem;
+ float memNowUsed = (float) state->allowedMem - state->availMem;
+
+ Assert(memNowUsed > 0);
+
+ /*
+ * XXX: This feels quite brittle; is there a better principled approach,
+ * that does not violate modularity?
+ */
+ newmemtupsize = (int) floor(oldmemtupsize * allowedMem / memNowUsed);
+ state->fin_growth = true;
+ }
+ else
+ {
+ newmemtupsize = state->memtupsize * 2;
+ }
/*
* On a 64-bit machine, allowedMem could be high enough to get us into
* trouble with MaxAllocSize, too.
*/
! if ((Size) (newmemtupsize) >= MaxAllocSize / sizeof(SortTuple))
return false;
FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
! state->memtupsize = newmemtupsize;
state->memtuples = (SortTuple *)
repalloc(state->memtuples,
state->memtupsize * sizeof(SortTuple));