LCOV - differential code coverage report
Current view: top level - src/backend/utils/sort - tuplesort.c (source / functions) Coverage Total Hit UNC LBC UBC GBC GNC CBC DCB
Current: 1a1248818fb8b8b0353c292c632d6a6af77e8209 vs 8e82d6610e7280d7870c0c36ff1c797e3cfb3e09 Lines: 92.2 % 981 904 77 30 874 28
Current Date: 2026-10-12 11:56:10 +0200 Functions: 100.0 % 58 58 12 46 2
Baseline: lcov-20261012-baseline Branches: 66.8 % 690 461 1 1 227 1 17 443
Baseline Date: 2026-10-12 10:36:06 +0200 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 100.0 % 5 5 5
(30,360] days: 100.0 % 163 163 25 138
(360..) days: 90.5 % 813 736 77 736
Function coverage date bins:
(30,360] days: 100.0 % 8 8 4 4
(360..) days: 100.0 % 50 50 8 42
Branch coverage date bins:
(30,360] days: 91.2 % 102 93 1 1 7 17 76
(360..) days: 62.6 % 588 368 220 1 367

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * tuplesort.c
                                  4                 :                :  *    Generalized tuple sorting routines.
                                  5                 :                :  *
                                  6                 :                :  * This module provides a generalized facility for tuple sorting, which can be
                                  7                 :                :  * applied to different kinds of sortable objects.  Implementation of
                                  8                 :                :  * the particular sorting variants is given in tuplesortvariants.c.
                                  9                 :                :  * This module works efficiently for both small and large amounts
                                 10                 :                :  * of data.  Small amounts are sorted in-memory.  Large amounts are
                                 11                 :                :  * sorted using temporary files and a standard external sort
                                 12                 :                :  * algorithm.
                                 13                 :                :  *
                                 14                 :                :  * See Knuth, volume 3, for more than you want to know about external
                                 15                 :                :  * sorting algorithms.  The algorithm we use is a balanced k-way merge.
                                 16                 :                :  * Before PostgreSQL 15, we used the polyphase merge algorithm (Knuth's
                                 17                 :                :  * Algorithm 5.4.2D), but with modern hardware, a straightforward balanced
                                 18                 :                :  * merge is better.  Knuth is assuming that tape drives are expensive
                                 19                 :                :  * beasts, and in particular that there will always be many more runs than
                                 20                 :                :  * tape drives.  The polyphase merge algorithm was good at keeping all the
                                 21                 :                :  * tape drives busy, but in our implementation a "tape drive" doesn't cost
                                 22                 :                :  * much more than a few Kb of memory buffers, so we can afford to have
                                 23                 :                :  * lots of them.  In particular, if we can have as many tape drives as
                                 24                 :                :  * sorted runs, we can eliminate any repeated I/O at all.
                                 25                 :                :  *
                                 26                 :                :  * Historically, we divided the input into sorted runs using replacement
                                 27                 :                :  * selection, in the form of a priority tree implemented as a heap
                                 28                 :                :  * (essentially Knuth's Algorithm 5.2.3H), but now we always use quicksort
                                 29                 :                :  * or radix sort for run generation.
                                 30                 :                :  *
                                 31                 :                :  * The approximate amount of memory allowed for any one sort operation
                                 32                 :                :  * is specified in kilobytes by the caller (most pass work_mem).  Initially,
                                 33                 :                :  * we absorb tuples and simply store them in an unsorted array as long as
                                 34                 :                :  * we haven't exceeded workMem.  If we reach the end of the input without
                                 35                 :                :  * exceeding workMem, we sort the array in memory and subsequently return
                                 36                 :                :  * tuples just by scanning the tuple array sequentially.  If we do exceed
                                 37                 :                :  * workMem, we begin to emit tuples into sorted runs in temporary tapes.
                                 38                 :                :  * When tuples are dumped in batch after in-memory sorting, we begin a new run
                                 39                 :                :  * with a new output tape.  If we reach the max number of tapes, we write
                                 40                 :                :  * subsequent runs on the existing tapes in a round-robin fashion.  We will
                                 41                 :                :  * need multiple merge passes to finish the merge in that case.  After the
                                 42                 :                :  * end of the input is reached, we dump out remaining tuples in memory into
                                 43                 :                :  * a final run, then merge the runs.
                                 44                 :                :  *
                                 45                 :                :  * When merging runs, we use a heap containing just the frontmost tuple from
                                 46                 :                :  * each source run; we repeatedly output the smallest tuple and replace it
                                 47                 :                :  * with the next tuple from its source tape (if any).  When the heap empties,
                                 48                 :                :  * the merge is complete.  The basic merge algorithm thus needs very little
                                 49                 :                :  * memory --- only M tuples for an M-way merge, and M is constrained to a
                                 50                 :                :  * small number.  However, we can still make good use of our full workMem
                                 51                 :                :  * allocation by pre-reading additional blocks from each source tape.  Without
                                 52                 :                :  * prereading, our access pattern to the temporary file would be very erratic;
                                 53                 :                :  * on average we'd read one block from each of M source tapes during the same
                                 54                 :                :  * time that we're writing M blocks to the output tape, so there is no
                                 55                 :                :  * sequentiality of access at all, defeating the read-ahead methods used by
                                 56                 :                :  * most Unix kernels.  Worse, the output tape gets written into a very random
                                 57                 :                :  * sequence of blocks of the temp file, ensuring that things will be even
                                 58                 :                :  * worse when it comes time to read that tape.  A straightforward merge pass
                                 59                 :                :  * thus ends up doing a lot of waiting for disk seeks.  We can improve matters
                                 60                 :                :  * by prereading from each source tape sequentially, loading about workMem/M
                                 61                 :                :  * bytes from each tape in turn, and making the sequential blocks immediately
                                 62                 :                :  * available for reuse.  This approach helps to localize both read and write
                                 63                 :                :  * accesses.  The pre-reading is handled by logtape.c, we just tell it how
                                 64                 :                :  * much memory to use for the buffers.
                                 65                 :                :  *
                                 66                 :                :  * In the current code we determine the number of input tapes M on the basis
                                 67                 :                :  * of workMem: we want workMem/M to be large enough that we read a fair
                                 68                 :                :  * amount of data each time we read from a tape, so as to maintain the
                                 69                 :                :  * locality of access described above.  Nonetheless, with large workMem we
                                 70                 :                :  * can have many tapes.  The logical "tapes" are implemented by logtape.c,
                                 71                 :                :  * which avoids space wastage by recycling disk space as soon as each block
                                 72                 :                :  * is read from its "tape".
                                 73                 :                :  *
                                 74                 :                :  * When the caller requests random access to the sort result, we form
                                 75                 :                :  * the final sorted run on a logical tape which is then "frozen", so
                                 76                 :                :  * that we can access it randomly.  When the caller does not need random
                                 77                 :                :  * access, we return from tuplesort_performsort() as soon as we are down
                                 78                 :                :  * to one run per logical tape.  The final merge is then performed
                                 79                 :                :  * on-the-fly as the caller repeatedly calls tuplesort_getXXX; this
                                 80                 :                :  * saves one cycle of writing all the data out to disk and reading it in.
                                 81                 :                :  *
                                 82                 :                :  * This module supports parallel sorting.  Parallel sorts involve coordination
                                 83                 :                :  * among one or more worker processes, and a leader process, each with its own
                                 84                 :                :  * tuplesort state.  The leader process (or, more accurately, the
                                 85                 :                :  * Tuplesortstate associated with a leader process) creates a full tapeset
                                 86                 :                :  * consisting of worker tapes with one run to merge; a run for every
                                 87                 :                :  * worker process.  This is then merged.  Worker processes are guaranteed to
                                 88                 :                :  * produce exactly one output run from their partial input.
                                 89                 :                :  *
                                 90                 :                :  *
                                 91                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                 92                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 93                 :                :  *
                                 94                 :                :  * IDENTIFICATION
                                 95                 :                :  *    src/backend/utils/sort/tuplesort.c
                                 96                 :                :  *
                                 97                 :                :  *-------------------------------------------------------------------------
                                 98                 :                :  */
                                 99                 :                : 
                                100                 :                : #include "postgres.h"
                                101                 :                : 
                                102                 :                : #include <limits.h>
                                103                 :                : 
                                104                 :                : #include "commands/tablespace.h"
                                105                 :                : #include "miscadmin.h"
                                106                 :                : #include "pg_trace.h"
                                107                 :                : #include "port/atomics.h"
                                108                 :                : #include "port/pg_bitutils.h"
                                109                 :                : #include "storage/shmem.h"
                                110                 :                : #include "utils/guc.h"
                                111                 :                : #include "utils/memutils.h"
                                112                 :                : #include "utils/pg_rusage.h"
                                113                 :                : #include "utils/tuplesort.h"
                                114                 :                : 
                                115                 :                : /*
                                116                 :                :  * Initial size of memtuples array.  This must be more than
                                117                 :                :  * ALLOCSET_SEPARATE_THRESHOLD; see comments in grow_memtuples().  Clamp at
                                118                 :                :  * 1024 elements to avoid excessive reallocs.
                                119                 :                :  */
                                120                 :                : #define INITIAL_MEMTUPSIZE Max(1024, \
                                121                 :                :     ALLOCSET_SEPARATE_THRESHOLD / sizeof(SortTuple) + 1)
                                122                 :                : 
                                123                 :                : /* GUC variables */
                                124                 :                : bool        trace_sort = false;
                                125                 :                : 
                                126                 :                : #ifdef DEBUG_BOUNDED_SORT
                                127                 :                : bool        optimize_bounded_sort = true;
                                128                 :                : #endif
                                129                 :                : 
                                130                 :                : 
                                131                 :                : /*
                                132                 :                :  * During merge, we use a pre-allocated set of fixed-size slots to hold
                                133                 :                :  * tuples.  To avoid palloc/pfree overhead.
                                134                 :                :  *
                                135                 :                :  * Merge doesn't require a lot of memory, so we can afford to waste some,
                                136                 :                :  * by using gratuitously-sized slots.  If a tuple is larger than 1 kB, the
                                137                 :                :  * palloc() overhead is not significant anymore.
                                138                 :                :  *
                                139                 :                :  * 'nextfree' is valid when this chunk is in the free list.  When in use, the
                                140                 :                :  * slot holds a tuple.
                                141                 :                :  */
                                142                 :                : #define SLAB_SLOT_SIZE 1024
                                143                 :                : 
                                144                 :                : typedef union SlabSlot
                                145                 :                : {
                                146                 :                :     union SlabSlot *nextfree;
                                147                 :                :     char        buffer[SLAB_SLOT_SIZE];
                                148                 :                : } SlabSlot;
                                149                 :                : 
                                150                 :                : /*
                                151                 :                :  * Possible states of a Tuplesort object.  These denote the states that
                                152                 :                :  * persist between calls of Tuplesort routines.
                                153                 :                :  */
                                154                 :                : typedef enum
                                155                 :                : {
                                156                 :                :     TSS_INITIAL,                /* Loading tuples; still within memory limit */
                                157                 :                :     TSS_BOUNDED,                /* Loading tuples into bounded-size heap */
                                158                 :                :     TSS_BUILDRUNS,              /* Loading tuples; writing to tape */
                                159                 :                :     TSS_SORTEDINMEM,            /* Sort completed entirely in memory */
                                160                 :                :     TSS_SORTEDONTAPE,           /* Sort completed, final run is on tape */
                                161                 :                :     TSS_FINALMERGE,             /* Performing final merge on-the-fly */
                                162                 :                : } TupSortStatus;
                                163                 :                : 
                                164                 :                : /*
                                165                 :                :  * Parameters for calculation of number of tapes to use --- see inittapes()
                                166                 :                :  * and tuplesort_merge_order().
                                167                 :                :  *
                                168                 :                :  * In this calculation we assume that each tape will cost us about 1 blocks
                                169                 :                :  * worth of buffer space.  This ignores the overhead of all the other data
                                170                 :                :  * structures needed for each tape, but it's probably close enough.
                                171                 :                :  *
                                172                 :                :  * MERGE_BUFFER_SIZE is how much buffer space we'd like to allocate for each
                                173                 :                :  * input tape, for pre-reading (see discussion at top of file).  This is *in
                                174                 :                :  * addition to* the 1 block already included in TAPE_BUFFER_OVERHEAD.
                                175                 :                :  */
                                176                 :                : #define MINORDER        6       /* minimum merge order */
                                177                 :                : #define MAXORDER        500     /* maximum merge order */
                                178                 :                : #define TAPE_BUFFER_OVERHEAD        BLCKSZ
                                179                 :                : #define MERGE_BUFFER_SIZE           (BLCKSZ * 32)
                                180                 :                : 
                                181                 :                : 
                                182                 :                : /*
                                183                 :                :  * Private state of a Tuplesort operation.
                                184                 :                :  */
                                185                 :                : struct Tuplesortstate
                                186                 :                : {
                                187                 :                :     TuplesortPublic base;
                                188                 :                :     TupSortStatus status;       /* enumerated value as shown above */
                                189                 :                :     bool        bounded;        /* did caller specify a maximum number of
                                190                 :                :                                  * tuples to return? */
                                191                 :                :     bool        boundUsed;      /* true if we made use of a bounded heap */
                                192                 :                :     int         bound;          /* if bounded, the maximum number of tuples */
                                193                 :                :     int64       tupleMem;       /* memory consumed by individual tuples.
                                194                 :                :                                  * storing this separately from what we track
                                195                 :                :                                  * in availMem allows us to subtract the
                                196                 :                :                                  * memory consumed by all tuples when dumping
                                197                 :                :                                  * tuples to tape */
                                198                 :                :     int64       availMem;       /* remaining memory available, in bytes */
                                199                 :                :     int64       allowedMem;     /* total memory allowed, in bytes */
                                200                 :                :     int         maxTapes;       /* max number of input tapes to merge in each
                                201                 :                :                                  * pass */
                                202                 :                :     int64       maxSpace;       /* maximum amount of space occupied among sort
                                203                 :                :                                  * of groups, either in-memory or on-disk */
                                204                 :                :     bool        isMaxSpaceDisk; /* true when maxSpace tracks on-disk space,
                                205                 :                :                                  * false means in-memory */
                                206                 :                :     TupSortStatus maxSpaceStatus;   /* sort status when maxSpace was reached */
                                207                 :                :     LogicalTapeSet *tapeset;    /* logtape.c object for tapes in a temp file */
                                208                 :                : 
                                209                 :                :     /*
                                210                 :                :      * This array holds the tuples now in sort memory.  If we are in state
                                211                 :                :      * INITIAL, the tuples are in no particular order; if we are in state
                                212                 :                :      * SORTEDINMEM, the tuples are in final sorted order; in states BUILDRUNS
                                213                 :                :      * and FINALMERGE, the tuples are organized in "heap" order per Algorithm
                                214                 :                :      * H.  In state SORTEDONTAPE, the array is not used.
                                215                 :                :      */
                                216                 :                :     SortTuple  *memtuples;      /* array of SortTuple structs */
                                217                 :                :     int         memtupcount;    /* number of tuples currently present */
                                218                 :                :     int         memtupsize;     /* allocated length of memtuples array */
                                219                 :                :     bool        growmemtuples;  /* memtuples' growth still underway? */
                                220                 :                : 
                                221                 :                :     /*
                                222                 :                :      * Memory for tuples is sometimes allocated using a simple slab allocator,
                                223                 :                :      * rather than with palloc().  Currently, we switch to slab allocation
                                224                 :                :      * when we start merging.  Merging only needs to keep a small, fixed
                                225                 :                :      * number of tuples in memory at any time, so we can avoid the
                                226                 :                :      * palloc/pfree overhead by recycling a fixed number of fixed-size slots
                                227                 :                :      * to hold the tuples.
                                228                 :                :      *
                                229                 :                :      * For the slab, we use one large allocation, divided into SLAB_SLOT_SIZE
                                230                 :                :      * slots.  The allocation is sized to have one slot per tape, plus one
                                231                 :                :      * additional slot.  We need that many slots to hold all the tuples kept
                                232                 :                :      * in the heap during merge, plus the one we have last returned from the
                                233                 :                :      * sort, with tuplesort_gettuple.
                                234                 :                :      *
                                235                 :                :      * Initially, all the slots are kept in a linked list of free slots.  When
                                236                 :                :      * a tuple is read from a tape, it is put to the next available slot, if
                                237                 :                :      * it fits.  If the tuple is larger than SLAB_SLOT_SIZE, it is palloc'd
                                238                 :                :      * instead.
                                239                 :                :      *
                                240                 :                :      * When we're done processing a tuple, we return the slot back to the free
                                241                 :                :      * list, or pfree() if it was palloc'd.  We know that a tuple was
                                242                 :                :      * allocated from the slab, if its pointer value is between
                                243                 :                :      * slabMemoryBegin and -End.
                                244                 :                :      *
                                245                 :                :      * When the slab allocator is used, the USEMEM/LACKMEM mechanism of
                                246                 :                :      * tracking memory usage is not used.
                                247                 :                :      */
                                248                 :                :     bool        slabAllocatorUsed;
                                249                 :                : 
                                250                 :                :     char       *slabMemoryBegin;    /* beginning of slab memory arena */
                                251                 :                :     char       *slabMemoryEnd;  /* end of slab memory arena */
                                252                 :                :     SlabSlot   *slabFreeHead;   /* head of free list */
                                253                 :                : 
                                254                 :                :     /* Memory used for input and output tape buffers. */
                                255                 :                :     size_t      tape_buffer_mem;
                                256                 :                : 
                                257                 :                :     /*
                                258                 :                :      * When we return a tuple to the caller in tuplesort_gettuple_XXX, that
                                259                 :                :      * came from a tape (that is, in TSS_SORTEDONTAPE or TSS_FINALMERGE
                                260                 :                :      * modes), we remember the tuple in 'lastReturnedTuple', so that we can
                                261                 :                :      * recycle the memory on next gettuple call.
                                262                 :                :      */
                                263                 :                :     void       *lastReturnedTuple;
                                264                 :                : 
                                265                 :                :     /*
                                266                 :                :      * While building initial runs, this is the current output run number.
                                267                 :                :      * Afterwards, it is the number of initial runs we made.
                                268                 :                :      */
                                269                 :                :     int         currentRun;
                                270                 :                : 
                                271                 :                :     /*
                                272                 :                :      * Logical tapes, for merging.
                                273                 :                :      *
                                274                 :                :      * The initial runs are written in the output tapes.  In each merge pass,
                                275                 :                :      * the output tapes of the previous pass become the input tapes, and new
                                276                 :                :      * output tapes are created as needed.  When nInputTapes equals
                                277                 :                :      * nInputRuns, there is only one merge pass left.
                                278                 :                :      */
                                279                 :                :     LogicalTape **inputTapes;
                                280                 :                :     int         nInputTapes;
                                281                 :                :     int         nInputRuns;
                                282                 :                : 
                                283                 :                :     LogicalTape **outputTapes;
                                284                 :                :     int         nOutputTapes;
                                285                 :                :     int         nOutputRuns;
                                286                 :                : 
                                287                 :                :     LogicalTape *destTape;      /* current output tape */
                                288                 :                : 
                                289                 :                :     /*
                                290                 :                :      * These variables are used after completion of sorting to keep track of
                                291                 :                :      * the next tuple to return.  (In the tape case, the tape's current read
                                292                 :                :      * position is also critical state.)
                                293                 :                :      */
                                294                 :                :     LogicalTape *result_tape;   /* actual tape of finished output */
                                295                 :                :     int         current;        /* array index (only used if SORTEDINMEM) */
                                296                 :                :     bool        eof_reached;    /* reached EOF (needed for cursors) */
                                297                 :                : 
                                298                 :                :     /* markpos_xxx holds marked position for mark and restore */
                                299                 :                :     int64       markpos_block;  /* tape block# (only used if SORTEDONTAPE) */
                                300                 :                :     int         markpos_offset; /* saved "current", or offset in tape block */
                                301                 :                :     bool        markpos_eof;    /* saved "eof_reached" */
                                302                 :                : 
                                303                 :                :     /*
                                304                 :                :      * These variables are used during parallel sorting.
                                305                 :                :      *
                                306                 :                :      * worker is our worker identifier.  Follows the general convention that
                                307                 :                :      * -1 value relates to a leader tuplesort, and values >= 0 worker
                                308                 :                :      * tuplesorts. (-1 can also be a serial tuplesort.)
                                309                 :                :      *
                                310                 :                :      * shared is mutable shared memory state, which is used to coordinate
                                311                 :                :      * parallel sorts.
                                312                 :                :      *
                                313                 :                :      * nParticipants is the number of worker Tuplesortstates known by the
                                314                 :                :      * leader to have actually been launched, which implies that they must
                                315                 :                :      * finish a run that the leader needs to merge.  Typically includes a
                                316                 :                :      * worker state held by the leader process itself.  Set in the leader
                                317                 :                :      * Tuplesortstate only.
                                318                 :                :      */
                                319                 :                :     int         worker;
                                320                 :                :     Sharedsort *shared;
                                321                 :                :     int         nParticipants;
                                322                 :                : 
                                323                 :                :     /*
                                324                 :                :      * Additional state for managing "abbreviated key" sortsupport routines
                                325                 :                :      * (which currently may be used by all cases except the hash index case).
                                326                 :                :      * Tracks the intervals at which the optimization's effectiveness is
                                327                 :                :      * tested.
                                328                 :                :      */
                                329                 :                :     int64       abbrevNext;     /* Tuple # at which to next check
                                330                 :                :                                  * applicability */
                                331                 :                : 
                                332                 :                :     /*
                                333                 :                :      * Resource snapshot for time of sort start.
                                334                 :                :      */
                                335                 :                :     PGRUsage    ru_start;
                                336                 :                : };
                                337                 :                : 
                                338                 :                : /*
                                339                 :                :  * Private mutable state of tuplesort-parallel-operation.  This is allocated
                                340                 :                :  * in shared memory.
                                341                 :                :  */
                                342                 :                : struct Sharedsort
                                343                 :                : {
                                344                 :                :     /*
                                345                 :                :      * currentWorker generates ordinal identifier numbers for parallel sort
                                346                 :                :      * workers.  These start from 0, and are always gapless.
                                347                 :                :      *
                                348                 :                :      * Workers increment workersFinished to indicate having finished.  If this
                                349                 :                :      * is equal to state.nParticipants within the leader, leader is ready to
                                350                 :                :      * merge worker runs.
                                351                 :                :      */
                                352                 :                :     pg_atomic_uint32 currentWorker;
                                353                 :                :     pg_atomic_uint32 workersFinished;
                                354                 :                : 
                                355                 :                :     /* Temporary file space */
                                356                 :                :     SharedFileSet fileset;
                                357                 :                : 
                                358                 :                :     /* Size of tapes flexible array */
                                359                 :                :     int         nTapes;
                                360                 :                : 
                                361                 :                :     /*
                                362                 :                :      * Tapes array used by workers to report back information needed by the
                                363                 :                :      * leader to concatenate all worker tapes into one for merging
                                364                 :                :      */
                                365                 :                :     TapeShare   tapes[FLEXIBLE_ARRAY_MEMBER];
                                366                 :                : };
                                367                 :                : 
                                368                 :                : /*
                                369                 :                :  * Is the given tuple allocated from the slab memory arena?
                                370                 :                :  */
                                371                 :                : #define IS_SLAB_SLOT(state, tuple) \
                                372                 :                :     ((char *) (tuple) >= (state)->slabMemoryBegin && \
                                373                 :                :      (char *) (tuple) < (state)->slabMemoryEnd)
                                374                 :                : 
                                375                 :                : /*
                                376                 :                :  * Return the given tuple to the slab memory free list, or free it
                                377                 :                :  * if it was palloc'd.
                                378                 :                :  */
                                379                 :                : #define RELEASE_SLAB_SLOT(state, tuple) \
                                380                 :                :     do { \
                                381                 :                :         SlabSlot *buf = (SlabSlot *) tuple; \
                                382                 :                :         \
                                383                 :                :         if (IS_SLAB_SLOT((state), buf)) \
                                384                 :                :         { \
                                385                 :                :             buf->nextfree = (state)->slabFreeHead; \
                                386                 :                :             (state)->slabFreeHead = buf; \
                                387                 :                :         } else \
                                388                 :                :             pfree(buf); \
                                389                 :                :     } while(0)
                                390                 :                : 
                                391                 :                : #define REMOVEABBREV(state,stup,count)  ((*(state)->base.removeabbrev) (state, stup, count))
                                392                 :                : #define COMPARETUP(state,a,b)   ((*(state)->base.comparetup) (a, b, state))
                                393                 :                : #define WRITETUP(state,tape,stup)   ((*(state)->base.writetup) (state, tape, stup))
                                394                 :                : #define READTUP(state,stup,tape,len) ((*(state)->base.readtup) (state, stup, tape, len))
                                395                 :                : #define FREESTATE(state)    ((state)->base.freestate ? (*(state)->base.freestate) (state) : (void) 0)
                                396                 :                : #define LACKMEM(state)      ((state)->availMem < 0 && !(state)->slabAllocatorUsed)
                                397                 :                : #define USEMEM(state,amt)   ((state)->availMem -= (amt))
                                398                 :                : #define FREEMEM(state,amt)  ((state)->availMem += (amt))
                                399                 :                : #define SERIAL(state)       ((state)->shared == NULL)
                                400                 :                : #define WORKER(state)       ((state)->shared && (state)->worker != -1)
                                401                 :                : #define LEADER(state)       ((state)->shared && (state)->worker == -1)
                                402                 :                : 
                                403                 :                : /*
                                404                 :                :  * NOTES about on-tape representation of tuples:
                                405                 :                :  *
                                406                 :                :  * We require the first "unsigned int" of a stored tuple to be the total size
                                407                 :                :  * on-tape of the tuple, including itself (so it is never zero; an all-zero
                                408                 :                :  * unsigned int is used to delimit runs).  The remainder of the stored tuple
                                409                 :                :  * may or may not match the in-memory representation of the tuple ---
                                410                 :                :  * any conversion needed is the job of the writetup and readtup routines.
                                411                 :                :  *
                                412                 :                :  * If state->sortopt contains TUPLESORT_RANDOMACCESS, then the stored
                                413                 :                :  * representation of the tuple must be followed by another "unsigned int" that
                                414                 :                :  * is a copy of the length --- so the total tape space used is actually
                                415                 :                :  * sizeof(unsigned int) more than the stored length value.  This allows
                                416                 :                :  * read-backwards.  When the random access flag was not specified, the
                                417                 :                :  * write/read routines may omit the extra length word.
                                418                 :                :  *
                                419                 :                :  * writetup is expected to write both length words as well as the tuple
                                420                 :                :  * data.  When readtup is called, the tape is positioned just after the
                                421                 :                :  * front length word; readtup must read the tuple data and advance past
                                422                 :                :  * the back length word (if present).
                                423                 :                :  *
                                424                 :                :  * The write/read routines can make use of the tuple description data
                                425                 :                :  * stored in the Tuplesortstate record, if needed.  They are also expected
                                426                 :                :  * to adjust state->availMem by the amount of memory space (not tape space!)
                                427                 :                :  * released or consumed.  There is no error return from either writetup
                                428                 :                :  * or readtup; they should ereport() on failure.
                                429                 :                :  *
                                430                 :                :  *
                                431                 :                :  * NOTES about memory consumption calculations:
                                432                 :                :  *
                                433                 :                :  * We count space allocated for tuples against the workMem limit, plus
                                434                 :                :  * the space used by the variable-size memtuples array.  Fixed-size space
                                435                 :                :  * is not counted; it's small enough to not be interesting.
                                436                 :                :  *
                                437                 :                :  * Note that we count actual space used (as shown by GetMemoryChunkSpace)
                                438                 :                :  * rather than the originally-requested size.  This is important since
                                439                 :                :  * palloc can add substantial overhead.  It's not a complete answer since
                                440                 :                :  * we won't count any wasted space in palloc allocation blocks, but it's
                                441                 :                :  * a lot better than what we were doing before 7.3.  As of 9.6, a
                                442                 :                :  * separate memory context is used for caller passed tuples.  Resetting
                                443                 :                :  * it at certain key increments significantly ameliorates fragmentation.
                                444                 :                :  * readtup routines use the slab allocator (they cannot use
                                445                 :                :  * the reset context because it gets deleted at the point that merging
                                446                 :                :  * begins).
                                447                 :                :  */
                                448                 :                : 
                                449                 :                : 
                                450                 :                : static void tuplesort_begin_batch(Tuplesortstate *state);
                                451                 :                : static bool consider_abort_common(Tuplesortstate *state);
                                452                 :                : static void inittapes(Tuplesortstate *state, bool mergeruns);
                                453                 :                : static void inittapestate(Tuplesortstate *state, int maxTapes);
                                454                 :                : static void selectnewtape(Tuplesortstate *state);
                                455                 :                : static void init_slab_allocator(Tuplesortstate *state, int numSlots);
                                456                 :                : static void mergeruns(Tuplesortstate *state);
                                457                 :                : static void mergeonerun(Tuplesortstate *state);
                                458                 :                : static void beginmerge(Tuplesortstate *state);
                                459                 :                : static bool mergereadnext(Tuplesortstate *state, LogicalTape *srcTape, SortTuple *stup);
                                460                 :                : static void dumptuples(Tuplesortstate *state, bool alltuples);
                                461                 :                : static void make_bounded_heap(Tuplesortstate *state);
                                462                 :                : static void sort_bounded_heap(Tuplesortstate *state);
                                463                 :                : static void tuplesort_sort_memtuples(Tuplesortstate *state);
                                464                 :                : static void tuplesort_heap_insert(Tuplesortstate *state, SortTuple *tuple);
                                465                 :                : static void tuplesort_heap_replace_top(Tuplesortstate *state, SortTuple *tuple);
                                466                 :                : static void tuplesort_heap_delete_top(Tuplesortstate *state);
                                467                 :                : static void reversedirection(Tuplesortstate *state);
                                468                 :                : static unsigned int getlen(LogicalTape *tape, bool eofOK);
                                469                 :                : static void markrunend(LogicalTape *tape);
                                470                 :                : static int  worker_get_identifier(Tuplesortstate *state);
                                471                 :                : static void worker_freeze_result_tape(Tuplesortstate *state);
                                472                 :                : static void worker_nomergeruns(Tuplesortstate *state);
                                473                 :                : static void leader_takeover_tapes(Tuplesortstate *state);
                                474                 :                : static void free_sort_tuple(Tuplesortstate *state, SortTuple *stup);
                                475                 :                : static void tuplesort_free(Tuplesortstate *state);
                                476                 :                : static void tuplesort_updatemax(Tuplesortstate *state);
                                477                 :                : 
                                478                 :                : 
                                479                 :                : /*
                                480                 :                :  * Special versions of qsort just for SortTuple objects.  qsort_tuple() sorts
                                481                 :                :  * any variant of SortTuples, using the appropriate comparetup function.
                                482                 :                :  * qsort_ssup() is specialized for the case where the comparetup function
                                483                 :                :  * reduces to ApplySortComparator(), that is single-key MinimalTuple sorts
                                484                 :                :  * and Datum sorts.
                                485                 :                :  */
                                486                 :                : 
                                487                 :                : #define ST_SORT qsort_tuple
                                488                 :                : #define ST_ELEMENT_TYPE SortTuple
                                489                 :                : #define ST_COMPARE_RUNTIME_POINTER
                                490                 :                : #define ST_COMPARE_ARG_TYPE Tuplesortstate
                                491                 :                : #define ST_CHECK_FOR_INTERRUPTS
                                492                 :                : #define ST_SCOPE static
                                493                 :                : #define ST_DECLARE
                                494                 :                : #define ST_DEFINE
                                495                 :                : #include "lib/sort_template.h"
                                496                 :                : 
                                497                 :                : #define ST_SORT qsort_ssup
                                498                 :                : #define ST_ELEMENT_TYPE SortTuple
                                499                 :                : #define ST_COMPARE(a, b, ssup) \
                                500                 :                :     ApplySortComparator((a)->datum1, (a)->isnull1, \
                                501                 :                :                         (b)->datum1, (b)->isnull1, (ssup))
                                502                 :                : #define ST_COMPARE_ARG_TYPE SortSupportData
                                503                 :                : #define ST_CHECK_FOR_INTERRUPTS
                                504                 :                : #define ST_SCOPE static
                                505                 :                : #define ST_DEFINE
                                506                 :                : #include "lib/sort_template.h"
                                507                 :                : 
                                508                 :                : /* state for radix sort */
                                509                 :                : typedef struct RadixSortInfo
                                510                 :                : {
                                511                 :                :     union
                                512                 :                :     {
                                513                 :                :         size_t      count;
                                514                 :                :         size_t      offset;
                                515                 :                :     };
                                516                 :                :     size_t      next_offset;
                                517                 :                : } RadixSortInfo;
                                518                 :                : 
                                519                 :                : /*
                                520                 :                :  * Threshold below which qsort_tuple() is generally faster than a radix sort.
                                521                 :                :  */
                                522                 :                : #define QSORT_THRESHOLD 40
                                523                 :                : 
                                524                 :                : 
                                525                 :                : /*
                                526                 :                :  *      tuplesort_begin_xxx
                                527                 :                :  *
                                528                 :                :  * Initialize for a tuple sort operation.
                                529                 :                :  *
                                530                 :                :  * After calling tuplesort_begin, the caller should call tuplesort_putXXX
                                531                 :                :  * zero or more times, then call tuplesort_performsort when all the tuples
                                532                 :                :  * have been supplied.  After performsort, retrieve the tuples in sorted
                                533                 :                :  * order by calling tuplesort_getXXX until it returns false/NULL.  (If random
                                534                 :                :  * access was requested, rescan, markpos, and restorepos can also be called.)
                                535                 :                :  * Call tuplesort_end to terminate the operation and release memory/disk space.
                                536                 :                :  *
                                537                 :                :  * Each variant of tuplesort_begin has a workMem parameter specifying the
                                538                 :                :  * maximum number of kilobytes of RAM to use before spilling data to disk.
                                539                 :                :  * (The normal value of this parameter is work_mem, but some callers use
                                540                 :                :  * other values.)  Each variant also has a sortopt which is a bitmask of
                                541                 :                :  * sort options.  See TUPLESORT_* definitions in tuplesort.h
                                542                 :                :  */
                                543                 :                : 
                                544                 :                : Tuplesortstate *
 1652 drowley@postgresql.o      545                 :CBC      170552 : tuplesort_begin_common(int workMem, SortCoordinate coordinate, int sortopt)
                                546                 :                : {
                                547                 :                :     Tuplesortstate *state;
                                548                 :                :     MemoryContext maincontext;
                                549                 :                :     MemoryContext sortcontext;
                                550                 :                :     MemoryContext oldcontext;
                                551                 :                : 
                                552                 :                :     /* See leader_takeover_tapes() remarks on random access support */
                                553   [ +  +  -  + ]:         170552 :     if (coordinate && (sortopt & TUPLESORT_RANDOMACCESS))
 3174 rhaas@postgresql.org      554         [ #  # ]:UBC           0 :         elog(ERROR, "random access disallowed under parallel sort");
                                555                 :                : 
                                556                 :                :     /*
                                557                 :                :      * Memory context surviving tuplesort_reset.  This memory context holds
                                558                 :                :      * data which is useful to keep while sorting multiple similar batches.
                                559                 :                :      */
 2380 tomas.vondra@postgre      560                 :CBC      170552 :     maincontext = AllocSetContextCreate(CurrentMemoryContext,
                                561                 :                :                                         "TupleSort main",
                                562                 :                :                                         ALLOCSET_DEFAULT_SIZES);
                                563                 :                : 
                                564                 :                :     /*
                                565                 :                :      * Create a working memory context for one sort operation.  The content of
                                566                 :                :      * this context is deleted by tuplesort_reset.
                                567                 :                :      */
                                568                 :         170552 :     sortcontext = AllocSetContextCreate(maincontext,
                                569                 :                :                                         "TupleSort sort",
                                570                 :                :                                         ALLOCSET_DEFAULT_SIZES);
                                571                 :                : 
                                572                 :                :     /*
                                573                 :                :      * Additionally a working memory context for tuples is setup in
                                574                 :                :      * tuplesort_begin_batch.
                                575                 :                :      */
                                576                 :                : 
                                577                 :                :     /*
                                578                 :                :      * Make the Tuplesortstate within the per-sortstate context.  This way, we
                                579                 :                :      * don't need a separate pfree() operation for it at shutdown.
                                580                 :                :      */
                                581                 :         170552 :     oldcontext = MemoryContextSwitchTo(maincontext);
                                582                 :                : 
  306 michael@paquier.xyz       583                 :         170552 :     state = palloc0_object(Tuplesortstate);
                                584                 :                : 
 7679 tgl@sss.pgh.pa.us         585         [ -  + ]:         170552 :     if (trace_sort)
 7679 tgl@sss.pgh.pa.us         586                 :UBC           0 :         pg_rusage_init(&state->ru_start);
                                587                 :                : 
 1538 akorotkov@postgresql      588                 :CBC      170552 :     state->base.sortopt = sortopt;
                                589                 :         170552 :     state->base.tuples = true;
                                590                 :         170552 :     state->abbrevNext = 10;
                                591                 :                : 
                                592                 :                :     /*
                                593                 :                :      * workMem is forced to be at least 64KB, the current minimum valid value
                                594                 :                :      * for the work_mem GUC.  This is a defense against parallel sort callers
                                595                 :                :      * that divide out memory among many workers in a way that leaves each
                                596                 :                :      * with very little memory.
                                597                 :                :      */
 3174 rhaas@postgresql.org      598                 :         170552 :     state->allowedMem = Max(workMem, 64) * (int64) 1024;
 1538 akorotkov@postgresql      599                 :         170552 :     state->base.sortcontext = sortcontext;
                                600                 :         170552 :     state->base.maincontext = maincontext;
                                601                 :                : 
 2380 tomas.vondra@postgre      602                 :         170552 :     state->memtupsize = INITIAL_MEMTUPSIZE;
                                603                 :         170552 :     state->memtuples = NULL;
                                604                 :                : 
                                605                 :                :     /*
                                606                 :                :      * After all of the other non-parallel-related state, we setup all of the
                                607                 :                :      * state needed for each batch.
                                608                 :                :      */
                                609                 :         170552 :     tuplesort_begin_batch(state);
                                610                 :                : 
                                611                 :                :     /*
                                612                 :                :      * Initialize parallel-related state based on coordination information
                                613                 :                :      * from caller
                                614                 :                :      */
 3174 rhaas@postgresql.org      615         [ +  + ]:         170552 :     if (!coordinate)
                                616                 :                :     {
                                617                 :                :         /* Serial sort */
                                618                 :         169995 :         state->shared = NULL;
                                619                 :         169995 :         state->worker = -1;
                                620                 :         169995 :         state->nParticipants = -1;
                                621                 :                :     }
                                622         [ +  + ]:            557 :     else if (coordinate->isWorker)
                                623                 :                :     {
                                624                 :                :         /* Parallel worker produces exactly one final run from all input */
                                625                 :            379 :         state->shared = coordinate->sharedsort;
                                626                 :            379 :         state->worker = worker_get_identifier(state);
                                627                 :            379 :         state->nParticipants = -1;
                                628                 :                :     }
                                629                 :                :     else
                                630                 :                :     {
                                631                 :                :         /* Parallel leader state only used for final merge */
                                632                 :            178 :         state->shared = coordinate->sharedsort;
                                633                 :            178 :         state->worker = -1;
                                634                 :            178 :         state->nParticipants = coordinate->nParticipants;
                                635         [ -  + ]:            178 :         Assert(state->nParticipants >= 1);
                                636                 :                :     }
                                637                 :                : 
 7533 tgl@sss.pgh.pa.us         638                 :         170552 :     MemoryContextSwitchTo(oldcontext);
                                639                 :                : 
 9857                           640                 :         170552 :     return state;
                                641                 :                : }
                                642                 :                : 
                                643                 :                : /*
                                644                 :                :  *      tuplesort_begin_batch
                                645                 :                :  *
                                646                 :                :  * Setup, or reset, all state need for processing a new set of tuples with this
                                647                 :                :  * sort state. Called both from tuplesort_begin_common (the first time sorting
                                648                 :                :  * with this sort state) and tuplesort_reset (for subsequent usages).
                                649                 :                :  */
                                650                 :                : static void
 2380 tomas.vondra@postgre      651                 :         172679 : tuplesort_begin_batch(Tuplesortstate *state)
                                652                 :                : {
                                653                 :                :     MemoryContext oldcontext;
                                654                 :                : 
 1538 akorotkov@postgresql      655                 :         172679 :     oldcontext = MemoryContextSwitchTo(state->base.maincontext);
                                656                 :                : 
                                657                 :                :     /*
                                658                 :                :      * Caller tuple (e.g. IndexTuple) memory context.
                                659                 :                :      *
                                660                 :                :      * A dedicated child context used exclusively for caller passed tuples
                                661                 :                :      * eases memory management.  Resetting at key points reduces
                                662                 :                :      * fragmentation. Note that the memtuples array of SortTuples is allocated
                                663                 :                :      * in the parent context, not this context, because there is no need to
                                664                 :                :      * free memtuples early.  For bounded sorts, tuples may be pfreed in any
                                665                 :                :      * order, so we use a regular aset.c context so that it can make use of
                                666                 :                :      * free'd memory.  When the sort is not bounded, we make use of a bump.c
                                667                 :                :      * context as this keeps allocations more compact with less wastage.
                                668                 :                :      * Allocations are also slightly more CPU efficient.
                                669                 :                :      */
  917 drowley@postgresql.o      670         [ +  + ]:         172679 :     if (TupleSortUseBumpTupleCxt(state->base.sortopt))
                                671                 :         171785 :         state->base.tuplecontext = BumpContextCreate(state->base.sortcontext,
                                672                 :                :                                                      "Caller tuples",
                                673                 :                :                                                      ALLOCSET_DEFAULT_SIZES);
                                674                 :                :     else
 1538 akorotkov@postgresql      675                 :            894 :         state->base.tuplecontext = AllocSetContextCreate(state->base.sortcontext,
                                676                 :                :                                                          "Caller tuples",
                                677                 :                :                                                          ALLOCSET_DEFAULT_SIZES);
                                678                 :                : 
                                679                 :                : 
 2380 tomas.vondra@postgre      680                 :         172679 :     state->status = TSS_INITIAL;
                                681                 :         172679 :     state->bounded = false;
                                682                 :         172679 :     state->boundUsed = false;
                                683                 :                : 
                                684                 :         172679 :     state->availMem = state->allowedMem;
                                685                 :                : 
                                686                 :         172679 :     state->tapeset = NULL;
                                687                 :                : 
                                688                 :         172679 :     state->memtupcount = 0;
                                689                 :                : 
                                690                 :         172679 :     state->growmemtuples = true;
                                691                 :         172679 :     state->slabAllocatorUsed = false;
                                692   [ +  +  +  + ]:         172679 :     if (state->memtuples != NULL && state->memtupsize != INITIAL_MEMTUPSIZE)
                                693                 :                :     {
                                694                 :             96 :         pfree(state->memtuples);
                                695                 :             96 :         state->memtuples = NULL;
                                696                 :             96 :         state->memtupsize = INITIAL_MEMTUPSIZE;
                                697                 :                :     }
                                698         [ +  + ]:         172679 :     if (state->memtuples == NULL)
                                699                 :                :     {
   56 michael@paquier.xyz       700                 :GNC      170648 :         state->memtuples = palloc_array(SortTuple, state->memtupsize);
 2380 tomas.vondra@postgre      701                 :CBC      170648 :         USEMEM(state, GetMemoryChunkSpace(state->memtuples));
                                702                 :                :     }
                                703                 :                : 
                                704                 :                :     /* workMem must be large enough for the minimal memtuples array */
                                705   [ -  +  -  - ]:         172679 :     if (LACKMEM(state))
 2380 tomas.vondra@postgre      706         [ #  # ]:UBC           0 :         elog(ERROR, "insufficient memory allowed for sort");
                                707                 :                : 
 2380 tomas.vondra@postgre      708                 :CBC      172679 :     state->currentRun = 0;
                                709                 :                : 
                                710                 :                :     /*
                                711                 :                :      * Tape variables (inputTapes, outputTapes, etc.) will be initialized by
                                712                 :                :      * inittapes(), if needed.
                                713                 :                :      */
                                714                 :                : 
 1820 heikki.linnakangas@i      715                 :         172679 :     state->result_tape = NULL;   /* flag that result tape has not been formed */
                                716                 :                : 
 2380 tomas.vondra@postgre      717                 :         172679 :     MemoryContextSwitchTo(oldcontext);
                                718                 :         172679 : }
                                719                 :                : 
                                720                 :                : /*
                                721                 :                :  * tuplesort_set_bound
                                722                 :                :  *
                                723                 :                :  *  Advise tuplesort that at most the first N result tuples are required.
                                724                 :                :  *
                                725                 :                :  * Must be called before inserting any tuples.  (Actually, we could allow it
                                726                 :                :  * as long as the sort hasn't spilled to disk, but there seems no need for
                                727                 :                :  * delayed calls at the moment.)
                                728                 :                :  *
                                729                 :                :  * This is a hint only. The tuplesort may still return more tuples than
                                730                 :                :  * requested.  Parallel leader tuplesorts will always ignore the hint.
                                731                 :                :  */
                                732                 :                : void
 7101 tgl@sss.pgh.pa.us         733                 :            805 : tuplesort_set_bound(Tuplesortstate *state, int64 bound)
                                734                 :                : {
                                735                 :                :     /* Assert we're called before loading any tuples */
 2587 alvherre@alvh.no-ip.      736   [ +  -  -  + ]:            805 :     Assert(state->status == TSS_INITIAL && state->memtupcount == 0);
                                737                 :                :     /* Assert we allow bounded sorts */
 1538 akorotkov@postgresql      738         [ -  + ]:            805 :     Assert(state->base.sortopt & TUPLESORT_ALLOWBOUNDED);
                                739                 :                :     /* Can't set the bound twice, either */
 7101 tgl@sss.pgh.pa.us         740         [ -  + ]:            805 :     Assert(!state->bounded);
                                741                 :                :     /* Also, this shouldn't be called in a parallel worker */
 3174 rhaas@postgresql.org      742   [ -  +  -  - ]:            805 :     Assert(!WORKER(state));
                                743                 :                : 
                                744                 :                :     /* Parallel leader allows but ignores hint */
 2586 tgl@sss.pgh.pa.us         745   [ -  +  -  - ]:            805 :     if (LEADER(state))
 2586 tgl@sss.pgh.pa.us         746                 :UBC           0 :         return;
                                747                 :                : 
                                748                 :                : #ifdef DEBUG_BOUNDED_SORT
                                749                 :                :     /* Honor GUC setting that disables the feature (for easy testing) */
                                750                 :                :     if (!optimize_bounded_sort)
                                751                 :                :         return;
                                752                 :                : #endif
                                753                 :                : 
                                754                 :                :     /* We want to be able to compute bound * 2, so limit the setting */
 6906 bruce@momjian.us          755         [ -  + ]:CBC         805 :     if (bound > (int64) (INT_MAX / 2))
 7101 tgl@sss.pgh.pa.us         756                 :UBC           0 :         return;
                                757                 :                : 
 7101 tgl@sss.pgh.pa.us         758                 :CBC         805 :     state->bounded = true;
                                759                 :            805 :     state->bound = (int) bound;
                                760                 :                : 
                                761                 :                :     /*
                                762                 :                :      * Bounded sorts are not an effective target for abbreviated key
                                763                 :                :      * optimization.  Disable by setting state to be consistent with no
                                764                 :                :      * abbreviation support.
                                765                 :                :      */
 1538 akorotkov@postgresql      766                 :            805 :     state->base.sortKeys->abbrev_converter = NULL;
                                767         [ +  + ]:            805 :     if (state->base.sortKeys->abbrev_full_comparator)
                                768                 :             10 :         state->base.sortKeys->comparator = state->base.sortKeys->abbrev_full_comparator;
                                769                 :                : 
                                770                 :                :     /* Not strictly necessary, but be tidy */
                                771                 :            805 :     state->base.sortKeys->abbrev_abort = NULL;
                                772                 :            805 :     state->base.sortKeys->abbrev_full_comparator = NULL;
                                773                 :                : }
                                774                 :                : 
                                775                 :                : /*
                                776                 :                :  * tuplesort_used_bound
                                777                 :                :  *
                                778                 :                :  * Allow callers to find out if the sort state was able to use a bound.
                                779                 :                :  */
                                780                 :                : bool
 2380 tomas.vondra@postgre      781                 :            307 : tuplesort_used_bound(Tuplesortstate *state)
                                782                 :                : {
                                783                 :            307 :     return state->boundUsed;
                                784                 :                : }
                                785                 :                : 
                                786                 :                : /*
                                787                 :                :  * tuplesort_free
                                788                 :                :  *
                                789                 :                :  *  Internal routine for freeing resources of tuplesort.
                                790                 :                :  */
                                791                 :                : static void
                                792                 :         172488 : tuplesort_free(Tuplesortstate *state)
                                793                 :                : {
                                794                 :                :     /* context swap probably not needed, but let's be safe */
 1538 akorotkov@postgresql      795                 :         172488 :     MemoryContext oldcontext = MemoryContextSwitchTo(state->base.sortcontext);
                                796                 :                :     int64       spaceUsed;
                                797                 :                : 
 9857 tgl@sss.pgh.pa.us         798         [ +  + ]:         172488 :     if (state->tapeset)
 7664                           799                 :            599 :         spaceUsed = LogicalTapeSetBlocks(state->tapeset);
                                800                 :                :     else
                                801                 :         171889 :         spaceUsed = (state->allowedMem - state->availMem + 1023) / 1024;
                                802                 :                : 
                                803                 :                :     /*
                                804                 :                :      * Delete temporary "tape" files, if any.
                                805                 :                :      *
                                806                 :                :      * We don't bother to destroy the individual tapes here. They will go away
                                807                 :                :      * with the sortcontext.  (In TSS_FINALMERGE state, we have closed
                                808                 :                :      * finished tapes already.)
                                809                 :                :      */
 7533                           810         [ +  + ]:         172488 :     if (state->tapeset)
                                811                 :            599 :         LogicalTapeSetClose(state->tapeset);
                                812                 :                : 
 7679                           813         [ -  + ]:         172488 :     if (trace_sort)
                                814                 :                :     {
 7664 tgl@sss.pgh.pa.us         815         [ #  # ]:UBC           0 :         if (state->tapeset)
  562 peter@eisentraut.org      816   [ #  #  #  # ]:              0 :             elog(LOG, "%s of worker %d ended, %" PRId64 " disk blocks used: %s",
                                817                 :                :                  SERIAL(state) ? "external sort" : "parallel external sort",
                                818                 :                :                  state->worker, spaceUsed, pg_rusage_show(&state->ru_start));
                                819                 :                :         else
                                820   [ #  #  #  # ]:              0 :             elog(LOG, "%s of worker %d ended, %" PRId64 " KB used: %s",
                                821                 :                :                  SERIAL(state) ? "internal sort" : "unperformed parallel sort",
                                822                 :                :                  state->worker, spaceUsed, pg_rusage_show(&state->ru_start));
                                823                 :                :     }
                                824                 :                : 
                                825                 :                :     TRACE_POSTGRESQL_SORT_DONE(state->tapeset != NULL, spaceUsed);
                                826                 :                : 
 1538 akorotkov@postgresql      827         [ +  + ]:CBC      172488 :     FREESTATE(state);
 7533 tgl@sss.pgh.pa.us         828                 :         172488 :     MemoryContextSwitchTo(oldcontext);
                                829                 :                : 
                                830                 :                :     /*
                                831                 :                :      * Free the per-sort memory context, thereby releasing all working memory.
                                832                 :                :      */
 1538 akorotkov@postgresql      833                 :         172488 :     MemoryContextReset(state->base.sortcontext);
 2380 tomas.vondra@postgre      834                 :         172488 : }
                                835                 :                : 
                                836                 :                : /*
                                837                 :                :  * tuplesort_end
                                838                 :                :  *
                                839                 :                :  *  Release resources and clean up.
                                840                 :                :  *
                                841                 :                :  * NOTE: after calling this, any pointers returned by tuplesort_getXXX are
                                842                 :                :  * pointing to garbage.  Be careful not to attempt to use or free such
                                843                 :                :  * pointers afterwards!
                                844                 :                :  */
                                845                 :                : void
                                846                 :         170361 : tuplesort_end(Tuplesortstate *state)
                                847                 :                : {
                                848                 :         170361 :     tuplesort_free(state);
                                849                 :                : 
                                850                 :                :     /*
                                851                 :                :      * Free the main memory context, including the Tuplesortstate struct
                                852                 :                :      * itself.
                                853                 :                :      */
 1538 akorotkov@postgresql      854                 :         170361 :     MemoryContextDelete(state->base.maincontext);
 2380 tomas.vondra@postgre      855                 :         170361 : }
                                856                 :                : 
                                857                 :                : /*
                                858                 :                :  * tuplesort_updatemax
                                859                 :                :  *
                                860                 :                :  *  Update maximum resource usage statistics.
                                861                 :                :  */
                                862                 :                : static void
                                863                 :           2391 : tuplesort_updatemax(Tuplesortstate *state)
                                864                 :                : {
                                865                 :                :     int64       spaceUsed;
                                866                 :                :     bool        isSpaceDisk;
                                867                 :                : 
                                868                 :                :     /*
                                869                 :                :      * Note: it might seem we should provide both memory and disk usage for a
                                870                 :                :      * disk-based sort.  However, the current code doesn't track memory space
                                871                 :                :      * accurately once we have begun to return tuples to the caller (since we
                                872                 :                :      * don't account for pfree's the caller is expected to do), so we cannot
                                873                 :                :      * rely on availMem in a disk sort.  This does not seem worth the overhead
                                874                 :                :      * to fix.  Is it worth creating an API for the memory context code to
                                875                 :                :      * tell us how much is actually used in sortcontext?
                                876                 :                :      */
                                877         [ +  + ]:           2391 :     if (state->tapeset)
                                878                 :                :     {
                                879                 :              4 :         isSpaceDisk = true;
                                880                 :              4 :         spaceUsed = LogicalTapeSetBlocks(state->tapeset) * BLCKSZ;
                                881                 :                :     }
                                882                 :                :     else
                                883                 :                :     {
                                884                 :           2387 :         isSpaceDisk = false;
                                885                 :           2387 :         spaceUsed = state->allowedMem - state->availMem;
                                886                 :                :     }
                                887                 :                : 
                                888                 :                :     /*
                                889                 :                :      * Sort evicts data to the disk when it wasn't able to fit that data into
                                890                 :                :      * main memory.  This is why we assume space used on the disk to be more
                                891                 :                :      * important for tracking resource usage than space used in memory. Note
                                892                 :                :      * that the amount of space occupied by some tupleset on the disk might be
                                893                 :                :      * less than amount of space occupied by the same tupleset in memory due
                                894                 :                :      * to more compact representation.
                                895                 :                :      */
                                896   [ +  +  -  + ]:           2391 :     if ((isSpaceDisk && !state->isMaxSpaceDisk) ||
                                897   [ +  -  +  + ]:           2387 :         (isSpaceDisk == state->isMaxSpaceDisk && spaceUsed > state->maxSpace))
                                898                 :                :     {
                                899                 :            357 :         state->maxSpace = spaceUsed;
                                900                 :            357 :         state->isMaxSpaceDisk = isSpaceDisk;
                                901                 :            357 :         state->maxSpaceStatus = state->status;
                                902                 :                :     }
                                903                 :           2391 : }
                                904                 :                : 
                                905                 :                : /*
                                906                 :                :  * tuplesort_reset
                                907                 :                :  *
                                908                 :                :  *  Reset the tuplesort.  Reset all the data in the tuplesort, but leave the
                                909                 :                :  *  meta-information in.  After tuplesort_reset, tuplesort is ready to start
                                910                 :                :  *  a new sort.  This allows avoiding recreation of tuple sort states (and
                                911                 :                :  *  save resources) when sorting multiple small batches.
                                912                 :                :  */
                                913                 :                : void
                                914                 :           2127 : tuplesort_reset(Tuplesortstate *state)
                                915                 :                : {
                                916                 :           2127 :     tuplesort_updatemax(state);
                                917                 :           2127 :     tuplesort_free(state);
                                918                 :                : 
                                919                 :                :     /*
                                920                 :                :      * After we've freed up per-batch memory, re-setup all of the state common
                                921                 :                :      * to both the first batch and any subsequent batch.
                                922                 :                :      */
                                923                 :           2127 :     tuplesort_begin_batch(state);
                                924                 :                : 
                                925                 :           2127 :     state->lastReturnedTuple = NULL;
                                926                 :           2127 :     state->slabMemoryBegin = NULL;
                                927                 :           2127 :     state->slabMemoryEnd = NULL;
                                928                 :           2127 :     state->slabFreeHead = NULL;
 7533 tgl@sss.pgh.pa.us         929                 :           2127 : }
                                930                 :                : 
                                931                 :                : /*
                                932                 :                :  * Grow the memtuples[] array, if possible within our memory constraint.  We
                                933                 :                :  * must not exceed INT_MAX tuples in memory or the caller-provided memory
                                934                 :                :  * limit.  Return true if we were able to enlarge the array, false if not.
                                935                 :                :  *
                                936                 :                :  * Normally, at each increment we double the size of the array.  When doing
                                937                 :                :  * that would exceed a limit, we attempt one last, smaller increase (and then
                                938                 :                :  * clear the growmemtuples flag so we don't try any more).  That allows us to
                                939                 :                :  * use memory as fully as permitted; sticking to the pure doubling rule could
                                940                 :                :  * result in almost half going unused.  Because availMem moves around with
                                941                 :                :  * tuple addition/removal, we need some rule to prevent making repeated small
                                942                 :                :  * increases in memtupsize, which would just be useless thrashing.  The
                                943                 :                :  * growmemtuples flag accomplishes that and also prevents useless
                                944                 :                :  * recalculations in this function.
                                945                 :                :  */
                                946                 :                : static bool
                                947                 :           5315 : grow_memtuples(Tuplesortstate *state)
                                948                 :                : {
                                949                 :                :     int         newmemtupsize;
 5016                           950                 :           5315 :     int         memtupsize = state->memtupsize;
 4848 noah@leadboat.com         951                 :           5315 :     int64       memNowUsed = state->allowedMem - state->availMem;
                                952                 :                : 
                                953                 :                :     /* Forget it if we've already maxed out memtuples, per comment above */
 5016 tgl@sss.pgh.pa.us         954         [ +  + ]:           5315 :     if (!state->growmemtuples)
                                955                 :             90 :         return false;
                                956                 :                : 
                                957                 :                :     /* Select new value of memtupsize */
                                958         [ +  + ]:           5225 :     if (memNowUsed <= state->availMem)
                                959                 :                :     {
                                960                 :                :         /*
                                961                 :                :          * We've used no more than half of allowedMem; double our usage,
                                962                 :                :          * clamping at INT_MAX tuples.
                                963                 :                :          */
 4855 noah@leadboat.com         964         [ +  - ]:           5133 :         if (memtupsize < INT_MAX / 2)
                                965                 :           5133 :             newmemtupsize = memtupsize * 2;
                                966                 :                :         else
                                967                 :                :         {
 4855 noah@leadboat.com         968                 :UBC           0 :             newmemtupsize = INT_MAX;
                                969                 :              0 :             state->growmemtuples = false;
                                970                 :                :         }
                                971                 :                :     }
                                972                 :                :     else
                                973                 :                :     {
                                974                 :                :         /*
                                975                 :                :          * This will be the last increment of memtupsize.  Abandon doubling
                                976                 :                :          * strategy and instead increase as much as we safely can.
                                977                 :                :          *
                                978                 :                :          * To stay within allowedMem, we can't increase memtupsize by more
                                979                 :                :          * than availMem / sizeof(SortTuple) elements.  In practice, we want
                                980                 :                :          * to increase it by considerably less, because we need to leave some
                                981                 :                :          * space for the tuples to which the new array slots will refer.  We
                                982                 :                :          * assume the new tuples will be about the same size as the tuples
                                983                 :                :          * we've already seen, and thus we can extrapolate from the space
                                984                 :                :          * consumption so far to estimate an appropriate new size for the
                                985                 :                :          * memtuples array.  The optimal value might be higher or lower than
                                986                 :                :          * this estimate, but it's hard to know that in advance.  We again
                                987                 :                :          * clamp at INT_MAX tuples.
                                988                 :                :          *
                                989                 :                :          * This calculation is safe against enlarging the array so much that
                                990                 :                :          * LACKMEM becomes true, because the memory currently used includes
                                991                 :                :          * the present array; thus, there would be enough allowedMem for the
                                992                 :                :          * new array elements even if no other memory were currently used.
                                993                 :                :          *
                                994                 :                :          * We do the arithmetic in float8, because otherwise the product of
                                995                 :                :          * memtupsize and allowedMem could overflow.  Any inaccuracy in the
                                996                 :                :          * result should be insignificant; but even if we computed a
                                997                 :                :          * completely insane result, the checks below will prevent anything
                                998                 :                :          * really bad from happening.
                                999                 :                :          */
                               1000                 :                :         double      grow_ratio;
                               1001                 :                : 
 5016 tgl@sss.pgh.pa.us        1002                 :CBC          92 :         grow_ratio = (double) state->allowedMem / (double) memNowUsed;
 4855 noah@leadboat.com        1003         [ +  - ]:             92 :         if (memtupsize * grow_ratio < INT_MAX)
                               1004                 :             92 :             newmemtupsize = (int) (memtupsize * grow_ratio);
                               1005                 :                :         else
 4855 noah@leadboat.com        1006                 :UBC           0 :             newmemtupsize = INT_MAX;
                               1007                 :                : 
                               1008                 :                :         /* We won't make any further enlargement attempts */
 5016 tgl@sss.pgh.pa.us        1009                 :CBC          92 :         state->growmemtuples = false;
                               1010                 :                :     }
                               1011                 :                : 
                               1012                 :                :     /* Must enlarge array by at least one element, else report failure */
                               1013         [ -  + ]:           5225 :     if (newmemtupsize <= memtupsize)
 5016 tgl@sss.pgh.pa.us        1014                 :UBC           0 :         goto noalloc;
                               1015                 :                : 
                               1016                 :                :     /*
                               1017                 :                :      * On a 32-bit machine, allowedMem could exceed MaxAllocHugeSize.  Clamp
                               1018                 :                :      * to ensure our request won't be rejected.  Note that we can easily
                               1019                 :                :      * exhaust address space before facing this outcome.  (This is presently
                               1020                 :                :      * impossible due to guc.c's MAX_KILOBYTES limitation on work_mem, but
                               1021                 :                :      * don't rely on that at this distance.)
                               1022                 :                :      */
 4855 noah@leadboat.com        1023         [ -  + ]:CBC        5225 :     if ((Size) newmemtupsize >= MaxAllocHugeSize / sizeof(SortTuple))
                               1024                 :                :     {
 4855 noah@leadboat.com        1025                 :UBC           0 :         newmemtupsize = (int) (MaxAllocHugeSize / sizeof(SortTuple));
 5016 tgl@sss.pgh.pa.us        1026                 :              0 :         state->growmemtuples = false;    /* can't grow any more */
                               1027                 :                :     }
                               1028                 :                : 
                               1029                 :                :     /*
                               1030                 :                :      * We need to be sure that we do not cause LACKMEM to become true, else
                               1031                 :                :      * the space management algorithm will go nuts.  The code above should
                               1032                 :                :      * never generate a dangerous request, but to be safe, check explicitly
                               1033                 :                :      * that the array growth fits within availMem.  (We could still cause
                               1034                 :                :      * LACKMEM if the memory chunk overhead associated with the memtuples
                               1035                 :                :      * array were to increase.  That shouldn't happen because we chose the
                               1036                 :                :      * initial array size large enough to ensure that palloc will be treating
                               1037                 :                :      * both old and new arrays as separate chunks.  But we'll check LACKMEM
                               1038                 :                :      * explicitly below just in case.)
                               1039                 :                :      */
 4848 noah@leadboat.com        1040         [ -  + ]:CBC        5225 :     if (state->availMem < (int64) ((newmemtupsize - memtupsize) * sizeof(SortTuple)))
 5016 tgl@sss.pgh.pa.us        1041                 :UBC           0 :         goto noalloc;
                               1042                 :                : 
                               1043                 :                :     /* OK, do it */
 7533 tgl@sss.pgh.pa.us        1044                 :CBC        5225 :     FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
 5016                          1045                 :           5225 :     state->memtupsize = newmemtupsize;
 7533                          1046                 :           5225 :     state->memtuples = (SortTuple *)
 4855 noah@leadboat.com        1047                 :           5225 :         repalloc_huge(state->memtuples,
                               1048                 :           5225 :                       state->memtupsize * sizeof(SortTuple));
 7533 tgl@sss.pgh.pa.us        1049                 :           5225 :     USEMEM(state, GetMemoryChunkSpace(state->memtuples));
                               1050   [ -  +  -  - ]:           5225 :     if (LACKMEM(state))
 4087 tgl@sss.pgh.pa.us        1051         [ #  # ]:UBC           0 :         elog(ERROR, "unexpected out-of-memory situation in tuplesort");
 7533 tgl@sss.pgh.pa.us        1052                 :CBC        5225 :     return true;
                               1053                 :                : 
 5016 tgl@sss.pgh.pa.us        1054                 :UBC           0 : noalloc:
                               1055                 :                :     /* If for any reason we didn't realloc, shut off future attempts */
                               1056                 :              0 :     state->growmemtuples = false;
                               1057                 :              0 :     return false;
                               1058                 :                : }
                               1059                 :                : 
                               1060                 :                : /*
                               1061                 :                :  * Shared code for tuple and datum cases.
                               1062                 :                :  */
                               1063                 :                : void
  917 drowley@postgresql.o     1064                 :CBC    19301191 : tuplesort_puttuple_common(Tuplesortstate *state, SortTuple *tuple,
                               1065                 :                :                           bool useAbbrev, Size tuplen)
                               1066                 :                : {
 1538 akorotkov@postgresql     1067                 :       19301191 :     MemoryContext oldcontext = MemoryContextSwitchTo(state->base.sortcontext);
                               1068                 :                : 
 3174 rhaas@postgresql.org     1069   [ +  +  -  + ]:       19301191 :     Assert(!LEADER(state));
                               1070                 :                : 
                               1071                 :                :     /* account for the memory used for this tuple */
  917 drowley@postgresql.o     1072                 :       19301191 :     USEMEM(state, tuplen);
                               1073                 :       19301191 :     state->tupleMem += tuplen;
                               1074                 :                : 
 1538 akorotkov@postgresql     1075         [ +  + ]:       19301191 :     if (!useAbbrev)
                               1076                 :                :     {
                               1077                 :                :         /*
                               1078                 :                :          * Leave ordinary Datum representation, or NULL value.  If there is a
                               1079                 :                :          * converter it won't expect NULL values, and cost model is not
                               1080                 :                :          * required to account for NULL, so in that case we avoid calling
                               1081                 :                :          * converter and just set datum1 to zeroed representation (to be
                               1082                 :                :          * consistent, and to support cheap inequality tests for NULL
                               1083                 :                :          * abbreviated keys).
                               1084                 :                :          */
                               1085                 :                :     }
                               1086         [ +  + ]:        2901290 :     else if (!consider_abort_common(state))
                               1087                 :                :     {
                               1088                 :                :         /* Store abbreviated key representation */
                               1089                 :        2901226 :         tuple->datum1 = state->base.sortKeys->abbrev_converter(tuple->datum1,
                               1090                 :                :                                                                state->base.sortKeys);
                               1091                 :                :     }
                               1092                 :                :     else
                               1093                 :                :     {
                               1094                 :                :         /*
                               1095                 :                :          * Set state to be consistent with never trying abbreviation.
                               1096                 :                :          *
                               1097                 :                :          * Alter datum1 representation in already-copied tuples, so as to
                               1098                 :                :          * ensure a consistent representation (current tuple was just
                               1099                 :                :          * handled).  It does not matter if some dumped tuples are already
                               1100                 :                :          * sorted on tape, since serialized tuples lack abbreviated keys
                               1101                 :                :          * (TSS_BUILDRUNS state prevents control reaching here in any case).
                               1102                 :                :          */
                               1103                 :             64 :         REMOVEABBREV(state, state->memtuples, state->memtupcount);
                               1104                 :                :     }
                               1105                 :                : 
 9857 tgl@sss.pgh.pa.us        1106   [ +  +  +  - ]:       19301191 :     switch (state->status)
                               1107                 :                :     {
 9118 bruce@momjian.us         1108                 :       16398132 :         case TSS_INITIAL:
                               1109                 :                : 
                               1110                 :                :             /*
                               1111                 :                :              * Save the tuple into the unsorted array.  First, grow the array
                               1112                 :                :              * as needed.  Note that we try to grow the array when there is
                               1113                 :                :              * still one free slot remaining --- if we fail, there'll still be
                               1114                 :                :              * room to store the incoming tuple, and then we'll switch to
                               1115                 :                :              * tape-based operation.
                               1116                 :                :              */
 7533 tgl@sss.pgh.pa.us        1117         [ +  + ]:       16398132 :             if (state->memtupcount >= state->memtupsize - 1)
                               1118                 :                :             {
                               1119                 :           5315 :                 (void) grow_memtuples(state);
                               1120         [ -  + ]:           5315 :                 Assert(state->memtupcount < state->memtupsize);
                               1121                 :                :             }
                               1122                 :       16398132 :             state->memtuples[state->memtupcount++] = *tuple;
                               1123                 :                : 
                               1124                 :                :             /*
                               1125                 :                :              * Check if it's time to switch over to a bounded heapsort. We do
                               1126                 :                :              * so if the input tuple count exceeds twice the desired tuple
                               1127                 :                :              * count (this is a heuristic for where heapsort becomes cheaper
                               1128                 :                :              * than a quicksort), or if we've just filled workMem and have
                               1129                 :                :              * enough tuples to meet the bound.
                               1130                 :                :              *
                               1131                 :                :              * Note that once we enter TSS_BOUNDED state we will always try to
                               1132                 :                :              * complete the sort that way.  In the worst case, if later input
                               1133                 :                :              * tuples are larger than earlier ones, this might cause us to
                               1134                 :                :              * exceed workMem significantly.
                               1135                 :                :              */
 7101                          1136         [ +  + ]:       16398132 :             if (state->bounded &&
                               1137         [ +  + ]:          48379 :                 (state->memtupcount > state->bound * 2 ||
                               1138   [ +  +  -  +  :          48115 :                  (state->memtupcount > state->bound && LACKMEM(state))))
                                              -  - ]
                               1139                 :                :             {
                               1140         [ -  + ]:            264 :                 if (trace_sort)
 7101 tgl@sss.pgh.pa.us        1141         [ #  # ]:UBC           0 :                     elog(LOG, "switching to bounded heapsort at %d tuples: %s",
                               1142                 :                :                          state->memtupcount,
                               1143                 :                :                          pg_rusage_show(&state->ru_start));
 7101 tgl@sss.pgh.pa.us        1144                 :CBC         264 :                 make_bounded_heap(state);
 1538 akorotkov@postgresql     1145                 :            264 :                 MemoryContextSwitchTo(oldcontext);
 7101 tgl@sss.pgh.pa.us        1146                 :            264 :                 return;
                               1147                 :                :             }
                               1148                 :                : 
                               1149                 :                :             /*
                               1150                 :                :              * Done if we still fit in available memory and have array slots.
                               1151                 :                :              */
 7533                          1152   [ +  +  -  +  :       16397868 :             if (state->memtupcount < state->memtupsize && !LACKMEM(state))
                                              -  - ]
                               1153                 :                :             {
 1538 akorotkov@postgresql     1154                 :       16397778 :                 MemoryContextSwitchTo(oldcontext);
 9857 tgl@sss.pgh.pa.us        1155                 :       16397778 :                 return;
                               1156                 :                :             }
                               1157                 :                : 
                               1158                 :                :             /*
                               1159                 :                :              * Nope; time to switch to tape-based operation.
                               1160                 :                :              */
 3174 rhaas@postgresql.org     1161                 :             90 :             inittapes(state, true);
                               1162                 :                : 
                               1163                 :                :             /*
                               1164                 :                :              * Dump all tuples.
                               1165                 :                :              */
 9857 tgl@sss.pgh.pa.us        1166                 :             90 :             dumptuples(state, false);
                               1167                 :             90 :             break;
                               1168                 :                : 
 7101                          1169                 :        2132056 :         case TSS_BOUNDED:
                               1170                 :                : 
                               1171                 :                :             /*
                               1172                 :                :              * We don't want to grow the array here, so check whether the new
                               1173                 :                :              * tuple can be discarded before putting it in.  This should be a
                               1174                 :                :              * good speed optimization, too, since when there are many more
                               1175                 :                :              * input tuples than the bound, most input tuples can be discarded
                               1176                 :                :              * with just this one comparison.  Note that because we currently
                               1177                 :                :              * have the sort direction reversed, we must check for <= not >=.
                               1178                 :                :              */
                               1179         [ +  + ]:        2132056 :             if (COMPARETUP(state, tuple, &state->memtuples[0]) <= 0)
                               1180                 :                :             {
                               1181                 :                :                 /* new tuple <= top of the heap, so we can discard it */
                               1182                 :        1797356 :                 free_sort_tuple(state, tuple);
 5319 rhaas@postgresql.org     1183         [ +  + ]:        1797356 :                 CHECK_FOR_INTERRUPTS();
                               1184                 :                :             }
                               1185                 :                :             else
                               1186                 :                :             {
                               1187                 :                :                 /* discard top of heap, replacing it with the new tuple */
 7101 tgl@sss.pgh.pa.us        1188                 :         334700 :                 free_sort_tuple(state, &state->memtuples[0]);
 3300 rhaas@postgresql.org     1189                 :         334700 :                 tuplesort_heap_replace_top(state, tuple);
                               1190                 :                :             }
 7101 tgl@sss.pgh.pa.us        1191                 :        2132056 :             break;
                               1192                 :                : 
 9857                          1193                 :         771003 :         case TSS_BUILDRUNS:
                               1194                 :                : 
                               1195                 :                :             /*
                               1196                 :                :              * Save the tuple into the unsorted array (there must be space)
                               1197                 :                :              */
 3300 rhaas@postgresql.org     1198                 :         771003 :             state->memtuples[state->memtupcount++] = *tuple;
                               1199                 :                : 
                               1200                 :                :             /*
                               1201                 :                :              * If we are over the memory limit, dump all tuples.
                               1202                 :                :              */
 9857 tgl@sss.pgh.pa.us        1203                 :         771003 :             dumptuples(state, false);
                               1204                 :         771003 :             break;
                               1205                 :                : 
 9857 tgl@sss.pgh.pa.us        1206                 :UBC           0 :         default:
 8480                          1207         [ #  # ]:              0 :             elog(ERROR, "invalid tuplesort state");
                               1208                 :                :             break;
                               1209                 :                :     }
 1538 akorotkov@postgresql     1210                 :CBC     2903149 :     MemoryContextSwitchTo(oldcontext);
                               1211                 :                : }
                               1212                 :                : 
                               1213                 :                : static bool
 4284 rhaas@postgresql.org     1214                 :        2901290 : consider_abort_common(Tuplesortstate *state)
                               1215                 :                : {
 1538 akorotkov@postgresql     1216         [ -  + ]:        2901290 :     Assert(state->base.sortKeys[0].abbrev_converter != NULL);
                               1217         [ -  + ]:        2901290 :     Assert(state->base.sortKeys[0].abbrev_abort != NULL);
                               1218         [ -  + ]:        2901290 :     Assert(state->base.sortKeys[0].abbrev_full_comparator != NULL);
                               1219                 :                : 
                               1220                 :                :     /*
                               1221                 :                :      * Check effectiveness of abbreviation optimization.  Consider aborting
                               1222                 :                :      * when still within memory limit.
                               1223                 :                :      */
 4284 rhaas@postgresql.org     1224         [ +  + ]:        2901290 :     if (state->status == TSS_INITIAL &&
                               1225         [ +  + ]:        2574675 :         state->memtupcount >= state->abbrevNext)
                               1226                 :                :     {
                               1227                 :           3244 :         state->abbrevNext *= 2;
                               1228                 :                : 
                               1229                 :                :         /*
                               1230                 :                :          * Check opclass-supplied abbreviation abort routine.  It may indicate
                               1231                 :                :          * that abbreviation should not proceed.
                               1232                 :                :          */
 1538 akorotkov@postgresql     1233         [ +  + ]:           3244 :         if (!state->base.sortKeys->abbrev_abort(state->memtupcount,
                               1234                 :                :                                                 state->base.sortKeys))
 4284 rhaas@postgresql.org     1235                 :           3180 :             return false;
                               1236                 :                : 
                               1237                 :                :         /*
                               1238                 :                :          * Finally, restore authoritative comparator, and indicate that
                               1239                 :                :          * abbreviation is not in play by setting abbrev_converter to NULL
                               1240                 :                :          */
 1538 akorotkov@postgresql     1241                 :             64 :         state->base.sortKeys[0].comparator = state->base.sortKeys[0].abbrev_full_comparator;
                               1242                 :             64 :         state->base.sortKeys[0].abbrev_converter = NULL;
                               1243                 :                :         /* Not strictly necessary, but be tidy */
                               1244                 :             64 :         state->base.sortKeys[0].abbrev_abort = NULL;
                               1245                 :             64 :         state->base.sortKeys[0].abbrev_full_comparator = NULL;
                               1246                 :                : 
                               1247                 :                :         /* Give up - expect original pass-by-value representation */
 4284 rhaas@postgresql.org     1248                 :             64 :         return true;
                               1249                 :                :     }
                               1250                 :                : 
                               1251                 :        2898046 :     return false;
                               1252                 :                : }
                               1253                 :                : 
                               1254                 :                : /*
                               1255                 :                :  * All tuples have been provided; finish the sort.
                               1256                 :                :  */
                               1257                 :                : void
 9857 tgl@sss.pgh.pa.us        1258                 :         147119 : tuplesort_performsort(Tuplesortstate *state)
                               1259                 :                : {
 1538 akorotkov@postgresql     1260                 :         147119 :     MemoryContext oldcontext = MemoryContextSwitchTo(state->base.sortcontext);
                               1261                 :                : 
 7679 tgl@sss.pgh.pa.us        1262         [ -  + ]:         147119 :     if (trace_sort)
 2902 pg@bowt.ie               1263         [ #  # ]:UBC           0 :         elog(LOG, "performsort of worker %d starting: %s",
                               1264                 :                :              state->worker, pg_rusage_show(&state->ru_start));
                               1265                 :                : 
 9857 tgl@sss.pgh.pa.us        1266   [ +  +  +  - ]:CBC      147119 :     switch (state->status)
                               1267                 :                :     {
 9118 bruce@momjian.us         1268                 :         146765 :         case TSS_INITIAL:
                               1269                 :                : 
                               1270                 :                :             /*
                               1271                 :                :              * We were able to accumulate all the tuples within the allowed
                               1272                 :                :              * amount of memory, or leader to take over worker tapes
                               1273                 :                :              */
 3174 rhaas@postgresql.org     1274         [ +  + ]:         146765 :             if (SERIAL(state))
                               1275                 :                :             {
                               1276                 :                :                 /* Sort in memory and we're done */
                               1277                 :         146256 :                 tuplesort_sort_memtuples(state);
                               1278                 :         146195 :                 state->status = TSS_SORTEDINMEM;
                               1279                 :                :             }
                               1280   [ +  -  +  + ]:            509 :             else if (WORKER(state))
                               1281                 :                :             {
                               1282                 :                :                 /*
                               1283                 :                :                  * Parallel workers must still dump out tuples to tape.  No
                               1284                 :                :                  * merge is required to produce single output run, though.
                               1285                 :                :                  */
                               1286                 :            379 :                 inittapes(state, false);
                               1287                 :            379 :                 dumptuples(state, true);
                               1288                 :            379 :                 worker_nomergeruns(state);
                               1289                 :            379 :                 state->status = TSS_SORTEDONTAPE;
                               1290                 :                :             }
                               1291                 :                :             else
                               1292                 :                :             {
                               1293                 :                :                 /*
                               1294                 :                :                  * Leader will take over worker tapes and merge worker runs.
                               1295                 :                :                  * Note that mergeruns sets the correct state->status.
                               1296                 :                :                  */
                               1297                 :            130 :                 leader_takeover_tapes(state);
                               1298                 :            130 :                 mergeruns(state);
                               1299                 :                :             }
 9857 tgl@sss.pgh.pa.us        1300                 :         146704 :             state->current = 0;
                               1301                 :         146704 :             state->eof_reached = false;
 3174 rhaas@postgresql.org     1302                 :         146704 :             state->markpos_block = 0L;
 9857 tgl@sss.pgh.pa.us        1303                 :         146704 :             state->markpos_offset = 0;
                               1304                 :         146704 :             state->markpos_eof = false;
                               1305                 :         146704 :             break;
                               1306                 :                : 
 7101                          1307                 :            264 :         case TSS_BOUNDED:
                               1308                 :                : 
                               1309                 :                :             /*
                               1310                 :                :              * We were able to accumulate all the tuples required for output
                               1311                 :                :              * in memory, using a heap to eliminate excess tuples.  Now we
                               1312                 :                :              * have to transform the heap to a properly-sorted array. Note
                               1313                 :                :              * that sort_bounded_heap sets the correct state->status.
                               1314                 :                :              */
 6981                          1315                 :            264 :             sort_bounded_heap(state);
 7101                          1316                 :            264 :             state->current = 0;
                               1317                 :            264 :             state->eof_reached = false;
                               1318                 :            264 :             state->markpos_offset = 0;
                               1319                 :            264 :             state->markpos_eof = false;
                               1320                 :            264 :             break;
                               1321                 :                : 
 9857                          1322                 :             90 :         case TSS_BUILDRUNS:
                               1323                 :                : 
                               1324                 :                :             /*
                               1325                 :                :              * Finish tape-based sort.  First, flush all tuples remaining in
                               1326                 :                :              * memory out to tape; then merge until we have a single remaining
                               1327                 :                :              * run (or, if !randomAccess and !WORKER(), one run per tape).
                               1328                 :                :              * Note that mergeruns sets the correct state->status.
                               1329                 :                :              */
                               1330                 :             90 :             dumptuples(state, true);
                               1331                 :             90 :             mergeruns(state);
                               1332                 :             90 :             state->eof_reached = false;
                               1333                 :             90 :             state->markpos_block = 0L;
                               1334                 :             90 :             state->markpos_offset = 0;
                               1335                 :             90 :             state->markpos_eof = false;
                               1336                 :             90 :             break;
                               1337                 :                : 
 9857 tgl@sss.pgh.pa.us        1338                 :UBC           0 :         default:
 8480                          1339         [ #  # ]:              0 :             elog(ERROR, "invalid tuplesort state");
                               1340                 :                :             break;
                               1341                 :                :     }
                               1342                 :                : 
 7679 tgl@sss.pgh.pa.us        1343         [ -  + ]:CBC      147058 :     if (trace_sort)
                               1344                 :                :     {
 7523 tgl@sss.pgh.pa.us        1345         [ #  # ]:UBC           0 :         if (state->status == TSS_FINALMERGE)
 2902 pg@bowt.ie               1346         [ #  # ]:              0 :             elog(LOG, "performsort of worker %d done (except %d-way final merge): %s",
                               1347                 :                :                  state->worker, state->nInputTapes,
                               1348                 :                :                  pg_rusage_show(&state->ru_start));
                               1349                 :                :         else
                               1350         [ #  # ]:              0 :             elog(LOG, "performsort of worker %d done: %s",
                               1351                 :                :                  state->worker, pg_rusage_show(&state->ru_start));
                               1352                 :                :     }
                               1353                 :                : 
 7533 tgl@sss.pgh.pa.us        1354                 :CBC      147058 :     MemoryContextSwitchTo(oldcontext);
 9857                          1355                 :         147058 : }
                               1356                 :                : 
                               1357                 :                : /*
                               1358                 :                :  * Internal routine to fetch the next tuple in either forward or back
                               1359                 :                :  * direction into *stup.  Returns false if no more tuples.
                               1360                 :                :  * Returned tuple belongs to tuplesort memory context, and must not be freed
                               1361                 :                :  * by caller.  Note that fetched tuple is stored in memory that may be
                               1362                 :                :  * recycled by any future fetch.
                               1363                 :                :  */
                               1364                 :                : bool
 7533                          1365                 :       17891825 : tuplesort_gettuple_common(Tuplesortstate *state, bool forward,
                               1366                 :                :                           SortTuple *stup)
                               1367                 :                : {
                               1368                 :                :     unsigned int tuplen;
                               1369                 :                :     size_t      nmoved;
                               1370                 :                : 
 3174 rhaas@postgresql.org     1371   [ +  +  -  + ]:       17891825 :     Assert(!WORKER(state));
                               1372                 :                : 
 9857 tgl@sss.pgh.pa.us        1373   [ +  +  +  - ]:       17891825 :     switch (state->status)
                               1374                 :                :     {
                               1375                 :       14948303 :         case TSS_SORTEDINMEM:
 1538 akorotkov@postgresql     1376   [ +  +  -  + ]:       14948303 :             Assert(forward || state->base.sortopt & TUPLESORT_RANDOMACCESS);
 3661 heikki.linnakangas@i     1377         [ -  + ]:       14948303 :             Assert(!state->slabAllocatorUsed);
 9857 tgl@sss.pgh.pa.us        1378         [ +  + ]:       14948303 :             if (forward)
                               1379                 :                :             {
                               1380         [ +  + ]:       14948259 :                 if (state->current < state->memtupcount)
                               1381                 :                :                 {
 7533                          1382                 :       14802603 :                     *stup = state->memtuples[state->current++];
                               1383                 :       14802603 :                     return true;
                               1384                 :                :                 }
 9857                          1385                 :         145656 :                 state->eof_reached = true;
                               1386                 :                : 
                               1387                 :                :                 /*
                               1388                 :                :                  * Complain if caller tries to retrieve more tuples than
                               1389                 :                :                  * originally asked for in a bounded sort.  This is because
                               1390                 :                :                  * returning EOF here might be the wrong thing.
                               1391                 :                :                  */
 7101                          1392   [ +  +  -  + ]:         145656 :                 if (state->bounded && state->current >= state->bound)
 7101 tgl@sss.pgh.pa.us        1393         [ #  # ]:UBC           0 :                     elog(ERROR, "retrieved too many tuples in a bounded sort");
                               1394                 :                : 
 7533 tgl@sss.pgh.pa.us        1395                 :CBC      145656 :                 return false;
                               1396                 :                :             }
                               1397                 :                :             else
                               1398                 :                :             {
 9857                          1399         [ -  + ]:             44 :                 if (state->current <= 0)
 7533 tgl@sss.pgh.pa.us        1400                 :UBC           0 :                     return false;
                               1401                 :                : 
                               1402                 :                :                 /*
                               1403                 :                :                  * if all tuples are fetched already then we return last
                               1404                 :                :                  * tuple, else - tuple before last returned.
                               1405                 :                :                  */
 9857 tgl@sss.pgh.pa.us        1406         [ +  + ]:CBC          44 :                 if (state->eof_reached)
                               1407                 :              8 :                     state->eof_reached = false;
                               1408                 :                :                 else
                               1409                 :                :                 {
 9679 bruce@momjian.us         1410                 :             36 :                     state->current--;    /* last returned tuple */
 9857 tgl@sss.pgh.pa.us        1411         [ +  + ]:             36 :                     if (state->current <= 0)
 7533                          1412                 :              4 :                         return false;
                               1413                 :                :                 }
                               1414                 :             40 :                 *stup = state->memtuples[state->current - 1];
                               1415                 :             40 :                 return true;
                               1416                 :                :             }
                               1417                 :                :             break;
                               1418                 :                : 
 9857                          1419                 :         196999 :         case TSS_SORTEDONTAPE:
 1538 akorotkov@postgresql     1420   [ +  +  -  + ]:         196999 :             Assert(forward || state->base.sortopt & TUPLESORT_RANDOMACCESS);
 3661 heikki.linnakangas@i     1421         [ -  + ]:         196999 :             Assert(state->slabAllocatorUsed);
                               1422                 :                : 
                               1423                 :                :             /*
                               1424                 :                :              * The slot that held the tuple that we returned in previous
                               1425                 :                :              * gettuple call can now be reused.
                               1426                 :                :              */
                               1427         [ +  + ]:         196999 :             if (state->lastReturnedTuple)
                               1428                 :                :             {
                               1429   [ +  -  +  - ]:         101900 :                 RELEASE_SLAB_SLOT(state, state->lastReturnedTuple);
                               1430                 :         101900 :                 state->lastReturnedTuple = NULL;
                               1431                 :                :             }
                               1432                 :                : 
 9857 tgl@sss.pgh.pa.us        1433         [ +  + ]:         196999 :             if (forward)
                               1434                 :                :             {
                               1435         [ -  + ]:         196979 :                 if (state->eof_reached)
 7533 tgl@sss.pgh.pa.us        1436                 :UBC           0 :                     return false;
                               1437                 :                : 
 1820 heikki.linnakangas@i     1438         [ +  + ]:CBC      196979 :                 if ((tuplen = getlen(state->result_tape, true)) != 0)
                               1439                 :                :                 {
 7533 tgl@sss.pgh.pa.us        1440                 :         196960 :                     READTUP(state, stup, state->result_tape, tuplen);
                               1441                 :                : 
                               1442                 :                :                     /*
                               1443                 :                :                      * Remember the tuple we return, so that we can recycle
                               1444                 :                :                      * its memory on next call.  (This can be NULL, in the
                               1445                 :                :                      * !state->tuples case).
                               1446                 :                :                      */
 3661 heikki.linnakangas@i     1447                 :         196960 :                     state->lastReturnedTuple = stup->tuple;
                               1448                 :                : 
 7533 tgl@sss.pgh.pa.us        1449                 :         196960 :                     return true;
                               1450                 :                :                 }
                               1451                 :                :                 else
                               1452                 :                :                 {
 9857                          1453                 :             19 :                     state->eof_reached = true;
 7533                          1454                 :             19 :                     return false;
                               1455                 :                :                 }
                               1456                 :                :             }
                               1457                 :                : 
                               1458                 :                :             /*
                               1459                 :                :              * Backward.
                               1460                 :                :              *
                               1461                 :                :              * if all tuples are fetched already then we return last tuple,
                               1462                 :                :              * else - tuple before last returned.
                               1463                 :                :              */
 9857                          1464         [ +  + ]:             20 :             if (state->eof_reached)
                               1465                 :                :             {
                               1466                 :                :                 /*
                               1467                 :                :                  * Seek position is pointing just past the zero tuplen at the
                               1468                 :                :                  * end of file; back up to fetch last tuple's ending length
                               1469                 :                :                  * word.  If seek fails we must have a completely empty file.
                               1470                 :                :                  */
 1820 heikki.linnakangas@i     1471                 :              8 :                 nmoved = LogicalTapeBackspace(state->result_tape,
                               1472                 :                :                                               2 * sizeof(unsigned int));
 3581                          1473         [ -  + ]:              8 :                 if (nmoved == 0)
 7533 tgl@sss.pgh.pa.us        1474                 :UBC           0 :                     return false;
 3581 heikki.linnakangas@i     1475         [ -  + ]:CBC           8 :                 else if (nmoved != 2 * sizeof(unsigned int))
 3581 heikki.linnakangas@i     1476         [ #  # ]:UBC           0 :                     elog(ERROR, "unexpected tape position");
 9857 tgl@sss.pgh.pa.us        1477                 :CBC           8 :                 state->eof_reached = false;
                               1478                 :                :             }
                               1479                 :                :             else
                               1480                 :                :             {
                               1481                 :                :                 /*
                               1482                 :                :                  * Back up and fetch previously-returned tuple's ending length
                               1483                 :                :                  * word.  If seek fails, assume we are at start of file.
                               1484                 :                :                  */
 1820 heikki.linnakangas@i     1485                 :             12 :                 nmoved = LogicalTapeBackspace(state->result_tape,
                               1486                 :                :                                               sizeof(unsigned int));
 3581                          1487         [ -  + ]:             12 :                 if (nmoved == 0)
 7533 tgl@sss.pgh.pa.us        1488                 :UBC           0 :                     return false;
 3581 heikki.linnakangas@i     1489         [ -  + ]:CBC          12 :                 else if (nmoved != sizeof(unsigned int))
 3581 heikki.linnakangas@i     1490         [ #  # ]:UBC           0 :                     elog(ERROR, "unexpected tape position");
 1820 heikki.linnakangas@i     1491                 :CBC          12 :                 tuplen = getlen(state->result_tape, false);
                               1492                 :                : 
                               1493                 :                :                 /*
                               1494                 :                :                  * Back up to get ending length word of tuple before it.
                               1495                 :                :                  */
                               1496                 :             12 :                 nmoved = LogicalTapeBackspace(state->result_tape,
                               1497                 :                :                                               tuplen + 2 * sizeof(unsigned int));
 3581                          1498         [ +  + ]:             12 :                 if (nmoved == tuplen + sizeof(unsigned int))
                               1499                 :                :                 {
                               1500                 :                :                     /*
                               1501                 :                :                      * We backed up over the previous tuple, but there was no
                               1502                 :                :                      * ending length word before it.  That means that the prev
                               1503                 :                :                      * tuple is the first tuple in the file.  It is now the
                               1504                 :                :                      * next to read in forward direction (not obviously right,
                               1505                 :                :                      * but that is what in-memory case does).
                               1506                 :                :                      */
 7533 tgl@sss.pgh.pa.us        1507                 :              4 :                     return false;
                               1508                 :                :                 }
 3581 heikki.linnakangas@i     1509         [ -  + ]:              8 :                 else if (nmoved != tuplen + 2 * sizeof(unsigned int))
 3581 heikki.linnakangas@i     1510         [ #  # ]:UBC           0 :                     elog(ERROR, "bogus tuple length in backward scan");
                               1511                 :                :             }
                               1512                 :                : 
 1820 heikki.linnakangas@i     1513                 :CBC          16 :             tuplen = getlen(state->result_tape, false);
                               1514                 :                : 
                               1515                 :                :             /*
                               1516                 :                :              * Now we have the length of the prior tuple, back up and read it.
                               1517                 :                :              * Note: READTUP expects we are positioned after the initial
                               1518                 :                :              * length word of the tuple, so back up to that point.
                               1519                 :                :              */
                               1520                 :             16 :             nmoved = LogicalTapeBackspace(state->result_tape,
                               1521                 :                :                                           tuplen);
 3581                          1522         [ -  + ]:             16 :             if (nmoved != tuplen)
 8480 tgl@sss.pgh.pa.us        1523         [ #  # ]:UBC           0 :                 elog(ERROR, "bogus tuple length in backward scan");
 7533 tgl@sss.pgh.pa.us        1524                 :CBC          16 :             READTUP(state, stup, state->result_tape, tuplen);
                               1525                 :                : 
                               1526                 :                :             /*
                               1527                 :                :              * Remember the tuple we return, so that we can recycle its memory
                               1528                 :                :              * on next call. (This can be NULL, in the Datum case).
                               1529                 :                :              */
 3661 heikki.linnakangas@i     1530                 :             16 :             state->lastReturnedTuple = stup->tuple;
                               1531                 :                : 
 7533 tgl@sss.pgh.pa.us        1532                 :             16 :             return true;
                               1533                 :                : 
 9857                          1534                 :        2746523 :         case TSS_FINALMERGE:
                               1535         [ -  + ]:        2746523 :             Assert(forward);
                               1536                 :                :             /* We are managing memory ourselves, with the slab allocator. */
 3661 heikki.linnakangas@i     1537         [ -  + ]:        2746523 :             Assert(state->slabAllocatorUsed);
                               1538                 :                : 
                               1539                 :                :             /*
                               1540                 :                :              * The slab slot holding the tuple that we returned in previous
                               1541                 :                :              * gettuple call can now be reused.
                               1542                 :                :              */
                               1543         [ +  + ]:        2746523 :             if (state->lastReturnedTuple)
                               1544                 :                :             {
                               1545   [ +  -  +  + ]:        2676297 :                 RELEASE_SLAB_SLOT(state, state->lastReturnedTuple);
                               1546                 :        2676297 :                 state->lastReturnedTuple = NULL;
                               1547                 :                :             }
                               1548                 :                : 
                               1549                 :                :             /*
                               1550                 :                :              * This code should match the inner loop of mergeonerun().
                               1551                 :                :              */
 9844 tgl@sss.pgh.pa.us        1552         [ +  + ]:        2746523 :             if (state->memtupcount > 0)
                               1553                 :                :             {
 1820 heikki.linnakangas@i     1554                 :        2746329 :                 int         srcTapeIndex = state->memtuples[0].srctape;
                               1555                 :        2746329 :                 LogicalTape *srcTape = state->inputTapes[srcTapeIndex];
                               1556                 :                :                 SortTuple   newtup;
                               1557                 :                : 
 3661                          1558                 :        2746329 :                 *stup = state->memtuples[0];
                               1559                 :                : 
                               1560                 :                :                 /*
                               1561                 :                :                  * Remember the tuple we return, so that we can recycle its
                               1562                 :                :                  * memory on next call. (This can be NULL, in the Datum case).
                               1563                 :                :                  */
                               1564                 :        2746329 :                 state->lastReturnedTuple = stup->tuple;
                               1565                 :                : 
                               1566                 :                :                 /*
                               1567                 :                :                  * Pull next tuple from tape, and replace the returned tuple
                               1568                 :                :                  * at top of the heap with it.
                               1569                 :                :                  */
                               1570         [ +  + ]:        2746329 :                 if (!mergereadnext(state, srcTape, &newtup))
                               1571                 :                :                 {
                               1572                 :                :                     /*
                               1573                 :                :                      * If no more data, we've reached end of run on this tape.
                               1574                 :                :                      * Remove the top node from the heap.
                               1575                 :                :                      */
 3300 rhaas@postgresql.org     1576                 :            263 :                     tuplesort_heap_delete_top(state);
 1820 heikki.linnakangas@i     1577                 :            263 :                     state->nInputRuns--;
                               1578                 :                : 
                               1579                 :                :                     /*
                               1580                 :                :                      * Close the tape.  It'd go away at the end of the sort
                               1581                 :                :                      * anyway, but better to release the memory early.
                               1582                 :                :                      */
 1538 akorotkov@postgresql     1583                 :            263 :                     LogicalTapeClose(srcTape);
                               1584                 :            263 :                     return true;
                               1585                 :                :                 }
                               1586                 :        2746066 :                 newtup.srctape = srcTapeIndex;
                               1587                 :        2746066 :                 tuplesort_heap_replace_top(state, &newtup);
                               1588                 :        2746066 :                 return true;
                               1589                 :                :             }
                               1590                 :            194 :             return false;
                               1591                 :                : 
 1538 akorotkov@postgresql     1592                 :UBC           0 :         default:
                               1593         [ #  # ]:              0 :             elog(ERROR, "invalid tuplesort state");
                               1594                 :                :             return false;       /* keep compiler quiet */
                               1595                 :                :     }
                               1596                 :                : }
                               1597                 :                : 
                               1598                 :                : 
                               1599                 :                : /*
                               1600                 :                :  * Advance over N tuples in either forward or back direction,
                               1601                 :                :  * without returning any data.  N==0 is a no-op.
                               1602                 :                :  * Returns true if successful, false if ran out of tuples.
                               1603                 :                :  */
                               1604                 :                : bool
 4676 tgl@sss.pgh.pa.us        1605                 :CBC         258 : tuplesort_skiptuples(Tuplesortstate *state, int64 ntuples, bool forward)
                               1606                 :                : {
                               1607                 :                :     MemoryContext oldcontext;
                               1608                 :                : 
                               1609                 :                :     /*
                               1610                 :                :      * We don't actually support backwards skip yet, because no callers need
                               1611                 :                :      * it.  The API is designed to allow for that later, though.
                               1612                 :                :      */
                               1613         [ -  + ]:            258 :     Assert(forward);
                               1614         [ -  + ]:            258 :     Assert(ntuples >= 0);
 3174 rhaas@postgresql.org     1615   [ -  +  -  - ]:            258 :     Assert(!WORKER(state));
                               1616                 :                : 
 4676 tgl@sss.pgh.pa.us        1617      [ +  +  - ]:            258 :     switch (state->status)
                               1618                 :                :     {
                               1619                 :            242 :         case TSS_SORTEDINMEM:
                               1620         [ +  - ]:            242 :             if (state->memtupcount - state->current >= ntuples)
                               1621                 :                :             {
                               1622                 :            242 :                 state->current += ntuples;
                               1623                 :            242 :                 return true;
                               1624                 :                :             }
 4676 tgl@sss.pgh.pa.us        1625                 :UBC           0 :             state->current = state->memtupcount;
                               1626                 :              0 :             state->eof_reached = true;
                               1627                 :                : 
                               1628                 :                :             /*
                               1629                 :                :              * Complain if caller tries to retrieve more tuples than
                               1630                 :                :              * originally asked for in a bounded sort.  This is because
                               1631                 :                :              * returning EOF here might be the wrong thing.
                               1632                 :                :              */
                               1633   [ #  #  #  # ]:              0 :             if (state->bounded && state->current >= state->bound)
                               1634         [ #  # ]:              0 :                 elog(ERROR, "retrieved too many tuples in a bounded sort");
                               1635                 :                : 
                               1636                 :              0 :             return false;
                               1637                 :                : 
 4676 tgl@sss.pgh.pa.us        1638                 :CBC          16 :         case TSS_SORTEDONTAPE:
                               1639                 :                :         case TSS_FINALMERGE:
                               1640                 :                : 
                               1641                 :                :             /*
                               1642                 :                :              * We could probably optimize these cases better, but for now it's
                               1643                 :                :              * not worth the trouble.
                               1644                 :                :              */
 1538 akorotkov@postgresql     1645                 :             16 :             oldcontext = MemoryContextSwitchTo(state->base.sortcontext);
 4676 tgl@sss.pgh.pa.us        1646         [ +  + ]:         160088 :             while (ntuples-- > 0)
                               1647                 :                :             {
                               1648                 :                :                 SortTuple   stup;
                               1649                 :                : 
 3591 rhaas@postgresql.org     1650         [ -  + ]:         160072 :                 if (!tuplesort_gettuple_common(state, forward, &stup))
                               1651                 :                :                 {
 4675 tgl@sss.pgh.pa.us        1652                 :UBC           0 :                     MemoryContextSwitchTo(oldcontext);
 4676                          1653                 :              0 :                     return false;
                               1654                 :                :                 }
 4676 tgl@sss.pgh.pa.us        1655         [ -  + ]:CBC      160072 :                 CHECK_FOR_INTERRUPTS();
                               1656                 :                :             }
 4675                          1657                 :             16 :             MemoryContextSwitchTo(oldcontext);
 4676                          1658                 :             16 :             return true;
                               1659                 :                : 
 4676 tgl@sss.pgh.pa.us        1660                 :UBC           0 :         default:
                               1661         [ #  # ]:              0 :             elog(ERROR, "invalid tuplesort state");
                               1662                 :                :             return false;       /* keep compiler quiet */
                               1663                 :                :     }
                               1664                 :                : }
                               1665                 :                : 
                               1666                 :                : /*
                               1667                 :                :  * tuplesort_merge_order - report merge order we'll use for given memory
                               1668                 :                :  * (note: "merge order" just means the number of input tapes in the merge).
                               1669                 :                :  *
                               1670                 :                :  * This is exported for use by the planner.  allowedMem is in bytes.
                               1671                 :                :  */
                               1672                 :                : int
 4848 noah@leadboat.com        1673                 :CBC       10647 : tuplesort_merge_order(int64 allowedMem)
                               1674                 :                : {
                               1675                 :                :     int         mOrder;
                               1676                 :                : 
                               1677                 :                :     /*----------
                               1678                 :                :      * In the merge phase, we need buffer space for each input and output tape.
                               1679                 :                :      * Each pass in the balanced merge algorithm reads from M input tapes, and
                               1680                 :                :      * writes to N output tapes.  Each tape consumes TAPE_BUFFER_OVERHEAD bytes
                               1681                 :                :      * of memory.  In addition to that, we want MERGE_BUFFER_SIZE workspace per
                               1682                 :                :      * input tape.
                               1683                 :                :      *
                               1684                 :                :      * totalMem = M * (TAPE_BUFFER_OVERHEAD + MERGE_BUFFER_SIZE) +
                               1685                 :                :      *            N * TAPE_BUFFER_OVERHEAD
                               1686                 :                :      *
                               1687                 :                :      * Except for the last and next-to-last merge passes, where there can be
                               1688                 :                :      * fewer tapes left to process, M = N.  We choose M so that we have the
                               1689                 :                :      * desired amount of memory available for the input buffers
                               1690                 :                :      * (TAPE_BUFFER_OVERHEAD + MERGE_BUFFER_SIZE), given the total memory
                               1691                 :                :      * available for the tape buffers (allowedMem).
                               1692                 :                :      *
                               1693                 :                :      * Note: you might be thinking we need to account for the memtuples[]
                               1694                 :                :      * array in this calculation, but we effectively treat that as part of the
                               1695                 :                :      * MERGE_BUFFER_SIZE workspace.
                               1696                 :                :      *----------
                               1697                 :                :      */
 1820 heikki.linnakangas@i     1698                 :          10647 :     mOrder = allowedMem /
                               1699                 :                :         (2 * TAPE_BUFFER_OVERHEAD + MERGE_BUFFER_SIZE);
                               1700                 :                : 
                               1701                 :                :     /*
                               1702                 :                :      * Even in minimum memory, use at least a MINORDER merge.  On the other
                               1703                 :                :      * hand, even when we have lots of memory, do not use more than a MAXORDER
                               1704                 :                :      * merge.  Tapes are pretty cheap, but they're not entirely free.  Each
                               1705                 :                :      * additional tape reduces the amount of memory available to build runs,
                               1706                 :                :      * which in turn can cause the same sort to need more runs, which makes
                               1707                 :                :      * merging slower even if it can still be done in a single pass.  Also,
                               1708                 :                :      * high order merges are quite slow due to CPU cache effects; it can be
                               1709                 :                :      * faster to pay the I/O cost of a multi-pass merge than to perform a
                               1710                 :                :      * single merge pass across many hundreds of tapes.
                               1711                 :                :      */
 7533 tgl@sss.pgh.pa.us        1712                 :          10647 :     mOrder = Max(mOrder, MINORDER);
 3618 rhaas@postgresql.org     1713                 :          10647 :     mOrder = Min(mOrder, MAXORDER);
                               1714                 :                : 
 7533 tgl@sss.pgh.pa.us        1715                 :          10647 :     return mOrder;
                               1716                 :                : }
                               1717                 :                : 
                               1718                 :                : /*
                               1719                 :                :  * Helper function to calculate how much memory to allocate for the read buffer
                               1720                 :                :  * of each input tape in a merge pass.
                               1721                 :                :  *
                               1722                 :                :  * 'avail_mem' is the amount of memory available for the buffers of all the
                               1723                 :                :  *      tapes, both input and output.
                               1724                 :                :  * 'nInputTapes' and 'nInputRuns' are the number of input tapes and runs.
                               1725                 :                :  * 'maxOutputTapes' is the max. number of output tapes we should produce.
                               1726                 :                :  */
                               1727                 :                : static int64
 1820 heikki.linnakangas@i     1728                 :            260 : merge_read_buffer_size(int64 avail_mem, int nInputTapes, int nInputRuns,
                               1729                 :                :                        int maxOutputTapes)
                               1730                 :                : {
                               1731                 :                :     int         nOutputRuns;
                               1732                 :                :     int         nOutputTapes;
                               1733                 :                : 
                               1734                 :                :     /*
                               1735                 :                :      * How many output tapes will we produce in this pass?
                               1736                 :                :      *
                               1737                 :                :      * This is nInputRuns / nInputTapes, rounded up.
                               1738                 :                :      */
                               1739                 :            260 :     nOutputRuns = (nInputRuns + nInputTapes - 1) / nInputTapes;
                               1740                 :                : 
                               1741                 :            260 :     nOutputTapes = Min(nOutputRuns, maxOutputTapes);
                               1742                 :                : 
                               1743                 :                :     /*
                               1744                 :                :      * Each output tape consumes TAPE_BUFFER_OVERHEAD bytes of memory.  All
                               1745                 :                :      * remaining memory is divided evenly between the input tapes.
                               1746                 :                :      *
                               1747                 :                :      * This also follows from the formula in tuplesort_merge_order, but here
                               1748                 :                :      * we derive the input buffer size from the amount of memory available,
                               1749                 :                :      * and M and N.
                               1750                 :                :      */
                               1751                 :            260 :     return Max((avail_mem - TAPE_BUFFER_OVERHEAD * nOutputTapes) / nInputTapes, 0);
                               1752                 :                : }
                               1753                 :                : 
                               1754                 :                : /*
                               1755                 :                :  * inittapes - initialize for tape sorting.
                               1756                 :                :  *
                               1757                 :                :  * This is called only if we have found we won't sort in memory.
                               1758                 :                :  */
                               1759                 :                : static void
 3174 rhaas@postgresql.org     1760                 :            469 : inittapes(Tuplesortstate *state, bool mergeruns)
                               1761                 :                : {
                               1762   [ +  +  -  + ]:            469 :     Assert(!LEADER(state));
                               1763                 :                : 
                               1764         [ +  + ]:            469 :     if (mergeruns)
                               1765                 :                :     {
                               1766                 :                :         /* Compute number of input tapes to use when merging */
 1820 heikki.linnakangas@i     1767                 :             90 :         state->maxTapes = tuplesort_merge_order(state->allowedMem);
                               1768                 :                :     }
                               1769                 :                :     else
                               1770                 :                :     {
                               1771                 :                :         /* Workers can sometimes produce single run, output without merge */
 3174 rhaas@postgresql.org     1772   [ +  -  -  + ]:            379 :         Assert(WORKER(state));
 1820 heikki.linnakangas@i     1773                 :            379 :         state->maxTapes = MINORDER;
                               1774                 :                :     }
                               1775                 :                : 
 7679 tgl@sss.pgh.pa.us        1776         [ -  + ]:            469 :     if (trace_sort)
 2902 pg@bowt.ie               1777         [ #  # ]:UBC           0 :         elog(LOG, "worker %d switching to external sort with %d tapes: %s",
                               1778                 :                :              state->worker, state->maxTapes, pg_rusage_show(&state->ru_start));
                               1779                 :                : 
                               1780                 :                :     /* Create the tape set */
 1820 heikki.linnakangas@i     1781                 :CBC         469 :     inittapestate(state, state->maxTapes);
 3174 rhaas@postgresql.org     1782                 :            469 :     state->tapeset =
 1820 heikki.linnakangas@i     1783                 :            469 :         LogicalTapeSetCreate(false,
 3174 rhaas@postgresql.org     1784         [ +  + ]:            469 :                              state->shared ? &state->shared->fileset : NULL,
                               1785                 :                :                              state->worker);
                               1786                 :                : 
 3300                          1787                 :            469 :     state->currentRun = 0;
                               1788                 :                : 
                               1789                 :                :     /*
                               1790                 :                :      * Initialize logical tape arrays.
                               1791                 :                :      */
 1820 heikki.linnakangas@i     1792                 :            469 :     state->inputTapes = NULL;
                               1793                 :            469 :     state->nInputTapes = 0;
                               1794                 :            469 :     state->nInputRuns = 0;
                               1795                 :                : 
   56 michael@paquier.xyz      1796                 :GNC         469 :     state->outputTapes = palloc0_array(LogicalTape *, state->maxTapes);
 1820 heikki.linnakangas@i     1797                 :CBC         469 :     state->nOutputTapes = 0;
                               1798                 :            469 :     state->nOutputRuns = 0;
                               1799                 :                : 
 9857 tgl@sss.pgh.pa.us        1800                 :            469 :     state->status = TSS_BUILDRUNS;
                               1801                 :                : 
 1820 heikki.linnakangas@i     1802                 :            469 :     selectnewtape(state);
 9857 tgl@sss.pgh.pa.us        1803                 :            469 : }
                               1804                 :                : 
                               1805                 :                : /*
                               1806                 :                :  * inittapestate - initialize generic tape management state
                               1807                 :                :  */
                               1808                 :                : static void
 3174 rhaas@postgresql.org     1809                 :            599 : inittapestate(Tuplesortstate *state, int maxTapes)
                               1810                 :                : {
                               1811                 :                :     int64       tapeSpace;
                               1812                 :                : 
                               1813                 :                :     /*
                               1814                 :                :      * Decrease availMem to reflect the space needed for tape buffers; but
                               1815                 :                :      * don't decrease it to the point that we have no room for tuples. (That
                               1816                 :                :      * case is only likely to occur if sorting pass-by-value Datums; in all
                               1817                 :                :      * other scenarios the memtuples[] array is unlikely to occupy more than
                               1818                 :                :      * half of allowedMem.  In the pass-by-value case it's not important to
                               1819                 :                :      * account for tuple space, so we don't care if LACKMEM becomes
                               1820                 :                :      * inaccurate.)
                               1821                 :                :      */
                               1822                 :            599 :     tapeSpace = (int64) maxTapes * TAPE_BUFFER_OVERHEAD;
                               1823                 :                : 
                               1824         [ +  + ]:            599 :     if (tapeSpace + GetMemoryChunkSpace(state->memtuples) < state->allowedMem)
                               1825                 :            521 :         USEMEM(state, tapeSpace);
                               1826                 :                : 
                               1827                 :                :     /*
                               1828                 :                :      * Make sure that the temp file(s) underlying the tape set are created in
                               1829                 :                :      * suitable temp tablespaces.  For parallel sorts, this should have been
                               1830                 :                :      * called already, but it doesn't matter if it is called a second time.
                               1831                 :                :      */
                               1832                 :            599 :     PrepareTempTablespaces();
                               1833                 :            599 : }
                               1834                 :                : 
                               1835                 :                : /*
                               1836                 :                :  * selectnewtape -- select next tape to output to.
                               1837                 :                :  *
                               1838                 :                :  * This is called after finishing a run when we know another run
                               1839                 :                :  * must be started.  This is used both when building the initial
                               1840                 :                :  * runs, and during merge passes.
                               1841                 :                :  */
                               1842                 :                : static void
 9857 tgl@sss.pgh.pa.us        1843                 :           1304 : selectnewtape(Tuplesortstate *state)
                               1844                 :                : {
                               1845                 :                :     /*
                               1846                 :                :      * At the beginning of each merge pass, nOutputTapes and nOutputRuns are
                               1847                 :                :      * both zero.  On each call, we create a new output tape to hold the next
                               1848                 :                :      * run, until maxTapes is reached.  After that, we assign new runs to the
                               1849                 :                :      * existing tapes in a round robin fashion.
                               1850                 :                :      */
 1813 heikki.linnakangas@i     1851         [ +  + ]:           1304 :     if (state->nOutputTapes < state->maxTapes)
                               1852                 :                :     {
                               1853                 :                :         /* Create a new tape to hold the next run */
 1820                          1854         [ -  + ]:            876 :         Assert(state->outputTapes[state->nOutputRuns] == NULL);
                               1855         [ -  + ]:            876 :         Assert(state->nOutputRuns == state->nOutputTapes);
                               1856                 :            876 :         state->destTape = LogicalTapeCreate(state->tapeset);
 1813                          1857                 :            876 :         state->outputTapes[state->nOutputTapes] = state->destTape;
 1820                          1858                 :            876 :         state->nOutputTapes++;
                               1859                 :            876 :         state->nOutputRuns++;
                               1860                 :                :     }
                               1861                 :                :     else
                               1862                 :                :     {
                               1863                 :                :         /*
                               1864                 :                :          * We have reached the max number of tapes.  Append to an existing
                               1865                 :                :          * tape.
                               1866                 :                :          */
                               1867                 :            428 :         state->destTape = state->outputTapes[state->nOutputRuns % state->nOutputTapes];
                               1868                 :            428 :         state->nOutputRuns++;
                               1869                 :                :     }
 9857 tgl@sss.pgh.pa.us        1870                 :           1304 : }
                               1871                 :                : 
                               1872                 :                : /*
                               1873                 :                :  * Initialize the slab allocation arena, for the given number of slots.
                               1874                 :                :  */
                               1875                 :                : static void
 3661 heikki.linnakangas@i     1876                 :            220 : init_slab_allocator(Tuplesortstate *state, int numSlots)
                               1877                 :                : {
                               1878         [ +  + ]:            220 :     if (numSlots > 0)
                               1879                 :                :     {
                               1880                 :                :         char       *p;
                               1881                 :                :         int         i;
                               1882                 :                : 
                               1883                 :            204 :         state->slabMemoryBegin = palloc(numSlots * SLAB_SLOT_SIZE);
                               1884                 :            204 :         state->slabMemoryEnd = state->slabMemoryBegin +
                               1885                 :            204 :             numSlots * SLAB_SLOT_SIZE;
                               1886                 :            204 :         state->slabFreeHead = (SlabSlot *) state->slabMemoryBegin;
                               1887                 :            204 :         USEMEM(state, numSlots * SLAB_SLOT_SIZE);
                               1888                 :                : 
                               1889                 :            204 :         p = state->slabMemoryBegin;
                               1890         [ +  + ]:            802 :         for (i = 0; i < numSlots - 1; i++)
                               1891                 :                :         {
                               1892                 :            598 :             ((SlabSlot *) p)->nextfree = (SlabSlot *) (p + SLAB_SLOT_SIZE);
                               1893                 :            598 :             p += SLAB_SLOT_SIZE;
                               1894                 :                :         }
                               1895                 :            204 :         ((SlabSlot *) p)->nextfree = NULL;
                               1896                 :                :     }
                               1897                 :                :     else
                               1898                 :                :     {
                               1899                 :             16 :         state->slabMemoryBegin = state->slabMemoryEnd = NULL;
                               1900                 :             16 :         state->slabFreeHead = NULL;
                               1901                 :                :     }
                               1902                 :            220 :     state->slabAllocatorUsed = true;
                               1903                 :            220 : }
                               1904                 :                : 
                               1905                 :                : /*
                               1906                 :                :  * mergeruns -- merge all the completed initial runs.
                               1907                 :                :  *
                               1908                 :                :  * This implements the Balanced k-Way Merge Algorithm.  All input data has
                               1909                 :                :  * already been written to initial runs on tape (see dumptuples).
                               1910                 :                :  */
                               1911                 :                : static void
 9857 tgl@sss.pgh.pa.us        1912                 :            220 : mergeruns(Tuplesortstate *state)
                               1913                 :                : {
                               1914                 :                :     int         tapenum;
                               1915                 :                : 
                               1916         [ -  + ]:            220 :     Assert(state->status == TSS_BUILDRUNS);
 9844                          1917         [ -  + ]:            220 :     Assert(state->memtupcount == 0);
                               1918                 :                : 
 1538 akorotkov@postgresql     1919   [ +  +  +  + ]:            220 :     if (state->base.sortKeys != NULL && state->base.sortKeys->abbrev_converter != NULL)
                               1920                 :                :     {
                               1921                 :                :         /*
                               1922                 :                :          * If there are multiple runs to be merged, when we go to read back
                               1923                 :                :          * tuples from disk, abbreviated keys will not have been stored, and
                               1924                 :                :          * we don't care to regenerate them.  Disable abbreviation from this
                               1925                 :                :          * point on.
                               1926                 :                :          */
                               1927                 :             19 :         state->base.sortKeys->abbrev_converter = NULL;
                               1928                 :             19 :         state->base.sortKeys->comparator = state->base.sortKeys->abbrev_full_comparator;
                               1929                 :                : 
                               1930                 :                :         /* Not strictly necessary, but be tidy */
                               1931                 :             19 :         state->base.sortKeys->abbrev_abort = NULL;
                               1932                 :             19 :         state->base.sortKeys->abbrev_full_comparator = NULL;
                               1933                 :                :     }
                               1934                 :                : 
                               1935                 :                :     /*
                               1936                 :                :      * Reset tuple memory.  We've freed all the tuples that we previously
                               1937                 :                :      * allocated.  We will use the slab allocator from now on.
                               1938                 :                :      */
                               1939                 :            220 :     MemoryContextResetOnly(state->base.tuplecontext);
                               1940                 :                : 
                               1941                 :                :     /*
                               1942                 :                :      * We no longer need a large memtuples array.  (We will allocate a smaller
                               1943                 :                :      * one for the heap later.)
                               1944                 :                :      */
 3661 heikki.linnakangas@i     1945                 :            220 :     FREEMEM(state, GetMemoryChunkSpace(state->memtuples));
                               1946                 :            220 :     pfree(state->memtuples);
                               1947                 :            220 :     state->memtuples = NULL;
                               1948                 :                : 
                               1949                 :                :     /*
                               1950                 :                :      * Initialize the slab allocator.  We need one slab slot per input tape,
                               1951                 :                :      * for the tuples in the heap, plus one to hold the tuple last returned
                               1952                 :                :      * from tuplesort_gettuple.  (If we're sorting pass-by-val Datums,
                               1953                 :                :      * however, we don't need to do allocate anything.)
                               1954                 :                :      *
                               1955                 :                :      * In a multi-pass merge, we could shrink this allocation for the last
                               1956                 :                :      * merge pass, if it has fewer tapes than previous passes, but we don't
                               1957                 :                :      * bother.
                               1958                 :                :      *
                               1959                 :                :      * From this point on, we no longer use the USEMEM()/LACKMEM() mechanism
                               1960                 :                :      * to track memory usage of individual tuples.
                               1961                 :                :      */
 1538 akorotkov@postgresql     1962         [ +  + ]:            220 :     if (state->base.tuples)
 1820 heikki.linnakangas@i     1963                 :            204 :         init_slab_allocator(state, state->nOutputTapes + 1);
                               1964                 :                :     else
 3661                          1965                 :             16 :         init_slab_allocator(state, 0);
                               1966                 :                : 
                               1967                 :                :     /*
                               1968                 :                :      * Allocate a new 'memtuples' array, for the heap.  It will hold one tuple
                               1969                 :                :      * from each input tape.
                               1970                 :                :      *
                               1971                 :                :      * We could shrink this, too, between passes in a multi-pass merge, but we
                               1972                 :                :      * don't bother.  (The initial input tapes are still in outputTapes.  The
                               1973                 :                :      * number of input tapes will not increase between passes.)
                               1974                 :                :      */
 1820                          1975                 :            220 :     state->memtupsize = state->nOutputTapes;
 1538 akorotkov@postgresql     1976                 :            440 :     state->memtuples = (SortTuple *) MemoryContextAlloc(state->base.maincontext,
 1820 heikki.linnakangas@i     1977                 :            220 :                                                         state->nOutputTapes * sizeof(SortTuple));
 3595                          1978                 :            220 :     USEMEM(state, GetMemoryChunkSpace(state->memtuples));
                               1979                 :                : 
                               1980                 :                :     /*
                               1981                 :                :      * Use all the remaining memory we have available for tape buffers among
                               1982                 :                :      * all the input tapes.  At the beginning of each merge pass, we will
                               1983                 :                :      * divide this memory between the input and output tapes in the pass.
                               1984                 :                :      */
 1820                          1985                 :            220 :     state->tape_buffer_mem = state->availMem;
 1813                          1986                 :            220 :     USEMEM(state, state->tape_buffer_mem);
 3652                          1987         [ -  + ]:            220 :     if (trace_sort)
 1820 heikki.linnakangas@i     1988         [ #  # ]:UBC           0 :         elog(LOG, "worker %d using %zu KB of memory for tape buffers",
                               1989                 :                :              state->worker, state->tape_buffer_mem / 1024);
                               1990                 :                : 
                               1991                 :                :     for (;;)
                               1992                 :                :     {
                               1993                 :                :         /*
                               1994                 :                :          * On the first iteration, or if we have read all the runs from the
                               1995                 :                :          * input tapes in a multi-pass merge, it's time to start a new pass.
                               1996                 :                :          * Rewind all the output tapes, and make them inputs for the next
                               1997                 :                :          * pass.
                               1998                 :                :          */
 1820 heikki.linnakangas@i     1999         [ +  + ]:CBC         352 :         if (state->nInputRuns == 0)
                               2000                 :                :         {
                               2001                 :                :             int64       input_buffer_size;
                               2002                 :                : 
                               2003                 :                :             /* Close the old, emptied, input tapes */
                               2004         [ +  + ]:            260 :             if (state->nInputTapes > 0)
                               2005                 :                :             {
                               2006         [ +  + ]:            280 :                 for (tapenum = 0; tapenum < state->nInputTapes; tapenum++)
                               2007                 :            240 :                     LogicalTapeClose(state->inputTapes[tapenum]);
                               2008                 :             40 :                 pfree(state->inputTapes);
                               2009                 :                :             }
                               2010                 :                : 
                               2011                 :                :             /* Previous pass's outputs become next pass's inputs. */
                               2012                 :            260 :             state->inputTapes = state->outputTapes;
                               2013                 :            260 :             state->nInputTapes = state->nOutputTapes;
                               2014                 :            260 :             state->nInputRuns = state->nOutputRuns;
                               2015                 :                : 
                               2016                 :                :             /*
                               2017                 :                :              * Reset output tape variables.  The actual LogicalTapes will be
                               2018                 :                :              * created as needed, here we only allocate the array to hold
                               2019                 :                :              * them.
                               2020                 :                :              */
   56 michael@paquier.xyz      2021                 :GNC         260 :             state->outputTapes = palloc0_array(LogicalTape *, state->nInputTapes);
 1820 heikki.linnakangas@i     2022                 :CBC         260 :             state->nOutputTapes = 0;
                               2023                 :            260 :             state->nOutputRuns = 0;
                               2024                 :                : 
                               2025                 :                :             /*
                               2026                 :                :              * Redistribute the memory allocated for tape buffers, among the
                               2027                 :                :              * new input and output tapes.
                               2028                 :                :              */
                               2029                 :            260 :             input_buffer_size = merge_read_buffer_size(state->tape_buffer_mem,
                               2030                 :                :                                                        state->nInputTapes,
                               2031                 :                :                                                        state->nInputRuns,
                               2032                 :                :                                                        state->maxTapes);
                               2033                 :                : 
                               2034         [ -  + ]:            260 :             if (trace_sort)
 1820 heikki.linnakangas@i     2035         [ #  # ]:UBC           0 :                 elog(LOG, "starting merge pass of %d input runs on %d tapes, " INT64_FORMAT " KB of memory for each input tape: %s",
                               2036                 :                :                      state->nInputRuns, state->nInputTapes, input_buffer_size / 1024,
                               2037                 :                :                      pg_rusage_show(&state->ru_start));
                               2038                 :                : 
                               2039                 :                :             /* Prepare the new input tapes for merge pass. */
 1820 heikki.linnakangas@i     2040         [ +  + ]:CBC        1026 :             for (tapenum = 0; tapenum < state->nInputTapes; tapenum++)
                               2041                 :            766 :                 LogicalTapeRewindForRead(state->inputTapes[tapenum], input_buffer_size);
                               2042                 :                : 
                               2043                 :                :             /*
                               2044                 :                :              * If there's just one run left on each input tape, then only one
                               2045                 :                :              * merge pass remains.  If we don't have to produce a materialized
                               2046                 :                :              * sorted tape, we can stop at this point and do the final merge
                               2047                 :                :              * on-the-fly.
                               2048                 :                :              */
 1538 akorotkov@postgresql     2049         [ +  + ]:            260 :             if ((state->base.sortopt & TUPLESORT_RANDOMACCESS) == 0
 1652 drowley@postgresql.o     2050         [ +  + ]:            242 :                 && state->nInputRuns <= state->nInputTapes
 1820 heikki.linnakangas@i     2051   [ +  +  +  - ]:            206 :                 && !WORKER(state))
                               2052                 :                :             {
                               2053                 :                :                 /* Tell logtape.c we won't be writing anymore */
 7524 tgl@sss.pgh.pa.us        2054                 :            206 :                 LogicalTapeSetForgetFreeSpace(state->tapeset);
                               2055                 :                :                 /* Initialize for the final merge pass */
 3661 heikki.linnakangas@i     2056                 :            206 :                 beginmerge(state);
 9857 tgl@sss.pgh.pa.us        2057                 :            206 :                 state->status = TSS_FINALMERGE;
                               2058                 :            206 :                 return;
                               2059                 :                :             }
                               2060                 :                :         }
                               2061                 :                : 
                               2062                 :                :         /* Select an output tape */
 1820 heikki.linnakangas@i     2063                 :            146 :         selectnewtape(state);
                               2064                 :                : 
                               2065                 :                :         /* Merge one run from each input tape. */
                               2066                 :            146 :         mergeonerun(state);
                               2067                 :                : 
                               2068                 :                :         /*
                               2069                 :                :          * If the input tapes are empty, and we output only one output run,
                               2070                 :                :          * we're done.  The current output tape contains the final result.
                               2071                 :                :          */
                               2072   [ +  +  +  + ]:            146 :         if (state->nInputRuns == 0 && state->nOutputRuns <= 1)
                               2073                 :             14 :             break;
                               2074                 :                :     }
                               2075                 :                : 
                               2076                 :                :     /*
                               2077                 :                :      * Done.  The result is on a single run on a single tape.
                               2078                 :                :      */
                               2079                 :             14 :     state->result_tape = state->outputTapes[0];
 3174 rhaas@postgresql.org     2080   [ -  +  -  - ]:             14 :     if (!WORKER(state))
 1820 heikki.linnakangas@i     2081                 :             14 :         LogicalTapeFreeze(state->result_tape, NULL);
                               2082                 :                :     else
 3174 rhaas@postgresql.org     2083                 :UBC           0 :         worker_freeze_result_tape(state);
 9857 tgl@sss.pgh.pa.us        2084                 :CBC          14 :     state->status = TSS_SORTEDONTAPE;
                               2085                 :                : 
                               2086                 :                :     /* Close all the now-empty input tapes, to release their read buffers. */
 1820 heikki.linnakangas@i     2087         [ +  + ]:             62 :     for (tapenum = 0; tapenum < state->nInputTapes; tapenum++)
                               2088                 :             48 :         LogicalTapeClose(state->inputTapes[tapenum]);
                               2089                 :                : }
                               2090                 :                : 
                               2091                 :                : /*
                               2092                 :                :  * Merge one run from each input tape.
                               2093                 :                :  */
                               2094                 :                : static void
 9857 tgl@sss.pgh.pa.us        2095                 :            146 : mergeonerun(Tuplesortstate *state)
                               2096                 :                : {
                               2097                 :                :     int         srcTapeIndex;
                               2098                 :                :     LogicalTape *srcTape;
                               2099                 :                : 
                               2100                 :                :     /*
                               2101                 :                :      * Start the merge by loading one tuple from each active source tape into
                               2102                 :                :      * the heap.
                               2103                 :                :      */
 3661 heikki.linnakangas@i     2104                 :            146 :     beginmerge(state);
                               2105                 :                : 
 1502 drowley@postgresql.o     2106         [ -  + ]:            146 :     Assert(state->slabAllocatorUsed);
                               2107                 :                : 
                               2108                 :                :     /*
                               2109                 :                :      * Execute merge by repeatedly extracting lowest tuple in heap, writing it
                               2110                 :                :      * out, and replacing it with next tuple from same tape (if there is
                               2111                 :                :      * another one).
                               2112                 :                :      */
 9844 tgl@sss.pgh.pa.us        2113         [ +  + ]:         980650 :     while (state->memtupcount > 0)
                               2114                 :                :     {
                               2115                 :                :         SortTuple   stup;
                               2116                 :                : 
                               2117                 :                :         /* write the tuple to destTape */
 1820 heikki.linnakangas@i     2118                 :         980504 :         srcTapeIndex = state->memtuples[0].srctape;
                               2119                 :         980504 :         srcTape = state->inputTapes[srcTapeIndex];
                               2120                 :         980504 :         WRITETUP(state, state->destTape, &state->memtuples[0]);
                               2121                 :                : 
                               2122                 :                :         /* recycle the slot of the tuple we just wrote out, for the next read */
 3556 tgl@sss.pgh.pa.us        2123         [ +  + ]:         980504 :         if (state->memtuples[0].tuple)
                               2124   [ +  -  +  - ]:         890416 :             RELEASE_SLAB_SLOT(state, state->memtuples[0].tuple);
                               2125                 :                : 
                               2126                 :                :         /*
                               2127                 :                :          * pull next tuple from the tape, and replace the written-out tuple in
                               2128                 :                :          * the heap with it.
                               2129                 :                :          */
 3661 heikki.linnakangas@i     2130         [ +  + ]:         980504 :         if (mergereadnext(state, srcTape, &stup))
                               2131                 :                :         {
 1820                          2132                 :         979788 :             stup.srctape = srcTapeIndex;
 3300 rhaas@postgresql.org     2133                 :         979788 :             tuplesort_heap_replace_top(state, &stup);
                               2134                 :                :         }
                               2135                 :                :         else
                               2136                 :                :         {
                               2137                 :            716 :             tuplesort_heap_delete_top(state);
 1820 heikki.linnakangas@i     2138                 :            716 :             state->nInputRuns--;
                               2139                 :                :         }
                               2140                 :                :     }
                               2141                 :                : 
                               2142                 :                :     /*
                               2143                 :                :      * When the heap empties, we're done.  Write an end-of-run marker on the
                               2144                 :                :      * output tape.
                               2145                 :                :      */
                               2146                 :            146 :     markrunend(state->destTape);
 9857 tgl@sss.pgh.pa.us        2147                 :            146 : }
                               2148                 :                : 
                               2149                 :                : /*
                               2150                 :                :  * beginmerge - initialize for a merge pass
                               2151                 :                :  *
                               2152                 :                :  * Fill the merge heap with the first tuple from each input tape.
                               2153                 :                :  */
                               2154                 :                : static void
 3661 heikki.linnakangas@i     2155                 :            352 : beginmerge(Tuplesortstate *state)
                               2156                 :                : {
                               2157                 :                :     int         activeTapes;
                               2158                 :                :     int         srcTapeIndex;
                               2159                 :                : 
                               2160                 :                :     /* Heap should be empty here */
 9844 tgl@sss.pgh.pa.us        2161         [ -  + ]:            352 :     Assert(state->memtupcount == 0);
                               2162                 :                : 
 1820 heikki.linnakangas@i     2163                 :            352 :     activeTapes = Min(state->nInputTapes, state->nInputRuns);
                               2164                 :                : 
                               2165         [ +  + ]:           1546 :     for (srcTapeIndex = 0; srcTapeIndex < activeTapes; srcTapeIndex++)
                               2166                 :                :     {
                               2167                 :                :         SortTuple   tup;
                               2168                 :                : 
                               2169         [ +  + ]:           1194 :         if (mergereadnext(state, state->inputTapes[srcTapeIndex], &tup))
                               2170                 :                :         {
                               2171                 :            999 :             tup.srctape = srcTapeIndex;
 3300 rhaas@postgresql.org     2172                 :            999 :             tuplesort_heap_insert(state, &tup);
                               2173                 :                :         }
                               2174                 :                :     }
 3861                          2175                 :            352 : }
                               2176                 :                : 
                               2177                 :                : /*
                               2178                 :                :  * mergereadnext - read next tuple from one merge input tape
                               2179                 :                :  *
                               2180                 :                :  * Returns false on EOF.
                               2181                 :                :  */
                               2182                 :                : static bool
 1820 heikki.linnakangas@i     2183                 :        3728027 : mergereadnext(Tuplesortstate *state, LogicalTape *srcTape, SortTuple *stup)
                               2184                 :                : {
                               2185                 :                :     unsigned int tuplen;
                               2186                 :                : 
                               2187                 :                :     /* read next tuple, if any */
                               2188         [ +  + ]:        3728027 :     if ((tuplen = getlen(srcTape, true)) == 0)
 3661                          2189                 :           1174 :         return false;
                               2190                 :        3726853 :     READTUP(state, stup, srcTape, tuplen);
                               2191                 :                : 
                               2192                 :        3726853 :     return true;
                               2193                 :                : }
                               2194                 :                : 
                               2195                 :                : /*
                               2196                 :                :  * dumptuples - remove tuples from memtuples and write initial run to tape
                               2197                 :                :  *
                               2198                 :                :  * When alltuples = true, dump everything currently in memory.  (This case is
                               2199                 :                :  * only used at end of input data.)
                               2200                 :                :  */
                               2201                 :                : static void
 9857 tgl@sss.pgh.pa.us        2202                 :         771562 : dumptuples(Tuplesortstate *state, bool alltuples)
                               2203                 :                : {
                               2204                 :                :     int         memtupwrite;
                               2205                 :                :     int         i;
                               2206                 :                : 
                               2207                 :                :     /*
                               2208                 :                :      * Nothing to do if we still fit in available memory and have array slots,
                               2209                 :                :      * unless this is the final call during initial run generation.
                               2210                 :                :      */
 3300 rhaas@postgresql.org     2211   [ +  +  +  +  :         771562 :     if (state->memtupcount < state->memtupsize && !LACKMEM(state) &&
                                              -  + ]
                               2212         [ +  + ]:         770873 :         !alltuples)
                               2213                 :         770404 :         return;
                               2214                 :                : 
                               2215                 :                :     /*
                               2216                 :                :      * Final call might require no sorting, in rare cases where we just so
                               2217                 :                :      * happen to have previously LACKMEM()'d at the point where exactly all
                               2218                 :                :      * remaining tuples are loaded into memory, just before input was
                               2219                 :                :      * exhausted.  In general, short final runs are quite possible, but avoid
                               2220                 :                :      * creating a completely empty run.  In a worker, though, we must produce
                               2221                 :                :      * at least one tape, even if it's empty.
                               2222                 :                :      */
 1820 heikki.linnakangas@i     2223   [ +  +  -  + ]:           1158 :     if (state->memtupcount == 0 && state->currentRun > 0)
 1820 heikki.linnakangas@i     2224                 :UBC           0 :         return;
                               2225                 :                : 
 3839 rhaas@postgresql.org     2226         [ -  + ]:CBC        1158 :     Assert(state->status == TSS_BUILDRUNS);
                               2227                 :                : 
                               2228                 :                :     /*
                               2229                 :                :      * It seems unlikely that this limit will ever be exceeded, but take no
                               2230                 :                :      * chances
                               2231                 :                :      */
                               2232         [ -  + ]:           1158 :     if (state->currentRun == INT_MAX)
 3839 rhaas@postgresql.org     2233         [ #  # ]:UBC           0 :         ereport(ERROR,
                               2234                 :                :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               2235                 :                :                  errmsg("cannot have more than %d runs for an external sort",
                               2236                 :                :                         INT_MAX)));
                               2237                 :                : 
 1820 heikki.linnakangas@i     2238         [ +  + ]:CBC        1158 :     if (state->currentRun > 0)
                               2239                 :            689 :         selectnewtape(state);
                               2240                 :                : 
 3839 rhaas@postgresql.org     2241                 :           1158 :     state->currentRun++;
                               2242                 :                : 
                               2243         [ -  + ]:           1158 :     if (trace_sort)
 2902 pg@bowt.ie               2244         [ #  # ]:UBC           0 :         elog(LOG, "worker %d starting quicksort of run %d: %s",
                               2245                 :                :              state->worker, state->currentRun,
                               2246                 :                :              pg_rusage_show(&state->ru_start));
                               2247                 :                : 
                               2248                 :                :     /*
                               2249                 :                :      * Sort all tuples accumulated within the allowed amount of memory for
                               2250                 :                :      * this run.
                               2251                 :                :      */
 3839 rhaas@postgresql.org     2252                 :CBC        1158 :     tuplesort_sort_memtuples(state);
                               2253                 :                : 
                               2254         [ -  + ]:           1158 :     if (trace_sort)
 2902 pg@bowt.ie               2255         [ #  # ]:UBC           0 :         elog(LOG, "worker %d finished quicksort of run %d: %s",
                               2256                 :                :              state->worker, state->currentRun,
                               2257                 :                :              pg_rusage_show(&state->ru_start));
                               2258                 :                : 
 3839 rhaas@postgresql.org     2259                 :CBC        1158 :     memtupwrite = state->memtupcount;
                               2260         [ +  + ]:        3087655 :     for (i = 0; i < memtupwrite; i++)
                               2261                 :                :     {
 1502 drowley@postgresql.o     2262                 :        3086497 :         SortTuple  *stup = &state->memtuples[i];
                               2263                 :                : 
                               2264                 :        3086497 :         WRITETUP(state, state->destTape, stup);
                               2265                 :                :     }
                               2266                 :                : 
                               2267                 :           1158 :     state->memtupcount = 0;
                               2268                 :                : 
                               2269                 :                :     /*
                               2270                 :                :      * Reset tuple memory.  We've freed all of the tuples that we previously
                               2271                 :                :      * allocated.  It's important to avoid fragmentation when there is a stark
                               2272                 :                :      * change in the sizes of incoming tuples.  In bounded sorts,
                               2273                 :                :      * fragmentation due to AllocSetFree's bucketing by size class might be
                               2274                 :                :      * particularly bad if this step wasn't taken.
                               2275                 :                :      */
 1538 akorotkov@postgresql     2276                 :           1158 :     MemoryContextReset(state->base.tuplecontext);
                               2277                 :                : 
                               2278                 :                :     /*
                               2279                 :                :      * Now update the memory accounting to subtract the memory used by the
                               2280                 :                :      * tuple.
                               2281                 :                :      */
  917 drowley@postgresql.o     2282                 :           1158 :     FREEMEM(state, state->tupleMem);
                               2283                 :           1158 :     state->tupleMem = 0;
                               2284                 :                : 
 1820 heikki.linnakangas@i     2285                 :           1158 :     markrunend(state->destTape);
                               2286                 :                : 
 3839 rhaas@postgresql.org     2287         [ -  + ]:           1158 :     if (trace_sort)
 2902 pg@bowt.ie               2288         [ #  # ]:UBC           0 :         elog(LOG, "worker %d finished writing run %d to tape %d: %s",
                               2289                 :                :              state->worker, state->currentRun, (state->currentRun - 1) % state->nOutputTapes + 1,
                               2290                 :                :              pg_rusage_show(&state->ru_start));
                               2291                 :                : }
                               2292                 :                : 
                               2293                 :                : /*
                               2294                 :                :  * tuplesort_rescan     - rewind and replay the scan
                               2295                 :                :  */
                               2296                 :                : void
 9857 tgl@sss.pgh.pa.us        2297                 :CBC          38 : tuplesort_rescan(Tuplesortstate *state)
                               2298                 :                : {
 1538 akorotkov@postgresql     2299                 :             38 :     MemoryContext oldcontext = MemoryContextSwitchTo(state->base.sortcontext);
                               2300                 :                : 
                               2301         [ -  + ]:             38 :     Assert(state->base.sortopt & TUPLESORT_RANDOMACCESS);
                               2302                 :                : 
 9857 tgl@sss.pgh.pa.us        2303      [ +  +  - ]:             38 :     switch (state->status)
                               2304                 :                :     {
                               2305                 :             33 :         case TSS_SORTEDINMEM:
                               2306                 :             33 :             state->current = 0;
                               2307                 :             33 :             state->eof_reached = false;
                               2308                 :             33 :             state->markpos_offset = 0;
                               2309                 :             33 :             state->markpos_eof = false;
                               2310                 :             33 :             break;
                               2311                 :              5 :         case TSS_SORTEDONTAPE:
 1820 heikki.linnakangas@i     2312                 :              5 :             LogicalTapeRewindForRead(state->result_tape, 0);
 9857 tgl@sss.pgh.pa.us        2313                 :              5 :             state->eof_reached = false;
                               2314                 :              5 :             state->markpos_block = 0L;
                               2315                 :              5 :             state->markpos_offset = 0;
                               2316                 :              5 :             state->markpos_eof = false;
                               2317                 :              5 :             break;
 9857 tgl@sss.pgh.pa.us        2318                 :UBC           0 :         default:
 8480                          2319         [ #  # ]:              0 :             elog(ERROR, "invalid tuplesort state");
                               2320                 :                :             break;
                               2321                 :                :     }
                               2322                 :                : 
 7533 tgl@sss.pgh.pa.us        2323                 :CBC          38 :     MemoryContextSwitchTo(oldcontext);
 9857                          2324                 :             38 : }
                               2325                 :                : 
                               2326                 :                : /*
                               2327                 :                :  * tuplesort_markpos    - saves current position in the merged sort file
                               2328                 :                :  */
                               2329                 :                : void
                               2330                 :         357137 : tuplesort_markpos(Tuplesortstate *state)
                               2331                 :                : {
 1538 akorotkov@postgresql     2332                 :         357137 :     MemoryContext oldcontext = MemoryContextSwitchTo(state->base.sortcontext);
                               2333                 :                : 
                               2334         [ -  + ]:         357137 :     Assert(state->base.sortopt & TUPLESORT_RANDOMACCESS);
                               2335                 :                : 
 9857 tgl@sss.pgh.pa.us        2336      [ +  +  - ]:         357137 :     switch (state->status)
                               2337                 :                :     {
                               2338                 :         351265 :         case TSS_SORTEDINMEM:
                               2339                 :         351265 :             state->markpos_offset = state->current;
                               2340                 :         351265 :             state->markpos_eof = state->eof_reached;
                               2341                 :         351265 :             break;
                               2342                 :           5872 :         case TSS_SORTEDONTAPE:
 1820 heikki.linnakangas@i     2343                 :           5872 :             LogicalTapeTell(state->result_tape,
                               2344                 :                :                             &state->markpos_block,
                               2345                 :                :                             &state->markpos_offset);
 9857 tgl@sss.pgh.pa.us        2346                 :           5872 :             state->markpos_eof = state->eof_reached;
                               2347                 :           5872 :             break;
 9857 tgl@sss.pgh.pa.us        2348                 :UBC           0 :         default:
 8480                          2349         [ #  # ]:              0 :             elog(ERROR, "invalid tuplesort state");
                               2350                 :                :             break;
                               2351                 :                :     }
                               2352                 :                : 
 7533 tgl@sss.pgh.pa.us        2353                 :CBC      357137 :     MemoryContextSwitchTo(oldcontext);
 9857                          2354                 :         357137 : }
                               2355                 :                : 
                               2356                 :                : /*
                               2357                 :                :  * tuplesort_restorepos - restores current position in merged sort file to
                               2358                 :                :  *                        last saved position
                               2359                 :                :  */
                               2360                 :                : void
                               2361                 :          28306 : tuplesort_restorepos(Tuplesortstate *state)
                               2362                 :                : {
 1538 akorotkov@postgresql     2363                 :          28306 :     MemoryContext oldcontext = MemoryContextSwitchTo(state->base.sortcontext);
                               2364                 :                : 
                               2365         [ -  + ]:          28306 :     Assert(state->base.sortopt & TUPLESORT_RANDOMACCESS);
                               2366                 :                : 
 9857 tgl@sss.pgh.pa.us        2367      [ +  +  - ]:          28306 :     switch (state->status)
                               2368                 :                :     {
                               2369                 :          24178 :         case TSS_SORTEDINMEM:
                               2370                 :          24178 :             state->current = state->markpos_offset;
                               2371                 :          24178 :             state->eof_reached = state->markpos_eof;
                               2372                 :          24178 :             break;
                               2373                 :           4128 :         case TSS_SORTEDONTAPE:
 1820 heikki.linnakangas@i     2374                 :           4128 :             LogicalTapeSeek(state->result_tape,
                               2375                 :                :                             state->markpos_block,
                               2376                 :                :                             state->markpos_offset);
 9857 tgl@sss.pgh.pa.us        2377                 :           4128 :             state->eof_reached = state->markpos_eof;
                               2378                 :           4128 :             break;
 9857 tgl@sss.pgh.pa.us        2379                 :UBC           0 :         default:
 8480                          2380         [ #  # ]:              0 :             elog(ERROR, "invalid tuplesort state");
                               2381                 :                :             break;
                               2382                 :                :     }
                               2383                 :                : 
 7533 tgl@sss.pgh.pa.us        2384                 :CBC       28306 :     MemoryContextSwitchTo(oldcontext);
 9857                          2385                 :          28306 : }
                               2386                 :                : 
                               2387                 :                : /*
                               2388                 :                :  * tuplesort_get_stats - extract summary statistics
                               2389                 :                :  *
                               2390                 :                :  * This can be called after tuplesort_performsort() finishes to obtain
                               2391                 :                :  * printable summary information about how the sort was performed.
                               2392                 :                :  */
                               2393                 :                : void
 6272                          2394                 :            264 : tuplesort_get_stats(Tuplesortstate *state,
                               2395                 :                :                     TuplesortInstrumentation *stats)
                               2396                 :                : {
                               2397                 :                :     /*
                               2398                 :                :      * Note: it might seem we should provide both memory and disk usage for a
                               2399                 :                :      * disk-based sort.  However, the current code doesn't track memory space
                               2400                 :                :      * accurately once we have begun to return tuples to the caller (since we
                               2401                 :                :      * don't account for pfree's the caller is expected to do), so we cannot
                               2402                 :                :      * rely on availMem in a disk sort.  This does not seem worth the overhead
                               2403                 :                :      * to fix.  Is it worth creating an API for the memory context code to
                               2404                 :                :      * tell us how much is actually used in sortcontext?
                               2405                 :                :      */
 2380 tomas.vondra@postgre     2406                 :            264 :     tuplesort_updatemax(state);
                               2407                 :                : 
                               2408         [ +  + ]:            264 :     if (state->isMaxSpaceDisk)
 3331 rhaas@postgresql.org     2409                 :              4 :         stats->spaceType = SORT_SPACE_TYPE_DISK;
                               2410                 :                :     else
                               2411                 :            260 :         stats->spaceType = SORT_SPACE_TYPE_MEMORY;
 2380 tomas.vondra@postgre     2412                 :            264 :     stats->spaceUsed = (state->maxSpace + 1023) / 1024;
                               2413                 :                : 
                               2414   [ +  -  +  - ]:            264 :     switch (state->maxSpaceStatus)
                               2415                 :                :     {
 7101 tgl@sss.pgh.pa.us        2416                 :            260 :         case TSS_SORTEDINMEM:
                               2417         [ +  + ]:            260 :             if (state->boundUsed)
 3331 rhaas@postgresql.org     2418                 :             28 :                 stats->sortMethod = SORT_TYPE_TOP_N_HEAPSORT;
                               2419                 :                :             else
                               2420                 :            232 :                 stats->sortMethod = SORT_TYPE_QUICKSORT;
 7101 tgl@sss.pgh.pa.us        2421                 :            260 :             break;
 7101 tgl@sss.pgh.pa.us        2422                 :UBC           0 :         case TSS_SORTEDONTAPE:
 3331 rhaas@postgresql.org     2423                 :              0 :             stats->sortMethod = SORT_TYPE_EXTERNAL_SORT;
 7101 tgl@sss.pgh.pa.us        2424                 :              0 :             break;
 7101 tgl@sss.pgh.pa.us        2425                 :CBC           4 :         case TSS_FINALMERGE:
 3331 rhaas@postgresql.org     2426                 :              4 :             stats->sortMethod = SORT_TYPE_EXTERNAL_MERGE;
 7101 tgl@sss.pgh.pa.us        2427                 :              4 :             break;
 7101 tgl@sss.pgh.pa.us        2428                 :UBC           0 :         default:
 3331 rhaas@postgresql.org     2429                 :              0 :             stats->sortMethod = SORT_TYPE_STILL_IN_PROGRESS;
 7101 tgl@sss.pgh.pa.us        2430                 :              0 :             break;
                               2431                 :                :     }
 7101 tgl@sss.pgh.pa.us        2432                 :CBC         264 : }
                               2433                 :                : 
                               2434                 :                : /*
                               2435                 :                :  * Convert TuplesortMethod to a string.
                               2436                 :                :  */
                               2437                 :                : const char *
 3331 rhaas@postgresql.org     2438                 :            196 : tuplesort_method_name(TuplesortMethod m)
                               2439                 :                : {
                               2440   [ -  +  +  -  :            196 :     switch (m)
                                              +  - ]
                               2441                 :                :     {
 3331 rhaas@postgresql.org     2442                 :UBC           0 :         case SORT_TYPE_STILL_IN_PROGRESS:
                               2443                 :              0 :             return "still in progress";
 3331 rhaas@postgresql.org     2444                 :CBC          28 :         case SORT_TYPE_TOP_N_HEAPSORT:
                               2445                 :             28 :             return "top-N heapsort";
                               2446                 :            164 :         case SORT_TYPE_QUICKSORT:
                               2447                 :            164 :             return "quicksort";
 3331 rhaas@postgresql.org     2448                 :UBC           0 :         case SORT_TYPE_EXTERNAL_SORT:
                               2449                 :              0 :             return "external sort";
 3331 rhaas@postgresql.org     2450                 :CBC           4 :         case SORT_TYPE_EXTERNAL_MERGE:
                               2451                 :              4 :             return "external merge";
                               2452                 :                :     }
                               2453                 :                : 
 3331 rhaas@postgresql.org     2454                 :UBC           0 :     return "unknown";
                               2455                 :                : }
                               2456                 :                : 
                               2457                 :                : /*
                               2458                 :                :  * Convert TuplesortSpaceType to a string.
                               2459                 :                :  */
                               2460                 :                : const char *
 3331 rhaas@postgresql.org     2461                 :CBC         172 : tuplesort_space_type_name(TuplesortSpaceType t)
                               2462                 :                : {
                               2463   [ +  +  -  + ]:            172 :     Assert(t == SORT_SPACE_TYPE_DISK || t == SORT_SPACE_TYPE_MEMORY);
                               2464         [ +  + ]:            172 :     return t == SORT_SPACE_TYPE_DISK ? "Disk" : "Memory";
                               2465                 :                : }
                               2466                 :                : 
                               2467                 :                : 
                               2468                 :                : /*
                               2469                 :                :  * Heap manipulation routines, per Knuth's Algorithm 5.2.3H.
                               2470                 :                :  */
                               2471                 :                : 
                               2472                 :                : /*
                               2473                 :                :  * Convert the existing unordered array of SortTuples to a bounded heap,
                               2474                 :                :  * discarding all but the smallest "state->bound" tuples.
                               2475                 :                :  *
                               2476                 :                :  * When working with a bounded heap, we want to keep the largest entry
                               2477                 :                :  * at the root (array entry zero), instead of the smallest as in the normal
                               2478                 :                :  * sort case.  This allows us to discard the largest entry cheaply.
                               2479                 :                :  * Therefore, we temporarily reverse the sort direction.
                               2480                 :                :  */
                               2481                 :                : static void
 7101 tgl@sss.pgh.pa.us        2482                 :            264 : make_bounded_heap(Tuplesortstate *state)
                               2483                 :                : {
 6906 bruce@momjian.us         2484                 :            264 :     int         tupcount = state->memtupcount;
                               2485                 :                :     int         i;
                               2486                 :                : 
 7101 tgl@sss.pgh.pa.us        2487         [ -  + ]:            264 :     Assert(state->status == TSS_INITIAL);
                               2488         [ -  + ]:            264 :     Assert(state->bounded);
                               2489         [ -  + ]:            264 :     Assert(tupcount >= state->bound);
 3174 rhaas@postgresql.org     2490         [ -  + ]:            264 :     Assert(SERIAL(state));
                               2491                 :                : 
                               2492                 :                :     /* Reverse sort direction so largest entry will be at root */
 4357                          2493                 :            264 :     reversedirection(state);
                               2494                 :                : 
 7101 tgl@sss.pgh.pa.us        2495                 :            264 :     state->memtupcount = 0;      /* make the heap empty */
 6906 bruce@momjian.us         2496         [ +  + ]:          34308 :     for (i = 0; i < tupcount; i++)
                               2497                 :                :     {
 3683 heikki.linnakangas@i     2498         [ +  + ]:          34044 :         if (state->memtupcount < state->bound)
                               2499                 :                :         {
                               2500                 :                :             /* Insert next tuple into heap */
                               2501                 :                :             /* Must copy source tuple to avoid possible overwrite */
 6906 bruce@momjian.us         2502                 :          16890 :             SortTuple   stup = state->memtuples[i];
                               2503                 :                : 
 3300 rhaas@postgresql.org     2504                 :          16890 :             tuplesort_heap_insert(state, &stup);
                               2505                 :                :         }
                               2506                 :                :         else
                               2507                 :                :         {
                               2508                 :                :             /*
                               2509                 :                :              * The heap is full.  Replace the largest entry with the new
                               2510                 :                :              * tuple, or just discard it, if it's larger than anything already
                               2511                 :                :              * in the heap.
                               2512                 :                :              */
 3683 heikki.linnakangas@i     2513         [ +  + ]:          17154 :             if (COMPARETUP(state, &state->memtuples[i], &state->memtuples[0]) <= 0)
                               2514                 :                :             {
                               2515                 :           7623 :                 free_sort_tuple(state, &state->memtuples[i]);
                               2516         [ -  + ]:           7623 :                 CHECK_FOR_INTERRUPTS();
                               2517                 :                :             }
                               2518                 :                :             else
 3300 rhaas@postgresql.org     2519                 :           9531 :                 tuplesort_heap_replace_top(state, &state->memtuples[i]);
                               2520                 :                :         }
                               2521                 :                :     }
                               2522                 :                : 
 7101 tgl@sss.pgh.pa.us        2523         [ -  + ]:            264 :     Assert(state->memtupcount == state->bound);
                               2524                 :            264 :     state->status = TSS_BOUNDED;
                               2525                 :            264 : }
                               2526                 :                : 
                               2527                 :                : /*
                               2528                 :                :  * Convert the bounded heap to a properly-sorted array
                               2529                 :                :  */
                               2530                 :                : static void
                               2531                 :            264 : sort_bounded_heap(Tuplesortstate *state)
                               2532                 :                : {
 6906 bruce@momjian.us         2533                 :            264 :     int         tupcount = state->memtupcount;
                               2534                 :                : 
 7101 tgl@sss.pgh.pa.us        2535         [ -  + ]:            264 :     Assert(state->status == TSS_BOUNDED);
                               2536         [ -  + ]:            264 :     Assert(state->bounded);
                               2537         [ -  + ]:            264 :     Assert(tupcount == state->bound);
 3174 rhaas@postgresql.org     2538         [ -  + ]:            264 :     Assert(SERIAL(state));
                               2539                 :                : 
                               2540                 :                :     /*
                               2541                 :                :      * We can unheapify in place because each delete-top call will remove the
                               2542                 :                :      * largest entry, which we can promptly store in the newly freed slot at
                               2543                 :                :      * the end.  Once we're down to a single-entry heap, we're done.
                               2544                 :                :      */
 7101 tgl@sss.pgh.pa.us        2545         [ +  + ]:          16890 :     while (state->memtupcount > 1)
                               2546                 :                :     {
 6906 bruce@momjian.us         2547                 :          16626 :         SortTuple   stup = state->memtuples[0];
                               2548                 :                : 
                               2549                 :                :         /* this sifts-up the next-largest entry and decreases memtupcount */
 3300 rhaas@postgresql.org     2550                 :          16626 :         tuplesort_heap_delete_top(state);
 7101 tgl@sss.pgh.pa.us        2551                 :          16626 :         state->memtuples[state->memtupcount] = stup;
                               2552                 :                :     }
                               2553                 :            264 :     state->memtupcount = tupcount;
                               2554                 :                : 
                               2555                 :                :     /*
                               2556                 :                :      * Reverse sort direction back to the original state.  This is not
                               2557                 :                :      * actually necessary but seems like a good idea for tidiness.
                               2558                 :                :      */
 4357 rhaas@postgresql.org     2559                 :            264 :     reversedirection(state);
                               2560                 :                : 
 7101 tgl@sss.pgh.pa.us        2561                 :            264 :     state->status = TSS_SORTEDINMEM;
                               2562                 :            264 :     state->boundUsed = true;
                               2563                 :            264 : }
                               2564                 :                : 
                               2565                 :                : 
                               2566                 :                : /* radix sort routines */
                               2567                 :                : 
                               2568                 :                : /*
                               2569                 :                :  * Retrieve byte from datum, indexed by 'level': 0 for MSB, 7 for LSB
                               2570                 :                :  */
                               2571                 :                : static inline uint8
  240 john.naylor@postgres     2572                 :       26428626 : current_byte(Datum key, int level)
                               2573                 :                : {
                               2574                 :       26428626 :     int         shift = (sizeof(Datum) - 1 - level) * BITS_PER_BYTE;
                               2575                 :                : 
                               2576                 :       26428626 :     return (key >> shift) & 0xFF;
                               2577                 :                : }
                               2578                 :                : 
                               2579                 :                : /*
                               2580                 :                :  * Normalize datum such that unsigned comparison is order-preserving,
                               2581                 :                :  * taking ASC/DESC into account as well.
                               2582                 :                :  */
                               2583                 :                : static inline Datum
                               2584                 :       26476043 : normalize_datum(Datum orig, SortSupport ssup)
                               2585                 :                : {
                               2586                 :                :     Datum       norm_datum1;
                               2587                 :                : 
   63 john.naylor@postgres     2588         [ +  + ]:GNC    26476043 :     if (ssup->comparator == ssup_datum_int64_cmp)
  166 john.naylor@postgres     2589                 :CBC     1110020 :         norm_datum1 = orig + (Int64GetDatum(PG_INT64_MAX)) + 1;
   63 john.naylor@postgres     2590         [ +  + ]:GNC    25366023 :     else if (ssup->comparator == ssup_datum_uint64_cmp)
                               2591                 :        6959343 :         norm_datum1 = orig;
                               2592                 :                :     else
                               2593                 :                :     {
                               2594                 :                :         /*
                               2595                 :                :          * Truncate to uint32. For the int32 case, we don't need to do this,
                               2596                 :                :          * but it forces the upper half of the datum to be zero regardless of
                               2597                 :                :          * sign.
                               2598                 :                :          */
                               2599                 :       18406680 :         uint32      u32 = DatumGetUInt32(orig);
                               2600                 :                : 
                               2601         [ +  + ]:       18406680 :         if (ssup->comparator == ssup_datum_int32_cmp)
                               2602                 :        7799114 :             norm_datum1 = UInt32GetDatum(u32 + ((uint32) PG_INT32_MAX) + 1);
                               2603                 :                :         else
                               2604                 :                :         {
                               2605                 :       10607566 :             norm_datum1 = UInt32GetDatum(u32);
                               2606         [ -  + ]:       10607566 :             Assert(ssup->comparator == ssup_datum_uint32_cmp);
                               2607                 :                :         }
                               2608                 :                :     }
                               2609                 :                : 
  240 john.naylor@postgres     2610         [ +  + ]:CBC    26476043 :     if (ssup->ssup_reverse)
                               2611                 :         787998 :         norm_datum1 = ~norm_datum1;
                               2612                 :                : 
                               2613                 :       26476043 :     return norm_datum1;
                               2614                 :                : }
                               2615                 :                : 
                               2616                 :                : /*
                               2617                 :                :  * radix_sort_recursive
                               2618                 :                :  *
                               2619                 :                :  * Radix sort by (pass-by-value) datum1, diverting to qsort_tuple()
                               2620                 :                :  * for tiebreaks.
                               2621                 :                :  *
                               2622                 :                :  * This is a modification of ska_byte_sort() from
                               2623                 :                :  * https://github.com/skarupke/ska_sort
                               2624                 :                :  * The original copyright notice follows:
                               2625                 :                :  *
                               2626                 :                :  * Copyright Malte Skarupke 2016.
                               2627                 :                :  * Distributed under the Boost Software License, Version 1.0.
                               2628                 :                :  *
                               2629                 :                :  * Boost Software License - Version 1.0 - August 17th, 2003
                               2630                 :                :  *
                               2631                 :                :  * Permission is hereby granted, free of charge, to any person or organization
                               2632                 :                :  * obtaining a copy of the software and accompanying documentation covered by
                               2633                 :                :  * this license (the "Software") to use, reproduce, display, distribute,
                               2634                 :                :  * execute, and transmit the Software, and to prepare derivative works of the
                               2635                 :                :  * Software, and to permit third-parties to whom the Software is furnished to
                               2636                 :                :  * do so, all subject to the following:
                               2637                 :                :  *
                               2638                 :                :  * The copyright notices in the Software and this entire statement, including
                               2639                 :                :  * the above license grant, this restriction and the following disclaimer,
                               2640                 :                :  * must be included in all copies of the Software, in whole or in part, and
                               2641                 :                :  * all derivative works of the Software, unless such copies or derivative
                               2642                 :                :  * works are solely in the form of machine-executable object code generated by
                               2643                 :                :  * a source language processor.
                               2644                 :                :  *
                               2645                 :                :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                               2646                 :                :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                               2647                 :                :  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
                               2648                 :                :  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
                               2649                 :                :  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
                               2650                 :                :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
                               2651                 :                :  * DEALINGS IN THE SOFTWARE.
                               2652                 :                :  */
                               2653                 :                : static void
                               2654                 :          47417 : radix_sort_recursive(SortTuple *begin, size_t n_elems, int level, Tuplesortstate *state)
                               2655                 :                : {
                               2656                 :          47417 :     RadixSortInfo partitions[256] = {0};
                               2657                 :                :     uint8       remaining_partitions[256];
                               2658                 :          47417 :     size_t      total = 0;
                               2659                 :          47417 :     int         num_partitions = 0;
                               2660                 :                :     int         num_remaining;
                               2661                 :          47417 :     SortSupport ssup = &state->base.sortKeys[0];
                               2662                 :                :     Datum       ref_datum;
  194                          2663                 :          47417 :     Datum       common_upper_bits = 0;
  240                          2664                 :          47417 :     size_t      start_offset = 0;
                               2665                 :          47417 :     SortTuple  *partition_begin = begin;
                               2666                 :                :     int         next_level;
                               2667                 :                : 
                               2668                 :                :     /* count number of occurrences of each byte */
  194                          2669                 :          47417 :     ref_datum = normalize_datum(begin[0].datum1, ssup);
  240                          2670         [ +  + ]:       26476043 :     for (SortTuple *st = begin; st < begin + n_elems; st++)
                               2671                 :                :     {
                               2672                 :                :         Datum       this_datum;
                               2673                 :                :         uint8       this_partition;
                               2674                 :                : 
  194                          2675                 :       26428626 :         this_datum = normalize_datum(st->datum1, ssup);
                               2676                 :                :         /* accumulate bits different from the reference datum */
                               2677                 :       26428626 :         common_upper_bits |= ref_datum ^ this_datum;
                               2678                 :                : 
                               2679                 :                :         /* extract the byte for this level from the normalized datum */
                               2680                 :       26428626 :         this_partition = current_byte(this_datum, level);
                               2681                 :                : 
                               2682                 :                :         /* save it for the permutation step */
  240                          2683                 :       26428626 :         st->curbyte = this_partition;
                               2684                 :                : 
                               2685                 :       26428626 :         partitions[this_partition].count++;
                               2686                 :                : 
                               2687         [ +  + ]:       26428626 :         CHECK_FOR_INTERRUPTS();
                               2688                 :                :     }
                               2689                 :                : 
                               2690                 :                :     /* compute partition offsets */
                               2691         [ +  + ]:       12186169 :     for (int i = 0; i < 256; i++)
                               2692                 :                :     {
                               2693                 :       12138752 :         size_t      count = partitions[i].count;
                               2694                 :                : 
                               2695         [ +  + ]:       12138752 :         if (count != 0)
                               2696                 :                :         {
                               2697                 :        2639308 :             partitions[i].offset = total;
                               2698                 :        2639308 :             total += count;
                               2699                 :        2639308 :             remaining_partitions[num_partitions] = i;
                               2700                 :        2639308 :             num_partitions++;
                               2701                 :                :         }
                               2702                 :       12138752 :         partitions[i].next_offset = total;
                               2703                 :                :     }
                               2704                 :                : 
                               2705                 :                :     /*
                               2706                 :                :      * Swap tuples to correct partition.
                               2707                 :                :      *
                               2708                 :                :      * In traditional American flag sort, a swap sends the current element to
                               2709                 :                :      * the correct partition, but the array pointer only advances if the
                               2710                 :                :      * partner of the swap happens to be an element that belongs in the
                               2711                 :                :      * current partition. That only requires one pass through the array, but
                               2712                 :                :      * the disadvantage is we don't know if the pointer can advance until the
                               2713                 :                :      * swap completes. Here lies the most interesting innovation from the
                               2714                 :                :      * upstream ska_byte_sort: After initiating the swap, we immediately
                               2715                 :                :      * proceed to the next element. This makes better use of CPU pipelining,
                               2716                 :                :      * but also means that we will often need multiple iterations of this
                               2717                 :                :      * loop. ska_byte_sort() maintains a separate list of which partitions
                               2718                 :                :      * haven't finished, which is updated every loop iteration. Here we simply
                               2719                 :                :      * check each partition during every iteration.
                               2720                 :                :      *
                               2721                 :                :      * If we started with a single partition, there is nothing to do. If a
                               2722                 :                :      * previous loop iteration results in only one partition that hasn't been
                               2723                 :                :      * counted as sorted, we know it's actually sorted and can exit the loop.
                               2724                 :                :      */
                               2725                 :          47417 :     num_remaining = num_partitions;
                               2726         [ +  + ]:         195781 :     while (num_remaining > 1)
                               2727                 :                :     {
                               2728                 :                :         /* start the count over */
                               2729                 :         148364 :         num_remaining = num_partitions;
                               2730                 :                : 
                               2731         [ +  + ]:       11721862 :         for (int i = 0; i < num_partitions; i++)
                               2732                 :                :         {
                               2733                 :       11573498 :             uint8       idx = remaining_partitions[i];
                               2734                 :                : 
                               2735                 :       11573498 :             for (SortTuple *st = begin + partitions[idx].offset;
                               2736         [ +  + ]:       28699642 :                  st < begin + partitions[idx].next_offset;
                               2737                 :       17126144 :                  st++)
                               2738                 :                :             {
                               2739                 :       17126144 :                 size_t      offset = partitions[st->curbyte].offset++;
                               2740                 :                :                 SortTuple   tmp;
                               2741                 :                : 
                               2742                 :                :                 /* swap current tuple with destination position */
                               2743         [ -  + ]:       17126144 :                 Assert(offset < n_elems);
                               2744                 :       17126144 :                 tmp = *st;
                               2745                 :       17126144 :                 *st = begin[offset];
                               2746                 :       17126144 :                 begin[offset] = tmp;
                               2747                 :                : 
                               2748         [ +  + ]:       17126144 :                 CHECK_FOR_INTERRUPTS();
                               2749                 :                :             };
                               2750                 :                : 
                               2751                 :                :             /* Is this partition sorted? */
                               2752         [ +  + ]:       11573498 :             if (partitions[idx].offset == partitions[idx].next_offset)
                               2753                 :        8935222 :                 num_remaining--;
                               2754                 :                :         }
                               2755                 :                :     }
                               2756                 :                : 
                               2757                 :                :     /* recurse */
                               2758                 :                : 
  194                          2759         [ +  + ]:          47417 :     if (num_partitions == 1)
                               2760                 :                :     {
                               2761                 :                :         /*
                               2762                 :                :          * There is only one distinct byte at the current level. It can happen
                               2763                 :                :          * that some subsequent bytes are also the same for all input values,
                               2764                 :                :          * such as the upper bytes of small integers. To skip unproductive
                               2765                 :                :          * passes for that case, we compute the level where the input has more
                               2766                 :                :          * than one distinct byte, so that the next recursion can start there.
                               2767                 :                :          */
                               2768         [ +  + ]:           9314 :         if (common_upper_bits == 0)
                               2769                 :            999 :             next_level = sizeof(Datum);
                               2770                 :                :         else
                               2771                 :                :         {
                               2772                 :                :             int         diffpos;
                               2773                 :                : 
                               2774                 :                :             /*
                               2775                 :                :              * The upper bits of common_upper_bits are zero where all datums
                               2776                 :                :              * have the same bits.
                               2777                 :                :              */
                               2778                 :           8315 :             diffpos = pg_leftmost_one_pos64(DatumGetUInt64(common_upper_bits));
                               2779                 :           8315 :             next_level = sizeof(Datum) - 1 - (diffpos / BITS_PER_BYTE);
                               2780                 :                :         }
                               2781                 :                :     }
                               2782                 :                :     else
                               2783                 :          38103 :         next_level = level + 1;
                               2784                 :                : 
  166                          2785         [ -  + ]:          47417 :     Assert(next_level > level);
                               2786                 :                : 
  240                          2787                 :          47417 :     for (uint8 *rp = remaining_partitions;
                               2788         [ +  + ]:        2686725 :          rp < remaining_partitions + num_partitions;
                               2789                 :        2639308 :          rp++)
                               2790                 :                :     {
                               2791                 :        2639308 :         size_t      end_offset = partitions[*rp].next_offset;
                               2792                 :        2639308 :         SortTuple  *partition_end = begin + end_offset;
                               2793                 :        2639308 :         size_t      num_elements = end_offset - start_offset;
                               2794                 :                : 
                               2795         [ +  + ]:        2639308 :         if (num_elements > 1)
                               2796                 :                :         {
  194                          2797         [ +  + ]:         870089 :             if (next_level < sizeof(Datum))
                               2798                 :                :             {
  240                          2799         [ +  + ]:         682003 :                 if (num_elements < QSORT_THRESHOLD)
                               2800                 :                :                 {
                               2801                 :         640078 :                     qsort_tuple(partition_begin,
                               2802                 :                :                                 num_elements,
                               2803                 :                :                                 state->base.comparetup,
                               2804                 :                :                                 state);
                               2805                 :                :                 }
                               2806                 :                :                 else
                               2807                 :                :                 {
                               2808                 :          41925 :                     radix_sort_recursive(partition_begin,
                               2809                 :                :                                          num_elements,
                               2810                 :                :                                          next_level,
                               2811                 :                :                                          state);
                               2812                 :                :                 }
                               2813                 :                :             }
                               2814         [ +  + ]:         188086 :             else if (state->base.onlyKey == NULL)
                               2815                 :                :             {
                               2816                 :                :                 /*
                               2817                 :                :                  * We've finished radix sort on all bytes of the pass-by-value
                               2818                 :                :                  * datum (possibly abbreviated), now sort using the tiebreak
                               2819                 :                :                  * comparator.
                               2820                 :                :                  */
                               2821                 :          92639 :                 qsort_tuple(partition_begin,
                               2822                 :                :                             num_elements,
                               2823                 :                :                             state->base.comparetup_tiebreak,
                               2824                 :                :                             state);
                               2825                 :                :             }
                               2826                 :                :         }
                               2827                 :                : 
                               2828                 :        2639308 :         start_offset = end_offset;
                               2829                 :        2639308 :         partition_begin = partition_end;
                               2830                 :                :     }
                               2831                 :          47417 : }
                               2832                 :                : 
                               2833                 :                : /*
                               2834                 :                :  * Entry point for radix_sort_recursive
                               2835                 :                :  *
                               2836                 :                :  * Partition tuples by isnull1, then sort both partitions, using
                               2837                 :                :  * radix sort on the NOT NULL partition if it's large enough.
                               2838                 :                :  */
                               2839                 :                : static void
                               2840                 :           7472 : radix_sort_tuple(SortTuple *data, size_t n, Tuplesortstate *state)
                               2841                 :                : {
                               2842                 :           7472 :     bool        nulls_first = state->base.sortKeys[0].ssup_nulls_first;
                               2843                 :                :     SortTuple  *null_start;
                               2844                 :                :     SortTuple  *not_null_start;
                               2845                 :           7472 :     size_t      d1 = 0,
                               2846                 :                :                 d2,
                               2847                 :                :                 null_count,
                               2848                 :                :                 not_null_count;
                               2849                 :                : 
                               2850                 :                :     /*
                               2851                 :                :      * Find the first NOT NULL if NULLS FIRST, or first NULL if NULLS LAST.
                               2852                 :                :      * This also serves as a quick check for the common case where all tuples
                               2853                 :                :      * are NOT NULL in the first sort key with the default order ASC NULLS
                               2854                 :                :      * LAST.
                               2855                 :                :      */
                               2856   [ +  +  +  + ]:       13317230 :     while (d1 < n && data[d1].isnull1 == nulls_first)
                               2857                 :                :     {
                               2858                 :       13309758 :         d1++;
                               2859         [ +  + ]:       13309758 :         CHECK_FOR_INTERRUPTS();
                               2860                 :                :     }
                               2861                 :                : 
                               2862                 :                :     /*
                               2863                 :                :      * If we have more than one tuple left after the quick check, partition
                               2864                 :                :      * the remainder using branchless cyclic permutation, based on
                               2865                 :                :      * https://orlp.net/blog/branchless-lomuto-partitioning/
                               2866                 :                :      */
                               2867         [ -  + ]:           7472 :     Assert(n > 0);
                               2868         [ +  + ]:           7472 :     if (d1 < n - 1)
                               2869                 :                :     {
                               2870                 :            733 :         size_t      i = d1,
                               2871                 :            733 :                     j = d1;
                               2872                 :            733 :         SortTuple   tmp = data[d1]; /* create gap at front */
                               2873                 :                : 
                               2874         [ +  + ]:         433720 :         while (j < n - 1)
                               2875                 :                :         {
                               2876                 :                :             /* gap is at j, move i's element to gap */
                               2877                 :         432987 :             data[j] = data[i];
                               2878                 :                :             /* advance j to the first unknown element */
                               2879                 :         432987 :             j += 1;
                               2880                 :                :             /* move the first unknown element back to i */
                               2881                 :         432987 :             data[i] = data[j];
                               2882                 :                :             /* advance i if this element belongs in the left partition */
                               2883                 :         432987 :             i += (data[i].isnull1 == nulls_first);
                               2884                 :                : 
                               2885         [ -  + ]:         432987 :             CHECK_FOR_INTERRUPTS();
                               2886                 :                :         }
                               2887                 :                : 
                               2888                 :                :         /* place gap between left and right partitions */
                               2889                 :            733 :         data[j] = data[i];
                               2890                 :                :         /* restore the saved element */
                               2891                 :            733 :         data[i] = tmp;
                               2892                 :                :         /* assign it to the correct partition */
                               2893                 :            733 :         i += (data[i].isnull1 == nulls_first);
                               2894                 :                : 
                               2895                 :                :         /* d1 is now the number of elements in the left partition */
                               2896                 :            733 :         d1 = i;
                               2897                 :                :     }
                               2898                 :                : 
                               2899                 :           7472 :     d2 = n - d1;
                               2900                 :                : 
                               2901                 :                :     /* set pointers and counts for each partition */
                               2902         [ +  + ]:           7472 :     if (nulls_first)
                               2903                 :                :     {
                               2904                 :            628 :         null_start = data;
                               2905                 :            628 :         null_count = d1;
                               2906                 :            628 :         not_null_start = data + d1;
                               2907                 :            628 :         not_null_count = d2;
                               2908                 :                :     }
                               2909                 :                :     else
                               2910                 :                :     {
                               2911                 :           6844 :         not_null_start = data;
                               2912                 :           6844 :         not_null_count = d1;
                               2913                 :           6844 :         null_start = data + d1;
                               2914                 :           6844 :         null_count = d2;
                               2915                 :                :     }
                               2916                 :                : 
                               2917                 :           7472 :     for (SortTuple *st = null_start;
                               2918         [ +  + ]:           9759 :          st < null_start + null_count;
                               2919                 :           2287 :          st++)
                               2920         [ -  + ]:           2287 :         Assert(st->isnull1 == true);
                               2921                 :           7472 :     for (SortTuple *st = not_null_start;
                               2922         [ +  + ]:       13748667 :          st < not_null_start + not_null_count;
                               2923                 :       13741195 :          st++)
                               2924         [ -  + ]:       13741195 :         Assert(st->isnull1 == false);
                               2925                 :                : 
                               2926                 :                :     /*
                               2927                 :                :      * Sort the NULL partition using tiebreak comparator, if necessary.
                               2928                 :                :      */
                               2929   [ +  +  +  + ]:           7472 :     if (state->base.onlyKey == NULL && null_count > 1)
                               2930                 :                :     {
                               2931                 :            111 :         qsort_tuple(null_start,
                               2932                 :                :                     null_count,
                               2933                 :                :                     state->base.comparetup_tiebreak,
                               2934                 :                :                     state);
                               2935                 :                :     }
                               2936                 :                : 
                               2937                 :                :     /*
                               2938                 :                :      * Sort the NOT NULL partition, using radix sort if large enough,
                               2939                 :                :      * otherwise fall back to quicksort.
                               2940                 :                :      */
                               2941         [ +  + ]:           7472 :     if (not_null_count < QSORT_THRESHOLD)
                               2942                 :                :     {
                               2943                 :             14 :         qsort_tuple(not_null_start,
                               2944                 :                :                     not_null_count,
                               2945                 :                :                     state->base.comparetup,
                               2946                 :                :                     state);
                               2947                 :                :     }
                               2948                 :                :     else
                               2949                 :                :     {
                               2950                 :           7458 :         bool        presorted = true;
                               2951                 :                : 
                               2952                 :           7458 :         for (SortTuple *st = not_null_start + 1;
                               2953         [ +  + ]:        5076494 :              st < not_null_start + not_null_count;
                               2954                 :        5069036 :              st++)
                               2955                 :                :         {
                               2956         [ +  + ]:        5074528 :             if (COMPARETUP(state, st - 1, st) > 0)
                               2957                 :                :             {
                               2958                 :           5492 :                 presorted = false;
                               2959                 :           5492 :                 break;
                               2960                 :                :             }
                               2961                 :                : 
                               2962         [ -  + ]:        5069036 :             CHECK_FOR_INTERRUPTS();
                               2963                 :                :         }
                               2964                 :                : 
                               2965         [ +  + ]:           7458 :         if (presorted)
                               2966                 :           1966 :             return;
                               2967                 :                :         else
                               2968                 :                :         {
                               2969                 :           5492 :             radix_sort_recursive(not_null_start,
                               2970                 :                :                                  not_null_count,
                               2971                 :                :                                  0,
                               2972                 :                :                                  state);
                               2973                 :                :         }
                               2974                 :                :     }
                               2975                 :                : }
                               2976                 :                : 
                               2977                 :                : /* Verify in-memory sort using standard comparator. */
                               2978                 :                : static void
                               2979                 :           7472 : verify_memtuples_sorted(Tuplesortstate *state)
                               2980                 :                : {
                               2981                 :                : #ifdef USE_ASSERT_CHECKING
                               2982                 :           7472 :     for (SortTuple *st = state->memtuples + 1;
                               2983         [ +  + ]:       13743482 :          st < state->memtuples + state->memtupcount;
                               2984                 :       13736010 :          st++)
                               2985         [ -  + ]:       13736010 :         Assert(COMPARETUP(state, st - 1, st) <= 0);
                               2986                 :                : #endif
                               2987                 :           7472 : }
                               2988                 :                : 
                               2989                 :                : /*
                               2990                 :                :  * Sort all memtuples using specialized routines.
                               2991                 :                :  *
                               2992                 :                :  * Quicksort or radix sort is used for small in-memory sorts,
                               2993                 :                :  * and external sort runs.
                               2994                 :                :  */
                               2995                 :                : static void
 3839 rhaas@postgresql.org     2996                 :         147414 : tuplesort_sort_memtuples(Tuplesortstate *state)
                               2997                 :                : {
 3174                          2998   [ +  +  -  + ]:         147414 :     Assert(!LEADER(state));
                               2999                 :                : 
 3839                          3000         [ +  + ]:         147414 :     if (state->memtupcount > 1)
                               3001                 :                :     {
                               3002                 :                :         /*
                               3003                 :                :          * Do we have the leading column's value or abbreviation in datum1?
                               3004                 :                :          */
 1538 akorotkov@postgresql     3005   [ +  +  +  + ]:          44271 :         if (state->base.haveDatum1 && state->base.sortKeys)
                               3006                 :                :         {
  240 john.naylor@postgres     3007                 :          44182 :             SortSupport ssup = &state->base.sortKeys[0];
                               3008                 :                : 
                               3009                 :                :             /* Does it compare as an integer? */
                               3010         [ +  + ]:          44182 :             if (state->memtupcount >= QSORT_THRESHOLD &&
   63 john.naylor@postgres     3011         [ +  + ]:GNC        8585 :                 (ssup->comparator == ssup_datum_uint64_cmp ||
                               3012         [ +  + ]:           8018 :                  ssup->comparator == ssup_datum_int64_cmp ||
                               3013         [ +  + ]:           7831 :                  ssup->comparator == ssup_datum_uint32_cmp ||
  240 john.naylor@postgres     3014         [ +  + ]:CBC        4289 :                  ssup->comparator == ssup_datum_int32_cmp))
                               3015                 :                :             {
                               3016                 :           7472 :                 radix_sort_tuple(state->memtuples,
                               3017                 :           7472 :                                  state->memtupcount,
                               3018                 :                :                                  state);
                               3019                 :           7472 :                 verify_memtuples_sorted(state);
 1652 tmunro@postgresql.or     3020                 :           7472 :                 return;
                               3021                 :                :             }
                               3022                 :                :         }
                               3023                 :                : 
                               3024                 :                :         /* Can we use the single-key sort function? */
 1538 akorotkov@postgresql     3025         [ +  + ]:          36799 :         if (state->base.onlyKey != NULL)
                               3026                 :                :         {
 3839 rhaas@postgresql.org     3027                 :          26415 :             qsort_ssup(state->memtuples, state->memtupcount,
 1538 akorotkov@postgresql     3028                 :          26415 :                        state->base.onlyKey);
                               3029                 :                :         }
                               3030                 :                :         else
                               3031                 :                :         {
 3839 rhaas@postgresql.org     3032                 :          10384 :             qsort_tuple(state->memtuples,
                               3033                 :          10384 :                         state->memtupcount,
                               3034                 :                :                         state->base.comparetup,
                               3035                 :                :                         state);
                               3036                 :                :         }
                               3037                 :                :     }
                               3038                 :                : }
                               3039                 :                : 
                               3040                 :                : /*
                               3041                 :                :  * Insert a new tuple into an empty or existing heap, maintaining the
                               3042                 :                :  * heap invariant.  Caller is responsible for ensuring there's room.
                               3043                 :                :  *
                               3044                 :                :  * Note: For some callers, tuple points to a memtuples[] entry above the
                               3045                 :                :  * end of the heap.  This is safe as long as it's not immediately adjacent
                               3046                 :                :  * to the end of the heap (ie, in the [memtupcount] array entry) --- if it
                               3047                 :                :  * is, it might get overwritten before being moved into the heap!
                               3048                 :                :  */
                               3049                 :                : static void
 3300                          3050                 :          17889 : tuplesort_heap_insert(Tuplesortstate *state, SortTuple *tuple)
                               3051                 :                : {
                               3052                 :                :     SortTuple  *memtuples;
                               3053                 :                :     int         j;
                               3054                 :                : 
 9844 tgl@sss.pgh.pa.us        3055                 :          17889 :     memtuples = state->memtuples;
 7533                          3056         [ -  + ]:          17889 :     Assert(state->memtupcount < state->memtupsize);
                               3057                 :                : 
 5319 rhaas@postgresql.org     3058         [ +  + ]:          17889 :     CHECK_FOR_INTERRUPTS();
                               3059                 :                : 
                               3060                 :                :     /*
                               3061                 :                :      * Sift-up the new entry, per Knuth 5.2.3 exercise 16. Note that Knuth is
                               3062                 :                :      * using 1-based array indexes, not 0-based.
                               3063                 :                :      */
 9844 tgl@sss.pgh.pa.us        3064                 :          17889 :     j = state->memtupcount++;
                               3065         [ +  + ]:          47677 :     while (j > 0)
                               3066                 :                :     {
 9679 bruce@momjian.us         3067                 :          43438 :         int         i = (j - 1) >> 1;
                               3068                 :                : 
 3300 rhaas@postgresql.org     3069         [ +  + ]:          43438 :         if (COMPARETUP(state, tuple, &memtuples[i]) >= 0)
 9857 tgl@sss.pgh.pa.us        3070                 :          13650 :             break;
 9844                          3071                 :          29788 :         memtuples[j] = memtuples[i];
 9857                          3072                 :          29788 :         j = i;
                               3073                 :                :     }
 7533                          3074                 :          17889 :     memtuples[j] = *tuple;
 9857                          3075                 :          17889 : }
                               3076                 :                : 
                               3077                 :                : /*
                               3078                 :                :  * Remove the tuple at state->memtuples[0] from the heap.  Decrement
                               3079                 :                :  * memtupcount, and sift up to maintain the heap invariant.
                               3080                 :                :  *
                               3081                 :                :  * The caller has already free'd the tuple the top node points to,
                               3082                 :                :  * if necessary.
                               3083                 :                :  */
                               3084                 :                : static void
 3300 rhaas@postgresql.org     3085                 :          17605 : tuplesort_heap_delete_top(Tuplesortstate *state)
                               3086                 :                : {
 7533 tgl@sss.pgh.pa.us        3087                 :          17605 :     SortTuple  *memtuples = state->memtuples;
                               3088                 :                :     SortTuple  *tuple;
                               3089                 :                : 
 9844                          3090         [ +  + ]:          17605 :     if (--state->memtupcount <= 0)
 9857                          3091                 :            257 :         return;
                               3092                 :                : 
                               3093                 :                :     /*
                               3094                 :                :      * Remove the last tuple in the heap, and re-insert it, by replacing the
                               3095                 :                :      * current top node with it.
                               3096                 :                :      */
 3683 heikki.linnakangas@i     3097                 :          17348 :     tuple = &memtuples[state->memtupcount];
 3300 rhaas@postgresql.org     3098                 :          17348 :     tuplesort_heap_replace_top(state, tuple);
                               3099                 :                : }
                               3100                 :                : 
                               3101                 :                : /*
                               3102                 :                :  * Replace the tuple at state->memtuples[0] with a new tuple.  Sift up to
                               3103                 :                :  * maintain the heap invariant.
                               3104                 :                :  *
                               3105                 :                :  * This corresponds to Knuth's "sift-up" algorithm (Algorithm 5.2.3H,
                               3106                 :                :  * Heapsort, steps H3-H8).
                               3107                 :                :  */
                               3108                 :                : static void
                               3109                 :        4087433 : tuplesort_heap_replace_top(Tuplesortstate *state, SortTuple *tuple)
                               3110                 :                : {
 3683 heikki.linnakangas@i     3111                 :        4087433 :     SortTuple  *memtuples = state->memtuples;
                               3112                 :                :     unsigned int i,
                               3113                 :                :                 n;
                               3114                 :                : 
                               3115         [ -  + ]:        4087433 :     Assert(state->memtupcount >= 1);
                               3116                 :                : 
 5319 rhaas@postgresql.org     3117         [ +  + ]:        4087433 :     CHECK_FOR_INTERRUPTS();
                               3118                 :                : 
                               3119                 :                :     /*
                               3120                 :                :      * state->memtupcount is "int", but we use "unsigned int" for i, j, n.
                               3121                 :                :      * This prevents overflow in the "2 * i + 1" calculation, since at the top
                               3122                 :                :      * of the loop we must have i < n <= INT_MAX <= UINT_MAX/2.
                               3123                 :                :      */
 9844 tgl@sss.pgh.pa.us        3124                 :        4087433 :     n = state->memtupcount;
 9857                          3125                 :        4087433 :     i = 0;                      /* i is where the "hole" is */
                               3126                 :                :     for (;;)
 9844                          3127                 :        1326975 :     {
 3379                          3128                 :        5414408 :         unsigned int j = 2 * i + 1;
                               3129                 :                : 
 9857                          3130         [ +  + ]:        5414408 :         if (j >= n)
                               3131                 :         969317 :             break;
 9679 bruce@momjian.us         3132   [ +  +  +  + ]:        6084919 :         if (j + 1 < n &&
 3300 rhaas@postgresql.org     3133                 :        1639828 :             COMPARETUP(state, &memtuples[j], &memtuples[j + 1]) > 0)
 9857 tgl@sss.pgh.pa.us        3134                 :         663613 :             j++;
 3300 rhaas@postgresql.org     3135         [ +  + ]:        4445091 :         if (COMPARETUP(state, tuple, &memtuples[j]) <= 0)
 9857 tgl@sss.pgh.pa.us        3136                 :        3118116 :             break;
 9844                          3137                 :        1326975 :         memtuples[i] = memtuples[j];
 9857                          3138                 :        1326975 :         i = j;
                               3139                 :                :     }
 7533                          3140                 :        4087433 :     memtuples[i] = *tuple;
 9857                          3141                 :        4087433 : }
                               3142                 :                : 
                               3143                 :                : /*
                               3144                 :                :  * Function to reverse the sort direction from its current state
                               3145                 :                :  *
                               3146                 :                :  * It is not safe to call this when performing hash tuplesorts
                               3147                 :                :  */
                               3148                 :                : static void
 4357 rhaas@postgresql.org     3149                 :            528 : reversedirection(Tuplesortstate *state)
                               3150                 :                : {
 1538 akorotkov@postgresql     3151                 :            528 :     SortSupport sortKey = state->base.sortKeys;
                               3152                 :                :     int         nkey;
                               3153                 :                : 
                               3154         [ +  + ]:           1280 :     for (nkey = 0; nkey < state->base.nKeys; nkey++, sortKey++)
                               3155                 :                :     {
 4357 rhaas@postgresql.org     3156                 :            752 :         sortKey->ssup_reverse = !sortKey->ssup_reverse;
                               3157                 :            752 :         sortKey->ssup_nulls_first = !sortKey->ssup_nulls_first;
                               3158                 :                :     }
                               3159                 :            528 : }
                               3160                 :                : 
                               3161                 :                : 
                               3162                 :                : /*
                               3163                 :                :  * Tape interface routines
                               3164                 :                :  */
                               3165                 :                : 
                               3166                 :                : static unsigned int
 1820 heikki.linnakangas@i     3167                 :        3925034 : getlen(LogicalTape *tape, bool eofOK)
                               3168                 :                : {
                               3169                 :                :     unsigned int len;
                               3170                 :                : 
                               3171         [ -  + ]:        3925034 :     if (LogicalTapeRead(tape,
                               3172                 :                :                         &len, sizeof(len)) != sizeof(len))
 8480 tgl@sss.pgh.pa.us        3173         [ #  # ]:UBC           0 :         elog(ERROR, "unexpected end of tape");
 9857 tgl@sss.pgh.pa.us        3174   [ +  +  -  + ]:CBC     3925034 :     if (len == 0 && !eofOK)
 8480 tgl@sss.pgh.pa.us        3175         [ #  # ]:UBC           0 :         elog(ERROR, "unexpected end of data");
 9857 tgl@sss.pgh.pa.us        3176                 :CBC     3925034 :     return len;
                               3177                 :                : }
                               3178                 :                : 
                               3179                 :                : static void
 1820 heikki.linnakangas@i     3180                 :           1304 : markrunend(LogicalTape *tape)
                               3181                 :                : {
 9679 bruce@momjian.us         3182                 :           1304 :     unsigned int len = 0;
                               3183                 :                : 
 1382 peter@eisentraut.org     3184                 :           1304 :     LogicalTapeWrite(tape, &len, sizeof(len));
 9857 tgl@sss.pgh.pa.us        3185                 :           1304 : }
                               3186                 :                : 
                               3187                 :                : /*
                               3188                 :                :  * Get memory for tuple from within READTUP() routine.
                               3189                 :                :  *
                               3190                 :                :  * We use next free slot from the slab allocator, or palloc() if the tuple
                               3191                 :                :  * is too large for that.
                               3192                 :                :  */
                               3193                 :                : void *
 1538 akorotkov@postgresql     3194                 :        3668645 : tuplesort_readtup_alloc(Tuplesortstate *state, Size tuplen)
                               3195                 :                : {
                               3196                 :                :     SlabSlot   *buf;
                               3197                 :                : 
                               3198                 :                :     /*
                               3199                 :                :      * We pre-allocate enough slots in the slab arena that we should never run
                               3200                 :                :      * out.
                               3201                 :                :      */
 3661 heikki.linnakangas@i     3202         [ -  + ]:        3668645 :     Assert(state->slabFreeHead);
                               3203                 :                : 
                               3204   [ +  +  -  + ]:        3668645 :     if (tuplen > SLAB_SLOT_SIZE || !state->slabFreeHead)
 1538 akorotkov@postgresql     3205                 :              4 :         return MemoryContextAlloc(state->base.sortcontext, tuplen);
                               3206                 :                :     else
                               3207                 :                :     {
 3661 heikki.linnakangas@i     3208                 :        3668641 :         buf = state->slabFreeHead;
                               3209                 :                :         /* Reuse this slot */
                               3210                 :        3668641 :         state->slabFreeHead = buf->nextfree;
                               3211                 :                : 
                               3212                 :        3668641 :         return buf;
                               3213                 :                :     }
                               3214                 :                : }
                               3215                 :                : 
                               3216                 :                : 
                               3217                 :                : /*
                               3218                 :                :  * Parallel sort routines
                               3219                 :                :  */
                               3220                 :                : 
                               3221                 :                : /*
                               3222                 :                :  * tuplesort_estimate_shared - estimate required shared memory allocation
                               3223                 :                :  *
                               3224                 :                :  * nWorkers is an estimate of the number of workers (it's the number that
                               3225                 :                :  * will be requested).
                               3226                 :                :  */
                               3227                 :                : Size
 3174 rhaas@postgresql.org     3228                 :            131 : tuplesort_estimate_shared(int nWorkers)
                               3229                 :                : {
                               3230                 :                :     Size        tapesSize;
                               3231                 :                : 
                               3232         [ -  + ]:            131 :     Assert(nWorkers > 0);
                               3233                 :                : 
                               3234                 :                :     /* Make sure that BufFile shared state is MAXALIGN'd */
                               3235                 :            131 :     tapesSize = mul_size(sizeof(TapeShare), nWorkers);
                               3236                 :            131 :     tapesSize = MAXALIGN(add_size(tapesSize, offsetof(Sharedsort, tapes)));
                               3237                 :                : 
                               3238                 :            131 :     return tapesSize;
                               3239                 :                : }
                               3240                 :                : 
                               3241                 :                : /*
                               3242                 :                :  * tuplesort_initialize_shared - initialize shared tuplesort state
                               3243                 :                :  *
                               3244                 :                :  * Must be called from leader process before workers are launched, to
                               3245                 :                :  * establish state needed up-front for worker tuplesortstates.  nWorkers
                               3246                 :                :  * should match the argument passed to tuplesort_estimate_shared().
                               3247                 :                :  */
                               3248                 :                : void
                               3249                 :            179 : tuplesort_initialize_shared(Sharedsort *shared, int nWorkers, dsm_segment *seg)
                               3250                 :                : {
                               3251                 :                :     int         i;
                               3252                 :                : 
                               3253         [ -  + ]:            179 :     Assert(nWorkers > 0);
                               3254                 :                : 
   20 nathan@postgresql.or     3255                 :GNC         179 :     pg_atomic_init_u32(&shared->currentWorker, 0);
                               3256                 :            179 :     pg_atomic_init_u32(&shared->workersFinished, 0);
 3174 rhaas@postgresql.org     3257                 :CBC         179 :     SharedFileSetInit(&shared->fileset, seg);
                               3258                 :            179 :     shared->nTapes = nWorkers;
                               3259         [ +  + ]:            562 :     for (i = 0; i < nWorkers; i++)
                               3260                 :                :     {
                               3261                 :            383 :         shared->tapes[i].firstblocknumber = 0L;
                               3262                 :                :     }
                               3263                 :            179 : }
                               3264                 :                : 
                               3265                 :                : /*
                               3266                 :                :  * tuplesort_attach_shared - attach to shared tuplesort state
                               3267                 :                :  *
                               3268                 :                :  * Must be called by all worker processes.
                               3269                 :                :  */
                               3270                 :                : void
                               3271                 :            201 : tuplesort_attach_shared(Sharedsort *shared, dsm_segment *seg)
                               3272                 :                : {
                               3273                 :                :     /* Attach to SharedFileSet */
                               3274                 :            201 :     SharedFileSetAttach(&shared->fileset, seg);
                               3275                 :            201 : }
                               3276                 :                : 
                               3277                 :                : /*
                               3278                 :                :  * worker_get_identifier - Assign and return ordinal identifier for worker
                               3279                 :                :  *
                               3280                 :                :  * The order in which these are assigned is not well defined, and should not
                               3281                 :                :  * matter; worker numbers across parallel sort participants need only be
                               3282                 :                :  * distinct and gapless.  logtape.c requires this.
                               3283                 :                :  *
                               3284                 :                :  * Note that the identifiers assigned from here have no relation to
                               3285                 :                :  * ParallelWorkerNumber number, to avoid making any assumption about
                               3286                 :                :  * caller's requirements.  However, we do follow the ParallelWorkerNumber
                               3287                 :                :  * convention of representing a non-worker with worker number -1.  This
                               3288                 :                :  * includes the leader, as well as serial Tuplesort processes.
                               3289                 :                :  */
                               3290                 :                : static int
                               3291                 :            379 : worker_get_identifier(Tuplesortstate *state)
                               3292                 :                : {
                               3293   [ +  -  -  + ]:            379 :     Assert(WORKER(state));
                               3294                 :                : 
   20 nathan@postgresql.or     3295                 :GNC         379 :     return pg_atomic_fetch_add_u32(&state->shared->currentWorker, 1);
                               3296                 :                : }
                               3297                 :                : 
                               3298                 :                : /*
                               3299                 :                :  * worker_freeze_result_tape - freeze worker's result tape for leader
                               3300                 :                :  *
                               3301                 :                :  * This is called by workers just after the result tape has been determined,
                               3302                 :                :  * instead of calling LogicalTapeFreeze() directly.  They do so because
                               3303                 :                :  * workers require a few additional steps over similar serial
                               3304                 :                :  * TSS_SORTEDONTAPE external sort cases, which also happen here.  The extra
                               3305                 :                :  * steps are around freeing now unneeded resources, and representing to
                               3306                 :                :  * leader that worker's input run is available for its merge.
                               3307                 :                :  *
                               3308                 :                :  * There should only be one final output run for each worker, which consists
                               3309                 :                :  * of all tuples that were originally input into worker.
                               3310                 :                :  */
                               3311                 :                : static void
 3174 rhaas@postgresql.org     3312                 :CBC         379 : worker_freeze_result_tape(Tuplesortstate *state)
                               3313                 :                : {
                               3314                 :            379 :     Sharedsort *shared = state->shared;
                               3315                 :                :     TapeShare   output;
                               3316                 :                : 
                               3317   [ +  -  -  + ]:            379 :     Assert(WORKER(state));
 1820 heikki.linnakangas@i     3318         [ -  + ]:            379 :     Assert(state->result_tape != NULL);
 3174 rhaas@postgresql.org     3319         [ -  + ]:            379 :     Assert(state->memtupcount == 0);
                               3320                 :                : 
                               3321                 :                :     /*
                               3322                 :                :      * Free most remaining memory, in case caller is sensitive to our holding
                               3323                 :                :      * on to it.  memtuples may not be a tiny merge heap at this point.
                               3324                 :                :      */
                               3325                 :            379 :     pfree(state->memtuples);
                               3326                 :                :     /* Be tidy */
                               3327                 :            379 :     state->memtuples = NULL;
                               3328                 :            379 :     state->memtupsize = 0;
                               3329                 :                : 
                               3330                 :                :     /*
                               3331                 :                :      * Parallel worker requires result tape metadata, which is to be stored in
                               3332                 :                :      * shared memory for leader
                               3333                 :                :      */
 1820 heikki.linnakangas@i     3334                 :            379 :     LogicalTapeFreeze(state->result_tape, &output);
                               3335                 :                : 
                               3336                 :                :     /* Store properties of output tape, and update finished worker count */
 3174 rhaas@postgresql.org     3337                 :            379 :     shared->tapes[state->worker] = output;
   20 nathan@postgresql.or     3338                 :GNC         379 :     pg_atomic_fetch_add_u32(&shared->workersFinished, 1);
 3174 rhaas@postgresql.org     3339                 :CBC         379 : }
                               3340                 :                : 
                               3341                 :                : /*
                               3342                 :                :  * worker_nomergeruns - dump memtuples in worker, without merging
                               3343                 :                :  *
                               3344                 :                :  * This called as an alternative to mergeruns() with a worker when no
                               3345                 :                :  * merging is required.
                               3346                 :                :  */
                               3347                 :                : static void
                               3348                 :            379 : worker_nomergeruns(Tuplesortstate *state)
                               3349                 :                : {
                               3350   [ +  -  -  + ]:            379 :     Assert(WORKER(state));
 1820 heikki.linnakangas@i     3351         [ -  + ]:            379 :     Assert(state->result_tape == NULL);
                               3352         [ -  + ]:            379 :     Assert(state->nOutputRuns == 1);
                               3353                 :                : 
                               3354                 :            379 :     state->result_tape = state->destTape;
 3174 rhaas@postgresql.org     3355                 :            379 :     worker_freeze_result_tape(state);
                               3356                 :            379 : }
                               3357                 :                : 
                               3358                 :                : /*
                               3359                 :                :  * leader_takeover_tapes - create tapeset for leader from worker tapes
                               3360                 :                :  *
                               3361                 :                :  * So far, leader Tuplesortstate has performed no actual sorting.  By now, all
                               3362                 :                :  * sorting has occurred in workers, all of which must have already returned
                               3363                 :                :  * from tuplesort_performsort().
                               3364                 :                :  *
                               3365                 :                :  * When this returns, leader process is left in a state that is virtually
                               3366                 :                :  * indistinguishable from it having generated runs as a serial external sort
                               3367                 :                :  * might have.
                               3368                 :                :  */
                               3369                 :                : static void
                               3370                 :            130 : leader_takeover_tapes(Tuplesortstate *state)
                               3371                 :                : {
                               3372                 :            130 :     Sharedsort *shared = state->shared;
                               3373                 :            130 :     int         nParticipants = state->nParticipants;
                               3374                 :                :     int         workersFinished;
                               3375                 :                :     int         j;
                               3376                 :                : 
                               3377   [ +  -  -  + ]:            130 :     Assert(LEADER(state));
                               3378         [ -  + ]:            130 :     Assert(nParticipants >= 1);
                               3379                 :                : 
   20 nathan@postgresql.or     3380                 :GNC         130 :     workersFinished = pg_atomic_read_membarrier_u32(&shared->workersFinished);
                               3381                 :                : 
 3174 rhaas@postgresql.org     3382         [ -  + ]:CBC         130 :     if (nParticipants != workersFinished)
 3174 rhaas@postgresql.org     3383         [ #  # ]:UBC           0 :         elog(ERROR, "cannot take over tapes before all workers finish");
                               3384                 :                : 
                               3385                 :                :     /*
                               3386                 :                :      * Create the tapeset from worker tapes, including a leader-owned tape at
                               3387                 :                :      * the end.  Parallel workers are far more expensive than logical tapes,
                               3388                 :                :      * so the number of tapes allocated here should never be excessive.
                               3389                 :                :      */
 1820 heikki.linnakangas@i     3390                 :CBC         130 :     inittapestate(state, nParticipants);
                               3391                 :            130 :     state->tapeset = LogicalTapeSetCreate(false, &shared->fileset, -1);
                               3392                 :                : 
                               3393                 :                :     /*
                               3394                 :                :      * Set currentRun to reflect the number of runs we will merge (it's not
                               3395                 :                :      * used for anything, this is just pro forma)
                               3396                 :                :      */
 3174 rhaas@postgresql.org     3397                 :            130 :     state->currentRun = nParticipants;
                               3398                 :                : 
                               3399                 :                :     /*
                               3400                 :                :      * Initialize the state to look the same as after building the initial
                               3401                 :                :      * runs.
                               3402                 :                :      *
                               3403                 :                :      * There will always be exactly 1 run per worker, and exactly one input
                               3404                 :                :      * tape per run, because workers always output exactly 1 run, even when
                               3405                 :                :      * there were no input tuples for workers to sort.
                               3406                 :                :      */
 1820 heikki.linnakangas@i     3407                 :            130 :     state->inputTapes = NULL;
                               3408                 :            130 :     state->nInputTapes = 0;
                               3409                 :            130 :     state->nInputRuns = 0;
                               3410                 :                : 
   56 michael@paquier.xyz      3411                 :GNC         130 :     state->outputTapes = palloc0_array(LogicalTape *, nParticipants);
 1820 heikki.linnakangas@i     3412                 :CBC         130 :     state->nOutputTapes = nParticipants;
                               3413                 :            130 :     state->nOutputRuns = nParticipants;
                               3414                 :                : 
                               3415         [ +  + ]:            413 :     for (j = 0; j < nParticipants; j++)
                               3416                 :                :     {
                               3417                 :            283 :         state->outputTapes[j] = LogicalTapeImport(state->tapeset, j, &shared->tapes[j]);
                               3418                 :                :     }
                               3419                 :                : 
 3174 rhaas@postgresql.org     3420                 :            130 :     state->status = TSS_BUILDRUNS;
                               3421                 :            130 : }
                               3422                 :                : 
                               3423                 :                : /*
                               3424                 :                :  * Convenience routine to free a tuple previously loaded into sort memory
                               3425                 :                :  */
                               3426                 :                : static void
 7101 tgl@sss.pgh.pa.us        3427                 :        2139679 : free_sort_tuple(Tuplesortstate *state, SortTuple *stup)
                               3428                 :                : {
 1917 drowley@postgresql.o     3429         [ +  + ]:        2139679 :     if (stup->tuple)
                               3430                 :                :     {
                               3431                 :        2044150 :         FREEMEM(state, GetMemoryChunkSpace(stup->tuple));
                               3432                 :        2044150 :         pfree(stup->tuple);
                               3433                 :        2044150 :         stup->tuple = NULL;
                               3434                 :                :     }
 7101 tgl@sss.pgh.pa.us        3435                 :        2139679 : }
                               3436                 :                : 
                               3437                 :                : int
   63 john.naylor@postgres     3438                 :GNC     4774433 : ssup_datum_uint64_cmp(Datum x, Datum y, SortSupport ssup)
                               3439                 :                : {
 1654 john.naylor@postgres     3440         [ +  + ]:CBC     4774433 :     if (x < y)
                               3441                 :        2033283 :         return -1;
                               3442         [ +  + ]:        2741150 :     else if (x > y)
                               3443                 :         684235 :         return 1;
                               3444                 :                :     else
                               3445                 :        2056915 :         return 0;
                               3446                 :                : }
                               3447                 :                : 
                               3448                 :                : int
   63 john.naylor@postgres     3449                 :GNC     3378217 : ssup_datum_int64_cmp(Datum x, Datum y, SortSupport ssup)
                               3450                 :                : {
 1615 drowley@postgresql.o     3451                 :CBC     3378217 :     int64       xx = DatumGetInt64(x);
                               3452                 :        3378217 :     int64       yy = DatumGetInt64(y);
                               3453                 :                : 
 1654 john.naylor@postgres     3454         [ +  + ]:        3378217 :     if (xx < yy)
                               3455                 :        2802388 :         return -1;
                               3456         [ +  + ]:         575829 :     else if (xx > yy)
                               3457                 :         247375 :         return 1;
                               3458                 :                :     else
                               3459                 :         328454 :         return 0;
                               3460                 :                : }
                               3461                 :                : 
                               3462                 :                : int
   63 john.naylor@postgres     3463                 :GNC   140300646 : ssup_datum_uint32_cmp(Datum x, Datum y, SortSupport ssup)
                               3464                 :                : {
                               3465                 :      140300646 :     uint32      xx = DatumGetUInt32(x);
                               3466                 :      140300646 :     uint32      yy = DatumGetUInt32(y);
                               3467                 :                : 
                               3468         [ +  + ]:      140300646 :     if (xx < yy)
                               3469                 :       34303007 :         return -1;
                               3470         [ +  + ]:      105997639 :     else if (xx > yy)
                               3471                 :       31241737 :         return 1;
                               3472                 :                :     else
                               3473                 :       74755902 :         return 0;
                               3474                 :                : }
                               3475                 :                : 
                               3476                 :                : int
 1654 john.naylor@postgres     3477                 :CBC   186965063 : ssup_datum_int32_cmp(Datum x, Datum y, SortSupport ssup)
                               3478                 :                : {
 1615 drowley@postgresql.o     3479                 :      186965063 :     int32       xx = DatumGetInt32(x);
                               3480                 :      186965063 :     int32       yy = DatumGetInt32(y);
                               3481                 :                : 
 1654 john.naylor@postgres     3482         [ +  + ]:      186965063 :     if (xx < yy)
                               3483                 :       40657308 :         return -1;
                               3484         [ +  + ]:      146307755 :     else if (xx > yy)
                               3485                 :       33568550 :         return 1;
                               3486                 :                :     else
                               3487                 :      112739205 :         return 0;
                               3488                 :                : }
        

Generated by: LCOV version 2.0-1