diff --git a/src/backend/utils/sort/logtape.c b/src/backend/utils/sort/logtape.c index 33495f8b4b..fd7624c231 100644 --- a/src/backend/utils/sort/logtape.c +++ b/src/backend/utils/sort/logtape.c @@ -201,6 +201,7 @@ static long ltsGetFreeBlock(LogicalTapeSet *lts); static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum); static void ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared, SharedFileSet *fileset); +static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt); /* @@ -535,6 +536,27 @@ ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared, lts->nHoleBlocks = lts->nBlocksAllocated - nphysicalblocks; } +/* + * Lazily allocate and initialize the read buffer. This avoids waste when many + * tapes are open at once, but not all are active between rewinding and + * reading. + */ +static void +ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt) +{ + if (lt->firstBlockNumber != -1L) + { + Assert(lt->buffer_size > 0); + lt->buffer = palloc(lt->buffer_size); + } + + /* Read the first block, or reset if tape is empty */ + lt->nextBlockNumber = lt->firstBlockNumber; + lt->pos = 0; + lt->nbytes = 0; + ltsReadFillBuffer(lts, lt); +} + /* * Create a set of logical tapes in a temporary underlying file. * @@ -821,15 +843,9 @@ LogicalTapeRewindForRead(LogicalTapeSet *lts, int tapenum, size_t buffer_size) lt->buffer_size = 0; if (lt->firstBlockNumber != -1L) { - lt->buffer = palloc(buffer_size); + /* the buffer is lazily allocated, but set the size here */ lt->buffer_size = buffer_size; } - - /* Read the first block, or reset if tape is empty */ - lt->nextBlockNumber = lt->firstBlockNumber; - lt->pos = 0; - lt->nbytes = 0; - ltsReadFillBuffer(lts, lt); } /* @@ -878,6 +894,9 @@ LogicalTapeRead(LogicalTapeSet *lts, int tapenum, lt = <s->tapes[tapenum]; Assert(!lt->writing); + if (lt->buffer == NULL) + ltsInitReadBuffer(lts, lt); + while (size > 0) { if (lt->pos >= lt->nbytes) @@ -1015,6 +1034,9 @@ LogicalTapeBackspace(LogicalTapeSet *lts, int tapenum, size_t size) Assert(lt->frozen); Assert(lt->buffer_size == BLCKSZ); + if (lt->buffer == NULL) + ltsInitReadBuffer(lts, lt); + /* * Easy case for seek within current block. */ @@ -1087,6 +1109,9 @@ LogicalTapeSeek(LogicalTapeSet *lts, int tapenum, Assert(offset >= 0 && offset <= TapeBlockPayloadSize); Assert(lt->buffer_size == BLCKSZ); + if (lt->buffer == NULL) + ltsInitReadBuffer(lts, lt); + if (blocknum != lt->curBlockNumber) { ltsReadBlock(lts, blocknum, (void *) lt->buffer); @@ -1114,6 +1139,10 @@ LogicalTapeTell(LogicalTapeSet *lts, int tapenum, Assert(tapenum >= 0 && tapenum < lts->nTapes); lt = <s->tapes[tapenum]; + + if (lt->buffer == NULL) + ltsInitReadBuffer(lts, lt); + Assert(lt->offsetBlockNumber == 0L); /* With a larger buffer, 'pos' wouldn't be the same as offset within page */