logtape.c: do not preallocate for tapes when sorting
authorJeff Davis <jdavis@postgresql.org>
Sat, 12 Sep 2020 00:10:02 +0000 (17:10 -0700)
committerJeff Davis <jdavis@postgresql.org>
Sat, 12 Sep 2020 00:10:02 +0000 (17:10 -0700)
The preallocation logic is only useful for HashAgg, so disable it when
sorting.

Also, adjust an out-of-date comment.

Reviewed-by: Peter Geoghegan
Discussion: https://postgr.es/m/CAH2-Wzn_o7tE2+hRVvwSFghRb75AJ5g-nqGzDUqLYMexjOAe=g@mail.gmail.com
Backpatch-through: 13

src/backend/executor/nodeAgg.c
src/backend/utils/sort/logtape.c
src/backend/utils/sort/tuplesort.c
src/include/utils/logtape.h

index 9776263ae75ac10068624981786be8391d0ebd24..f74d4841f170dbdbc2c1e08aecfd59491876f706 100644 (file)
@@ -2882,7 +2882,7 @@ hashagg_tapeinfo_init(AggState *aggstate)
        HashTapeInfo *tapeinfo = palloc(sizeof(HashTapeInfo));
        int                     init_tapes = 16;        /* expanded dynamically */
 
-       tapeinfo->tapeset = LogicalTapeSetCreate(init_tapes, NULL, NULL, -1);
+       tapeinfo->tapeset = LogicalTapeSetCreate(init_tapes, true, NULL, NULL, -1);
        tapeinfo->ntapes = init_tapes;
        tapeinfo->nfreetapes = init_tapes;
        tapeinfo->freetapes_alloc = init_tapes;
index bbb01f6d3373972262b6083c0c955eae33946d8b..d6d1e1911ea411d64b8cdeaa278675b88d61ab9d 100644 (file)
@@ -212,6 +212,7 @@ struct LogicalTapeSet
        long       *freeBlocks;         /* resizable array holding minheap */
        long            nFreeBlocks;    /* # of currently free blocks */
        Size            freeBlocksLen;  /* current allocated length of freeBlocks[] */
+       bool            enable_prealloc;        /* preallocate write blocks? */
 
        /* The array of logical tapes. */
        int                     nTapes;                 /* # of logical tapes in set */
@@ -220,6 +221,7 @@ struct LogicalTapeSet
 
 static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer);
 static void ltsReadBlock(LogicalTapeSet *lts, long blocknum, void *buffer);
+static long ltsGetBlock(LogicalTapeSet *lts, LogicalTape *lt);
 static long ltsGetFreeBlock(LogicalTapeSet *lts);
 static long ltsGetPreallocBlock(LogicalTapeSet *lts, LogicalTape *lt);
 static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum);
@@ -242,12 +244,8 @@ ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer)
         * that's past the current end of file, fill the space between the current
         * end of file and the target block with zeros.
         *
-        * This should happen rarely, otherwise you are not writing very
-        * sequentially.  In current use, this only happens when the sort ends
-        * writing a run, and switches to another tape.  The last block of the
-        * previous tape isn't flushed to disk until the end of the sort, so you
-        * get one-block hole, where the last block of the previous tape will
-        * later go.
+        * This can happen either when tapes preallocate blocks; or for the last
+        * block of a tape which might not have been flushed.
         *
         * Note that BufFile concatenation can leave "holes" in BufFile between
         * worker-owned block ranges.  These are tracked for reporting purposes
@@ -373,8 +371,20 @@ parent_offset(unsigned long i)
 }
 
 /*
- * Select the lowest currently unused block by taking the first element from
- * the freelist min heap.
+ * Get the next block for writing.
+ */
+static long
+ltsGetBlock(LogicalTapeSet *lts, LogicalTape *lt)
+{
+       if (lts->enable_prealloc)
+               return ltsGetPreallocBlock(lts, lt);
+       else
+               return ltsGetFreeBlock(lts);
+}
+
+/*
+ * Select the lowest currently unused block from the tape set's global free
+ * list min heap.
  */
 static long
 ltsGetFreeBlock(LogicalTapeSet *lts)
