Skip to content

Commit 1083f94

Browse files
committed
Be smarter about freeing tuples during tuplesorts
During dumptuples() the call to writetuple() would pfree any non-null tuple. This was quite wasteful as this happens just before we perform a reset of the context which stores all of those tuples. It seems to make sense to do a bit of a code refactor to make this work, so here we just get rid of the writetuple function and adjust the WRITETUP macro to call the state's writetup function. The WRITETUP usage in mergeonerun() always has state->slabAllocatorUsed == true, so writetuple() would never free the tuple or do any memory accounting. The only call path that needs memory accounting done is in dumptuples(), so let's just do it manually there. In passing, let's get rid of the state->memtupcount-- code that counts the memtupcount down to 0 one tuple at a time inside the loop. That seems to be a rather inefficient way to set memtupcount to 0, so let's just zero it after the loop instead. Author: David Rowley Discussion: https://postgr.es/m/CAApHDvqZXoDCyrfCzZJR0-xH+7_q+GgitcQiYXUjRani7h4j8Q@mail.gmail.com
1 parent 349baa8 commit 1083f94

File tree

1 file changed

+15
-23
lines changed

1 file changed

+15
-23
lines changed

src/backend/utils/sort/tuplesort.c

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ struct Sharedsort
395395

396396
#define REMOVEABBREV(state,stup,count) ((*(state)->base.removeabbrev) (state, stup, count))
397397
#define COMPARETUP(state,a,b) ((*(state)->base.comparetup) (a, b, state))
398-
#define WRITETUP(state,tape,stup) (writetuple(state, tape, stup))
398+
#define WRITETUP(state,tape,stup) ((*(state)->base.writetup) (state, tape, stup))
399399
#define READTUP(state,stup,tape,len) ((*(state)->base.readtup) (state, stup, tape, len))
400400
#define FREESTATE(state) ((state)->base.freestate ? (*(state)->base.freestate) (state) : (void) 0)
401401
#define LACKMEM(state) ((state)->availMem < 0 && !(state)->slabAllocatorUsed)
@@ -453,8 +453,6 @@ struct Sharedsort
453453

454454

455455
static void tuplesort_begin_batch(Tuplesortstate *state);
456-
static void writetuple(Tuplesortstate *state, LogicalTape *tape,
457-
SortTuple *stup);
458456
static bool consider_abort_common(Tuplesortstate *state);
459457
static void inittapes(Tuplesortstate *state, bool mergeruns);
460458
static void inittapestate(Tuplesortstate *state, int maxTapes);
@@ -1339,24 +1337,6 @@ tuplesort_puttuple_common(Tuplesortstate *state, SortTuple *tuple, bool useAbbre
13391337
MemoryContextSwitchTo(oldcontext);
13401338
}
13411339

1342-
/*
1343-
* Write a stored tuple onto tape. Unless the slab allocator is
1344-
* used, after writing the tuple, pfree() the out-of-line data (not the
1345-
* SortTuple struct!), and increase state->availMem by the amount of
1346-
* memory space thereby released.
1347-
*/
1348-
static void
1349-
writetuple(Tuplesortstate *state, LogicalTape *tape, SortTuple *stup)
1350-
{
1351-
state->base.writetup(state, tape, stup);
1352-
1353-
if (!state->slabAllocatorUsed && stup->tuple)
1354-
{
1355-
FREEMEM(state, GetMemoryChunkSpace(stup->tuple));
1356-
pfree(stup->tuple);
1357-
}
1358-
}
1359-
13601340
static bool
13611341
consider_abort_common(Tuplesortstate *state)
13621342
{
@@ -2260,6 +2240,8 @@ mergeonerun(Tuplesortstate *state)
22602240
*/
22612241
beginmerge(state);
22622242

2243+
Assert(state->slabAllocatorUsed);
2244+
22632245
/*
22642246
* Execute merge by repeatedly extracting lowest tuple in heap, writing it
22652247
* out, and replacing it with next tuple from same tape (if there is
@@ -2418,10 +2400,20 @@ dumptuples(Tuplesortstate *state, bool alltuples)
24182400
memtupwrite = state->memtupcount;
24192401
for (i = 0; i < memtupwrite; i++)
24202402
{
2421-
WRITETUP(state, state->destTape, &state->memtuples[i]);
2422-
state->memtupcount--;
2403+
SortTuple *stup = &state->memtuples[i];
2404+
2405+
WRITETUP(state, state->destTape, stup);
2406+
2407+
/*
2408+
* Account for freeing the tuple, but no need to do the actual pfree
2409+
* since the tuplecontext is being reset after the loop.
2410+
*/
2411+
if (stup->tuple != NULL)
2412+
FREEMEM(state, GetMemoryChunkSpace(stup->tuple));
24232413
}
24242414

2415+
state->memtupcount = 0;
2416+
24252417
/*
24262418
* Reset tuple memory. We've freed all of the tuples that we previously
24272419
* allocated. It's important to avoid fragmentation when there is a stark

0 commit comments

Comments
 (0)