Commit 24d85952 authored by Jeff Davis's avatar Jeff Davis

Introduce LogicalTapeSetExtend().

Increases the number of tapes in a logical tape set. This will be
important for disk-based hash aggregation, because the maximum number
of tapes is not known ahead of time.

While discussing this change, it was observed to regress the
performance of Sort for at least one test case. The performance
regression was because some versions of GCC switch to an inlined
version of memcpy() in LogicalTapeWrite() after this change. No
performance regression for clang was observed.

Because the regression is due to an arbitrary decision by the
compiler, I decided it shouldn't hold up this change. If it needs to
be fixed, we can find a workaround.

Author: Adam Lee, Jeff Davis
Discussion: https://postgr.es/m/e54bfec11c59689890f277722aaaabd05f78e22c.camel%40j-davis.com
parent 17d3fcdc
...@@ -192,7 +192,7 @@ struct LogicalTapeSet ...@@ -192,7 +192,7 @@ struct LogicalTapeSet
/* The array of logical tapes. */ /* The array of logical tapes. */
int nTapes; /* # of logical tapes in set */ int nTapes; /* # of logical tapes in set */
LogicalTape tapes[FLEXIBLE_ARRAY_MEMBER]; /* has nTapes nentries */ LogicalTape *tapes; /* has nTapes nentries */
}; };
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer); static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer);
...@@ -201,6 +201,7 @@ static long ltsGetFreeBlock(LogicalTapeSet *lts); ...@@ -201,6 +201,7 @@ static long ltsGetFreeBlock(LogicalTapeSet *lts);
static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum); static void ltsReleaseBlock(LogicalTapeSet *lts, long blocknum);
static void ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared, static void ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared,
SharedFileSet *fileset); SharedFileSet *fileset);
static void ltsInitTape(LogicalTape *lt);
static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt); static void ltsInitReadBuffer(LogicalTapeSet *lts, LogicalTape *lt);
...@@ -536,6 +537,27 @@ ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared, ...@@ -536,6 +537,27 @@ ltsConcatWorkerTapes(LogicalTapeSet *lts, TapeShare *shared,
lts->nHoleBlocks = lts->nBlocksAllocated - nphysicalblocks; lts->nHoleBlocks = lts->nBlocksAllocated - nphysicalblocks;
} }
/*
* Initialize per-tape struct. Note we allocate the I/O buffer lazily.
*/
static void
ltsInitTape(LogicalTape *lt)
{
lt->writing = true;
lt->frozen = false;
lt->dirty = false;
lt->firstBlockNumber = -1L;
lt->curBlockNumber = -1L;
lt->nextBlockNumber = -1L;
lt->offsetBlockNumber = 0L;
lt->buffer = NULL;
lt->buffer_size = 0;
/* palloc() larger than MaxAllocSize would fail */
lt->max_size = MaxAllocSize;
lt->pos = 0;
lt->nbytes = 0;
}
/* /*
* Lazily allocate and initialize the read buffer. This avoids waste when many * 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 * tapes are open at once, but not all are active between rewinding and
...@@ -579,15 +601,13 @@ LogicalTapeSetCreate(int ntapes, TapeShare *shared, SharedFileSet *fileset, ...@@ -579,15 +601,13 @@ LogicalTapeSetCreate(int ntapes, TapeShare *shared, SharedFileSet *fileset,
int worker) int worker)
{ {
LogicalTapeSet *lts; LogicalTapeSet *lts;
LogicalTape *lt;
int i; int i;
/* /*
* Create top-level struct including per-tape LogicalTape structs. * Create top-level struct including per-tape LogicalTape structs.
*/ */
Assert(ntapes > 0); Assert(ntapes > 0);
lts = (LogicalTapeSet *) palloc(offsetof(LogicalTapeSet, tapes) + lts = (LogicalTapeSet *) palloc(sizeof(LogicalTapeSet));
ntapes * sizeof(LogicalTape));
lts->nBlocksAllocated = 0L; lts->nBlocksAllocated = 0L;
lts->nBlocksWritten = 0L; lts->nBlocksWritten = 0L;
lts->nHoleBlocks = 0L; lts->nHoleBlocks = 0L;
...@@ -596,30 +616,10 @@ LogicalTapeSetCreate(int ntapes, TapeShare *shared, SharedFileSet *fileset, ...@@ -596,30 +616,10 @@ LogicalTapeSetCreate(int ntapes, TapeShare *shared, SharedFileSet *fileset,
lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long)); lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long));
lts->nFreeBlocks = 0; lts->nFreeBlocks = 0;
lts->nTapes = ntapes; lts->nTapes = ntapes;
lts->tapes = (LogicalTape *) palloc(ntapes * sizeof(LogicalTape));
/*
* Initialize per-tape structs. Note we allocate the I/O buffer and the
* first block for a tape only when it is first actually written to. This
* avoids wasting memory space when tuplesort.c overestimates the number
* of tapes needed.
*/
for (i = 0; i < ntapes; i++) for (i = 0; i < ntapes; i++)
{ ltsInitTape(&lts->tapes[i]);
lt = &lts->tapes[i];
lt->writing = true;
lt->frozen = false;
lt->dirty = false;
lt->firstBlockNumber = -1L;
lt->curBlockNumber = -1L;
lt->nextBlockNumber = -1L;
lt->offsetBlockNumber = 0L;
lt->buffer = NULL;
lt->buffer_size = 0;
/* palloc() larger than MaxAllocSize would fail */
lt->max_size = MaxAllocSize;
lt->pos = 0;
lt->nbytes = 0;
}
/* /*
* Create temp BufFile storage as required. * Create temp BufFile storage as required.
...@@ -1004,6 +1004,25 @@ LogicalTapeFreeze(LogicalTapeSet *lts, int tapenum, TapeShare *share) ...@@ -1004,6 +1004,25 @@ LogicalTapeFreeze(LogicalTapeSet *lts, int tapenum, TapeShare *share)
} }
} }
/*
* Add additional tapes to this tape set. Not intended to be used when any
* tapes are frozen.
*/
void
LogicalTapeSetExtend(LogicalTapeSet *lts, int nAdditional)
{
int i;
int nTapesOrig = lts->nTapes;
lts->nTapes += nAdditional;
lts->tapes = (LogicalTape *) repalloc(
lts->tapes, lts->nTapes * sizeof(LogicalTape));
for (i = nTapesOrig; i < lts->nTapes; i++)
ltsInitTape(&lts->tapes[i]);
}
/* /*
* Backspace the tape a given number of bytes. (We also support a more * Backspace the tape a given number of bytes. (We also support a more
* general seek interface, see below.) * general seek interface, see below.)
......
...@@ -67,6 +67,7 @@ extern void LogicalTapeRewindForRead(LogicalTapeSet *lts, int tapenum, ...@@ -67,6 +67,7 @@ extern void LogicalTapeRewindForRead(LogicalTapeSet *lts, int tapenum,
extern void LogicalTapeRewindForWrite(LogicalTapeSet *lts, int tapenum); extern void LogicalTapeRewindForWrite(LogicalTapeSet *lts, int tapenum);
extern void LogicalTapeFreeze(LogicalTapeSet *lts, int tapenum, extern void LogicalTapeFreeze(LogicalTapeSet *lts, int tapenum,
TapeShare *share); TapeShare *share);
extern void LogicalTapeSetExtend(LogicalTapeSet *lts, int nAdditional);
extern size_t LogicalTapeBackspace(LogicalTapeSet *lts, int tapenum, extern size_t LogicalTapeBackspace(LogicalTapeSet *lts, int tapenum,
size_t size); size_t size);
extern void LogicalTapeSeek(LogicalTapeSet *lts, int tapenum, extern void LogicalTapeSeek(LogicalTapeSet *lts, int tapenum,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment