120#define INITIAL_MEMTUPSIZE Max(1024, \
121 ALLOCSET_SEPARATE_THRESHOLD / sizeof(SortTuple) + 1)
126#ifdef DEBUG_BOUNDED_SORT
127bool optimize_bounded_sort =
true;
142#define SLAB_SLOT_SIZE 1024
178#define TAPE_BUFFER_OVERHEAD BLCKSZ
179#define MERGE_BUFFER_SIZE (BLCKSZ * 32)
375#define IS_SLAB_SLOT(state, tuple) \
376 ((char *) (tuple) >= (state)->slabMemoryBegin && \
377 (char *) (tuple) < (state)->slabMemoryEnd)
383#define RELEASE_SLAB_SLOT(state, tuple) \
385 SlabSlot *buf = (SlabSlot *) tuple; \
387 if (IS_SLAB_SLOT((state), buf)) \
389 buf->nextfree = (state)->slabFreeHead; \
390 (state)->slabFreeHead = buf; \
395#define REMOVEABBREV(state,stup,count) ((*(state)->base.removeabbrev) (state, stup, count))
396#define COMPARETUP(state,a,b) ((*(state)->base.comparetup) (a, b, state))
397#define WRITETUP(state,tape,stup) ((*(state)->base.writetup) (state, tape, stup))
398#define READTUP(state,stup,tape,len) ((*(state)->base.readtup) (state, stup, tape, len))
399#define FREESTATE(state) ((state)->base.freestate ? (*(state)->base.freestate) (state) : (void) 0)
400#define LACKMEM(state) ((state)->availMem < 0 && !(state)->slabAllocatorUsed)
401#define USEMEM(state,amt) ((state)->availMem -= (amt))
402#define FREEMEM(state,amt) ((state)->availMem += (amt))
403#define SERIAL(state) ((state)->shared == NULL)
404#define WORKER(state) ((state)->shared && (state)->worker != -1)
405#define LEADER(state) ((state)->shared && (state)->worker == -1)
500 b->datum1,
b->isnull1,
501 &
state->base.sortKeys[0]);
509 if (
state->base.onlyKey != NULL)
522 b->datum1,
b->isnull1,
523 &
state->base.sortKeys[0]);
532 if (
state->base.onlyKey != NULL)
545 b->datum1,
b->isnull1,
546 &
state->base.sortKeys[0]);
555 if (
state->base.onlyKey != NULL)
570#define ST_SORT qsort_tuple_unsigned
571#define ST_ELEMENT_TYPE SortTuple
572#define ST_COMPARE(a, b, state) qsort_tuple_unsigned_compare(a, b, state)
573#define ST_COMPARE_ARG_TYPE Tuplesortstate
574#define ST_CHECK_FOR_INTERRUPTS
575#define ST_SCOPE static
579#define ST_SORT qsort_tuple_signed
580#define ST_ELEMENT_TYPE SortTuple
581#define ST_COMPARE(a, b, state) qsort_tuple_signed_compare(a, b, state)
582#define ST_COMPARE_ARG_TYPE Tuplesortstate
583#define ST_CHECK_FOR_INTERRUPTS
584#define ST_SCOPE static
588#define ST_SORT qsort_tuple_int32
589#define ST_ELEMENT_TYPE SortTuple
590#define ST_COMPARE(a, b, state) qsort_tuple_int32_compare(a, b, state)
591#define ST_COMPARE_ARG_TYPE Tuplesortstate
592#define ST_CHECK_FOR_INTERRUPTS
593#define ST_SCOPE static
597#define ST_SORT qsort_tuple
598#define ST_ELEMENT_TYPE SortTuple
599#define ST_COMPARE_RUNTIME_POINTER
600#define ST_COMPARE_ARG_TYPE Tuplesortstate
601#define ST_CHECK_FOR_INTERRUPTS
602#define ST_SCOPE static
607#define ST_SORT qsort_ssup
608#define ST_ELEMENT_TYPE SortTuple
609#define ST_COMPARE(a, b, ssup) \
610 ApplySortComparator((a)->datum1, (a)->isnull1, \
611 (b)->datum1, (b)->isnull1, (ssup))
612#define ST_COMPARE_ARG_TYPE SortSupportData
613#define ST_CHECK_FOR_INTERRUPTS
614#define ST_SCOPE static
647 elog(
ERROR,
"random access disallowed under parallel sort");
681 state->base.sortopt = sortopt;
682 state->base.tuples =
true;
683 state->abbrevNext = 10;
692 state->base.sortcontext = sortcontext;
693 state->base.maincontext = maincontext;
700 state->memtuples = NULL;
715 state->shared = NULL;
717 state->nParticipants = -1;
724 state->nParticipants = -1;
778 state->bounded =
false;
779 state->boundUsed =
false;
783 state->tapeset = NULL;
785 state->memtupcount = 0;
791 state->growmemtuples =
true;
792 state->slabAllocatorUsed =
false;
796 state->memtuples = NULL;
799 if (
state->memtuples == NULL)
807 elog(
ERROR,
"insufficient memory allowed for sort");
809 state->currentRun = 0;
816 state->result_tape = NULL;
849#ifdef DEBUG_BOUNDED_SORT
851 if (!optimize_bounded_sort)
856 if (bound > (
int64) (INT_MAX / 2))
859 state->bounded =
true;
860 state->bound = (int) bound;
867 state->base.sortKeys->abbrev_converter = NULL;
868 if (
state->base.sortKeys->abbrev_full_comparator)
869 state->base.sortKeys->comparator =
state->base.sortKeys->abbrev_full_comparator;
872 state->base.sortKeys->abbrev_abort = NULL;
873 state->base.sortKeys->abbrev_full_comparator = NULL;
884 return state->boundUsed;
902 spaceUsed = (
state->allowedMem -
state->availMem + 1023) / 1024;
917 elog(
LOG,
"%s of worker %d ended, %" PRId64
" disk blocks used: %s",
918 SERIAL(
state) ?
"external sort" :
"parallel external sort",
921 elog(
LOG,
"%s of worker %d ended, %" PRId64
" KB used: %s",
922 SERIAL(
state) ?
"internal sort" :
"unperformed parallel sort",
926 TRACE_POSTGRESQL_SORT_DONE(
state->tapeset != NULL, spaceUsed);
986 spaceUsed =
state->allowedMem -
state->availMem;
997 if ((isSpaceDisk && !
state->isMaxSpaceDisk) ||
998 (isSpaceDisk ==
state->isMaxSpaceDisk && spaceUsed >
state->maxSpace))
1000 state->maxSpace = spaceUsed;
1001 state->isMaxSpaceDisk = isSpaceDisk;
1026 state->lastReturnedTuple = NULL;
1027 state->slabMemoryBegin = NULL;
1028 state->slabMemoryEnd = NULL;
1029 state->slabFreeHead = NULL;
1051 int memtupsize =
state->memtupsize;
1055 if (!
state->growmemtuples)
1059 if (memNowUsed <= state->availMem)
1065 if (memtupsize < INT_MAX / 2)
1066 newmemtupsize = memtupsize * 2;
1069 newmemtupsize = INT_MAX;
1070 state->growmemtuples =
false;
1103 grow_ratio = (double)
state->allowedMem / (
double) memNowUsed;
1104 if (memtupsize * grow_ratio < INT_MAX)
1105 newmemtupsize = (int) (memtupsize * grow_ratio);
1107 newmemtupsize = INT_MAX;
1110 state->growmemtuples =
false;
1114 if (newmemtupsize <= memtupsize)
1127 state->growmemtuples =
false;
1146 state->memtupsize = newmemtupsize;
1152 elog(
ERROR,
"unexpected out-of-memory situation in tuplesort");
1157 state->growmemtuples =
false;
1166 bool useAbbrev,
Size tuplen)
1174 state->tupleMem += tuplen;
1191 state->base.sortKeys);
1207 switch (
state->status)
1218 if (
state->memtupcount >=
state->memtupsize - 1)
1223 state->memtuples[
state->memtupcount++] = *tuple;
1237 if (
state->bounded &&
1242 elog(
LOG,
"switching to bounded heapsort at %d tuples: %s",
1299 state->memtuples[
state->memtupcount++] = *tuple;
1317 Assert(
state->base.sortKeys[0].abbrev_converter != NULL);
1318 Assert(
state->base.sortKeys[0].abbrev_abort != NULL);
1319 Assert(
state->base.sortKeys[0].abbrev_full_comparator != NULL);
1328 state->abbrevNext *= 2;
1334 if (!
state->base.sortKeys->abbrev_abort(
state->memtupcount,
1335 state->base.sortKeys))
1342 state->base.sortKeys[0].comparator =
state->base.sortKeys[0].abbrev_full_comparator;
1343 state->base.sortKeys[0].abbrev_converter = NULL;
1345 state->base.sortKeys[0].abbrev_abort = NULL;
1346 state->base.sortKeys[0].abbrev_full_comparator = NULL;
1364 elog(
LOG,
"performsort of worker %d starting: %s",
1367 switch (
state->status)
1402 state->eof_reached =
false;
1403 state->markpos_block = 0L;
1404 state->markpos_offset = 0;
1405 state->markpos_eof =
false;
1418 state->eof_reached =
false;
1419 state->markpos_offset = 0;
1420 state->markpos_eof =
false;
1433 state->eof_reached =
false;
1434 state->markpos_block = 0L;
1435 state->markpos_offset = 0;
1436 state->markpos_eof =
false;
1447 elog(
LOG,
"performsort of worker %d done (except %d-way final merge): %s",
1451 elog(
LOG,
"performsort of worker %d done: %s",
1469 unsigned int tuplen;
1474 switch (
state->status)
1486 state->eof_reached =
true;
1494 elog(
ERROR,
"retrieved too many tuples in a bounded sort");
1500 if (
state->current <= 0)
1507 if (
state->eof_reached)
1508 state->eof_reached =
false;
1512 if (
state->current <= 0)
1515 *stup =
state->memtuples[
state->current - 1];
1528 if (
state->lastReturnedTuple)
1531 state->lastReturnedTuple = NULL;
1536 if (
state->eof_reached)
1539 if ((tuplen =
getlen(
state->result_tape,
true)) != 0)
1554 state->eof_reached =
true;
1565 if (
state->eof_reached)
1573 2 *
sizeof(
unsigned int));
1576 else if (nmoved != 2 *
sizeof(
unsigned int))
1577 elog(
ERROR,
"unexpected tape position");
1578 state->eof_reached =
false;
1587 sizeof(
unsigned int));
1590 else if (nmoved !=
sizeof(
unsigned int))
1591 elog(
ERROR,
"unexpected tape position");
1598 tuplen + 2 *
sizeof(
unsigned int));
1599 if (nmoved == tuplen +
sizeof(
unsigned int))
1610 else if (nmoved != tuplen + 2 *
sizeof(
unsigned int))
1611 elog(
ERROR,
"bogus tuple length in backward scan");
1623 if (nmoved != tuplen)
1624 elog(
ERROR,
"bogus tuple length in backward scan");
1644 if (
state->lastReturnedTuple)
1647 state->lastReturnedTuple = NULL;
1653 if (
state->memtupcount > 0)
1655 int srcTapeIndex =
state->memtuples[0].srctape;
1659 *stup =
state->memtuples[0];
1678 state->nInputRuns--;
1687 newtup.
srctape = srcTapeIndex;
1718 switch (
state->status)
1721 if (
state->memtupcount -
state->current >= ntuples)
1723 state->current += ntuples;
1727 state->eof_reached =
true;
1735 elog(
ERROR,
"retrieved too many tuples in a bounded sort");
1747 while (ntuples-- > 0)
1799 mOrder = allowedMem /
1840 nOutputRuns = (nInputRuns + nInputTapes - 1) / nInputTapes;
1842 nOutputTapes =
Min(nOutputRuns, maxOutputTapes);
1878 elog(
LOG,
"worker %d switching to external sort with %d tapes: %s",
1885 state->shared ? &
state->shared->fileset : NULL,
1888 state->currentRun = 0;
1893 state->inputTapes = NULL;
1894 state->nInputTapes = 0;
1895 state->nInputRuns = 0;
1898 state->nOutputTapes = 0;
1899 state->nOutputRuns = 0;
1959 state->nOutputTapes++;
1960 state->nOutputRuns++;
1969 state->nOutputRuns++;
1985 state->slabMemoryEnd =
state->slabMemoryBegin +
1990 p =
state->slabMemoryBegin;
1991 for (
i = 0;
i < numSlots - 1;
i++)
2000 state->slabMemoryBegin =
state->slabMemoryEnd = NULL;
2001 state->slabFreeHead = NULL;
2003 state->slabAllocatorUsed =
true;
2020 if (
state->base.sortKeys != NULL &&
state->base.sortKeys->abbrev_converter != NULL)
2028 state->base.sortKeys->abbrev_converter = NULL;
2029 state->base.sortKeys->comparator =
state->base.sortKeys->abbrev_full_comparator;
2032 state->base.sortKeys->abbrev_abort = NULL;
2033 state->base.sortKeys->abbrev_full_comparator = NULL;
2048 state->memtuples = NULL;
2063 if (
state->base.tuples)
2089 elog(
LOG,
"worker %d using %zu KB of memory for tape buffers",
2090 state->worker,
state->tape_buffer_mem / 1024);
2100 if (
state->nInputRuns == 0)
2102 int64 input_buffer_size;
2105 if (
state->nInputTapes > 0)
2107 for (tapenum = 0; tapenum <
state->nInputTapes; tapenum++)
2123 state->nOutputTapes = 0;
2124 state->nOutputRuns = 0;
2136 elog(
LOG,
"starting merge pass of %d input runs on %d tapes, " INT64_FORMAT " KB of memory for each input tape: %s",
2137 state->nInputRuns,
state->nInputTapes, input_buffer_size / 1024,
2141 for (tapenum = 0; tapenum <
state->nInputTapes; tapenum++)
2173 if (
state->nInputRuns == 0 &&
state->nOutputRuns <= 1)
2188 for (tapenum = 0; tapenum <
state->nInputTapes; tapenum++)
2214 while (
state->memtupcount > 0)
2219 srcTapeIndex =
state->memtuples[0].srctape;
2220 srcTape =
state->inputTapes[srcTapeIndex];
2224 if (
state->memtuples[0].tuple)
2239 state->nInputRuns--;
2266 for (srcTapeIndex = 0; srcTapeIndex < activeTapes; srcTapeIndex++)
2286 unsigned int tuplen;
2289 if ((tuplen =
getlen(srcTape,
true)) == 0)
2324 if (
state->memtupcount == 0 &&
state->currentRun > 0)
2333 if (
state->currentRun == INT_MAX)
2335 (
errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2336 errmsg(
"cannot have more than %d runs for an external sort",
2339 if (
state->currentRun > 0)
2342 state->currentRun++;
2345 elog(
LOG,
"worker %d starting quicksort of run %d: %s",
2356 elog(
LOG,
"worker %d finished quicksort of run %d: %s",
2360 memtupwrite =
state->memtupcount;
2361 for (
i = 0;
i < memtupwrite;
i++)
2368 state->memtupcount = 0;
2384 state->tupleMem = 0;
2389 elog(
LOG,
"worker %d finished writing run %d to tape %d: %s",
2404 switch (
state->status)
2408 state->eof_reached =
false;
2409 state->markpos_offset = 0;
2410 state->markpos_eof =
false;
2414 state->eof_reached =
false;
2415 state->markpos_block = 0L;
2416 state->markpos_offset = 0;
2417 state->markpos_eof =
false;
2437 switch (
state->status)
2445 &
state->markpos_block,
2446 &
state->markpos_offset);
2468 switch (
state->status)
2476 state->markpos_block,
2477 state->markpos_offset);
2509 if (
state->isMaxSpaceDisk)
2515 switch (
state->maxSpaceStatus)
2518 if (
state->boundUsed)
2544 return "still in progress";
2546 return "top-N heapsort";
2550 return "external sort";
2552 return "external merge";
2585 int tupcount =
state->memtupcount;
2596 state->memtupcount = 0;
2597 for (
i = 0;
i < tupcount;
i++)
2634 int tupcount =
state->memtupcount;
2646 while (
state->memtupcount > 1)
2654 state->memtupcount = tupcount;
2663 state->boundUsed =
true;
2676 if (
state->memtupcount > 1)
2682 if (
state->base.haveDatum1 &&
state->base.sortKeys)
2686 qsort_tuple_unsigned(
state->memtuples,
2693 qsort_tuple_signed(
state->memtuples,
2700 qsort_tuple_int32(
state->memtuples,
2708 if (
state->base.onlyKey != NULL)
2710 qsort_ssup(
state->memtuples,
state->memtupcount,
2711 state->base.onlyKey);
2715 qsort_tuple(
state->memtuples,
2717 state->base.comparetup,
2738 memtuples =
state->memtuples;
2747 j =
state->memtupcount++;
2750 int i = (
j - 1) >> 1;
2754 memtuples[
j] = memtuples[
i];
2757 memtuples[
j] = *tuple;
2773 if (--
state->memtupcount <= 0)
2780 tuple = &memtuples[
state->memtupcount];
2807 n =
state->memtupcount;
2811 unsigned int j = 2 *
i + 1;
2820 memtuples[
i] = memtuples[
j];
2823 memtuples[
i] = *tuple;
2837 for (nkey = 0; nkey <
state->base.nKeys; nkey++, sortKey++)
2857 if (
len == 0 && !eofOK)
2865 unsigned int len = 0;
2893 state->slabFreeHead =
buf->nextfree;
2942 shared->
nTapes = nWorkers;
2943 for (
i = 0;
i < nWorkers;
i++)
3018 state->memtuples = NULL;
3019 state->memtupsize = 0;
3066 int nParticipants =
state->nParticipants;
3067 int workersFinished;
3071 Assert(nParticipants >= 1);
3077 if (nParticipants != workersFinished)
3078 elog(
ERROR,
"cannot take over tapes before all workers finish");
3092 state->currentRun = nParticipants;
3102 state->inputTapes = NULL;
3103 state->nInputTapes = 0;
3104 state->nInputRuns = 0;
3107 state->nOutputTapes = nParticipants;
3108 state->nOutputRuns = nParticipants;
3110 for (
j = 0;
j < nParticipants;
j++)
void PrepareTempTablespaces(void)
MemoryContext BumpContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
#define FLEXIBLE_ARRAY_MEMBER
#define pg_attribute_always_inline
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
static int compare(const void *arg1, const void *arg2)
Assert(PointerIsAligned(start, uint64))
void LogicalTapeRewindForRead(LogicalTape *lt, size_t buffer_size)
void LogicalTapeSetForgetFreeSpace(LogicalTapeSet *lts)
size_t LogicalTapeBackspace(LogicalTape *lt, size_t size)
size_t LogicalTapeRead(LogicalTape *lt, void *ptr, size_t size)
int64 LogicalTapeSetBlocks(LogicalTapeSet *lts)
void LogicalTapeClose(LogicalTape *lt)
void LogicalTapeSetClose(LogicalTapeSet *lts)
void LogicalTapeSeek(LogicalTape *lt, int64 blocknum, int offset)
LogicalTapeSet * LogicalTapeSetCreate(bool preallocate, SharedFileSet *fileset, int worker)
void LogicalTapeTell(LogicalTape *lt, int64 *blocknum, int *offset)
void LogicalTapeWrite(LogicalTape *lt, const void *ptr, size_t size)
LogicalTape * LogicalTapeCreate(LogicalTapeSet *lts)
void LogicalTapeFreeze(LogicalTape *lt, TapeShare *share)
LogicalTape * LogicalTapeImport(LogicalTapeSet *lts, int worker, TapeShare *shared)
void * MemoryContextAlloc(MemoryContext context, Size size)
void MemoryContextReset(MemoryContext context)
void pfree(void *pointer)
Size GetMemoryChunkSpace(void *pointer)
void * palloc0(Size size)
MemoryContext CurrentMemoryContext
void MemoryContextDelete(MemoryContext context)
void * repalloc_huge(void *pointer, Size size)
void MemoryContextResetOnly(MemoryContext context)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define CHECK_FOR_INTERRUPTS()
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
const char * pg_rusage_show(const PGRUsage *ru0)
void pg_rusage_init(PGRUsage *ru0)
static int64 DatumGetInt64(Datum X)
static int32 DatumGetInt32(Datum X)
void SharedFileSetAttach(SharedFileSet *fileset, dsm_segment *seg)
void SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg)
Size add_size(Size s1, Size s2)
Size mul_size(Size s1, Size s2)
static int ApplySignedSortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
static int ApplyUnsignedSortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
static int ApplyInt32SortComparator(Datum datum1, bool isNull1, Datum datum2, bool isNull2, SortSupport ssup)
#define SpinLockInit(lock)
#define SpinLockRelease(lock)
#define SpinLockAcquire(lock)
TapeShare tapes[FLEXIBLE_ARRAY_MEMBER]
TuplesortMethod sortMethod
TuplesortSpaceType spaceType
LogicalTape ** inputTapes
LogicalTape ** outputTapes
TupSortStatus maxSpaceStatus
LogicalTape * result_tape
void tuplesort_rescan(Tuplesortstate *state)
void tuplesort_performsort(Tuplesortstate *state)
int tuplesort_merge_order(int64 allowedMem)
#define TAPE_BUFFER_OVERHEAD
static void tuplesort_heap_delete_top(Tuplesortstate *state)
#define INITIAL_MEMTUPSIZE
static unsigned int getlen(LogicalTape *tape, bool eofOK)
void tuplesort_initialize_shared(Sharedsort *shared, int nWorkers, dsm_segment *seg)
#define COMPARETUP(state, a, b)
static void selectnewtape(Tuplesortstate *state)
void tuplesort_reset(Tuplesortstate *state)
static void markrunend(LogicalTape *tape)
bool tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
static void free_sort_tuple(Tuplesortstate *state, SortTuple *stup)
#define REMOVEABBREV(state, stup, count)
static void reversedirection(Tuplesortstate *state)
#define USEMEM(state, amt)
static void tuplesort_heap_insert(Tuplesortstate *state, SortTuple *tuple)
int ssup_datum_signed_cmp(Datum x, Datum y, SortSupport ssup)
static bool grow_memtuples(Tuplesortstate *state)
int ssup_datum_unsigned_cmp(Datum x, Datum y, SortSupport ssup)
static void beginmerge(Tuplesortstate *state)
static void make_bounded_heap(Tuplesortstate *state)
bool tuplesort_used_bound(Tuplesortstate *state)
#define WRITETUP(state, tape, stup)
static void sort_bounded_heap(Tuplesortstate *state)
static int worker_get_identifier(Tuplesortstate *state)
static void mergeonerun(Tuplesortstate *state)
#define FREEMEM(state, amt)
static void inittapestate(Tuplesortstate *state, int maxTapes)
static void leader_takeover_tapes(Tuplesortstate *state)
Size tuplesort_estimate_shared(int nWorkers)
void tuplesort_get_stats(Tuplesortstate *state, TuplesortInstrumentation *stats)
Tuplesortstate * tuplesort_begin_common(int workMem, SortCoordinate coordinate, int sortopt)
static void tuplesort_sort_memtuples(Tuplesortstate *state)
void tuplesort_end(Tuplesortstate *state)
static void inittapes(Tuplesortstate *state, bool mergeruns)
void tuplesort_markpos(Tuplesortstate *state)
void tuplesort_puttuple_common(Tuplesortstate *state, SortTuple *tuple, bool useAbbrev, Size tuplen)
const char * tuplesort_space_type_name(TuplesortSpaceType t)
#define MERGE_BUFFER_SIZE
#define READTUP(state, stup, tape, len)
int ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup)
bool tuplesort_gettuple_common(Tuplesortstate *state, bool forward, SortTuple *stup)
static int64 merge_read_buffer_size(int64 avail_mem, int nInputTapes, int nInputRuns, int maxOutputTapes)
static bool mergereadnext(Tuplesortstate *state, LogicalTape *srcTape, SortTuple *stup)
static void tuplesort_updatemax(Tuplesortstate *state)
static void worker_freeze_result_tape(Tuplesortstate *state)
static pg_attribute_always_inline int qsort_tuple_signed_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state)
#define RELEASE_SLAB_SLOT(state, tuple)
void tuplesort_attach_shared(Sharedsort *shared, dsm_segment *seg)
static void worker_nomergeruns(Tuplesortstate *state)
const char * tuplesort_method_name(TuplesortMethod m)
static pg_attribute_always_inline int qsort_tuple_unsigned_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state)
static void tuplesort_heap_replace_top(Tuplesortstate *state, SortTuple *tuple)
void tuplesort_restorepos(Tuplesortstate *state)
static pg_attribute_always_inline int qsort_tuple_int32_compare(SortTuple *a, SortTuple *b, Tuplesortstate *state)
static void mergeruns(Tuplesortstate *state)
void * tuplesort_readtup_alloc(Tuplesortstate *state, Size tuplen)
static void tuplesort_begin_batch(Tuplesortstate *state)
void tuplesort_set_bound(Tuplesortstate *state, int64 bound)
static void init_slab_allocator(Tuplesortstate *state, int numSlots)
static bool consider_abort_common(Tuplesortstate *state)
static void tuplesort_free(Tuplesortstate *state)
static void dumptuples(Tuplesortstate *state, bool alltuples)
#define TupleSortUseBumpTupleCxt(opt)
#define TUPLESORT_RANDOMACCESS
#define TUPLESORT_ALLOWBOUNDED
@ SORT_TYPE_EXTERNAL_SORT
@ SORT_TYPE_TOP_N_HEAPSORT
@ SORT_TYPE_STILL_IN_PROGRESS
@ SORT_TYPE_EXTERNAL_MERGE
char buffer[SLAB_SLOT_SIZE]
union SlabSlot * nextfree