@@ -430,7 +440,8 @@ ltsGetFreeBlock(LogicalTapeSet *lts)
 
 /*
  * Return the lowest free block number from the tape's preallocation list.
- * Refill the preallocation list if necessary.
+ * Refill the preallocation list with blocks from the tape set's free list if
+ * necessary.
  */
 static long
 ltsGetPreallocBlock(LogicalTapeSet *lts, LogicalTape *lt)
@@ -671,8 +682,8 @@ ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt)
  * infrastructure that may be lifted in the future.
  */
 LogicalTapeSet *
-LogicalTapeSetCreate(int ntapes, TapeShare *shared, SharedFileSet *fileset,
-                                        int worker)
+LogicalTapeSetCreate(int ntapes, bool preallocate, TapeShare *shared,
+                                        SharedFileSet *fileset, int worker)
 {
        LogicalTapeSet *lts;
        int                     i;
@@ -689,6 +700,7 @@ LogicalTapeSetCreate(int ntapes, TapeShare *shared, SharedFileSet *fileset,
        lts->freeBlocksLen = 32;        /* reasonable initial guess */
        lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long));
        lts->nFreeBlocks = 0;
+       lts->enable_prealloc = preallocate;
        lts->nTapes = ntapes;
        lts->tapes = (LogicalTape *) palloc(ntapes * sizeof(LogicalTape));
 
@@ -782,7 +794,7 @@ LogicalTapeWrite(LogicalTapeSet *lts, int tapenum,
                Assert(lt->firstBlockNumber == -1);
                Assert(lt->pos == 0);
 
-               lt->curBlockNumber = ltsGetPreallocBlock(lts, lt);
+               lt->curBlockNumber = ltsGetBlock(lts, lt);
                lt->firstBlockNumber = lt->curBlockNumber;
 
                TapeBlockGetTrailer(lt->buffer)->prev = -1L;
@@ -806,7 +818,7 @@ LogicalTapeWrite(LogicalTapeSet *lts, int tapenum,
                         * First allocate the next block, so that we can store it in the
                         * 'next' pointer of this block.
                         */
-                       nextBlockNumber = ltsGetPreallocBlock(lts, lt);
+                       nextBlockNumber = ltsGetBlock(lts, lt);
 
                        /* set the next-pointer and dump the current block. */
                        TapeBlockGetTrailer(lt->buffer)->next = nextBlockNumber;
index 3c49476483b1f02eb92b6994cf247248f7ff2f51..cbda911f465288084a3ec143b33e186be3c528a2 100644 (file)
@@ -2591,7 +2591,7 @@ inittapes(Tuplesortstate *state, bool mergeruns)
        /* Create the tape set and allocate the per-tape data arrays */
        inittapestate(state, maxTapes);
        state->tapeset =
-               LogicalTapeSetCreate(maxTapes, NULL,
+               LogicalTapeSetCreate(maxTapes, false, NULL,
                                                         state->shared ? &state->shared->fileset : NULL,
                                                         state->worker);
 
@@ -4657,8 +4657,9 @@ leader_takeover_tapes(Tuplesortstate *state)
         * randomAccess is disallowed for parallel sorts.
         */
        inittapestate(state, nParticipants + 1);
-       state->tapeset = LogicalTapeSetCreate(nParticipants + 1, shared->tapes,
-                                                                                 &shared->fileset, state->worker);
+       state->tapeset = LogicalTapeSetCreate(nParticipants + 1, false,
+                                                                                 shared->tapes, &shared->fileset,
+                                                                                 state->worker);
 
        /* mergeruns() relies on currentRun for # of runs (in one-pass cases) */
        state->currentRun = nParticipants;
index 39a99174afe34afd02c8fa95726b73315d69174b..da5159e4c6c762b6eeb105f90dbb98054e6085b9 100644 (file)
@@ -54,7 +54,8 @@ typedef struct TapeShare
  * prototypes for functions in logtape.c
  */
 
-extern LogicalTapeSet *LogicalTapeSetCreate(int ntapes, TapeShare *shared,
+extern LogicalTapeSet *LogicalTapeSetCreate(int ntapes, bool preallocate,
+                                                                                       TapeShare *shared,
                                                                                        SharedFileSet *fileset, int worker);
 extern void LogicalTapeSetClose(LogicalTapeSet *lts);
 extern void LogicalTapeSetForgetFreeSpace(LogicalTapeSet *lts);