* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/sort/logtape.c,v 1.17 2005/10/18 22:59:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/sort/logtape.c,v 1.18 2006/02/19 05:58:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* we do need the relative block number so we can detect end-of-tape while
* reading.
*/
+ char *buffer; /* physical buffer (separately palloc'd) */
long curBlockNumber; /* this block's logical blk# within tape */
int pos; /* next read/write position in buffer */
int nbytes; /* total # of valid bytes in buffer */
- char buffer[BLCKSZ];
} LogicalTape;
/*
* is of length nTapes.
*/
int nTapes; /* # of logical tapes in set */
- LogicalTape *tapes[1]; /* must be last in struct! */
+ LogicalTape tapes[1]; /* must be last in struct! */
};
static void ltsWriteBlock(LogicalTapeSet *lts, long blocknum, void *buffer);
IndirectBlock *indirect,
bool freezing)
{
+ /* Handle case of never-written-to tape */
+ if (indirect == NULL)
+ return -1L;
+
/* Insert sentinel if block is not full */
if (indirect->nextSlot < BLOCKS_PER_INDIR_BLOCK)
indirect->ptrs[indirect->nextSlot] = -1L;
ltsRewindFrozenIndirectBlock(LogicalTapeSet *lts,
IndirectBlock *indirect)
{
+ /* Handle case of never-written-to tape */
+ if (indirect == NULL)
+ return -1L;
+
/*
* If block is not topmost, recurse to obtain address of first block in
* this hierarchy level. Read that one in.
IndirectBlock *indirect,
bool frozen)
{
+ /* Handle case of never-written-to tape */
+ if (indirect == NULL)
+ return -1L;
+
if (indirect->nextSlot >= BLOCKS_PER_INDIR_BLOCK ||
indirect->ptrs[indirect->nextSlot] == -1L)
{
ltsRecallPrevBlockNum(LogicalTapeSet *lts,
IndirectBlock *indirect)
{
+ /* Handle case of never-written-to tape */
+ if (indirect == NULL)
+ return -1L;
+
if (indirect->nextSlot <= 1)
{
long indirblock;
int i;
/*
- * Create top-level struct. First LogicalTape pointer is already counted
- * in sizeof(LogicalTapeSet).
+ * Create top-level struct including per-tape LogicalTape structs.
+ * First LogicalTape struct is already counted in sizeof(LogicalTapeSet).
*/
Assert(ntapes > 0);
lts = (LogicalTapeSet *) palloc(sizeof(LogicalTapeSet) +
- (ntapes - 1) *sizeof(LogicalTape *));
+ (ntapes - 1) * sizeof(LogicalTape));
lts->pfile = BufFileCreateTemp(false);
lts->nFileBlocks = 0L;
lts->freeBlocksLen = 32; /* reasonable initial guess */
lts->nTapes = ntapes;
/*
- * Create per-tape structs, including first-level indirect blocks.
+ * Initialize per-tape structs. Note we allocate the I/O buffer and
+ * first-level indirect 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++)
{
- lt = (LogicalTape *) palloc(sizeof(LogicalTape));
- lts->tapes[i] = lt;
- lt->indirect = (IndirectBlock *) palloc(sizeof(IndirectBlock));
- lt->indirect->nextSlot = 0;
- lt->indirect->nextup = NULL;
+ lt = <s->tapes[i];
+ lt->indirect = NULL;
lt->writing = true;
lt->frozen = false;
lt->dirty = false;
lt->numFullBlocks = 0L;
lt->lastBlockBytes = 0;
+ lt->buffer = NULL;
lt->curBlockNumber = 0L;
lt->pos = 0;
lt->nbytes = 0;
BufFileClose(lts->pfile);
for (i = 0; i < lts->nTapes; i++)
{
- lt = lts->tapes[i];
+ lt = <s->tapes[i];
for (ib = lt->indirect; ib != NULL; ib = nextib)
{
nextib = ib->nextup;
pfree(ib);
}
- pfree(lt);
+ if (lt->buffer)
+ pfree(lt->buffer);
}
pfree(lts->freeBlocks);
pfree(lts);
size_t nthistime;
Assert(tapenum >= 0 && tapenum < lts->nTapes);
- lt = lts->tapes[tapenum];
+ lt = <s->tapes[tapenum];
Assert(lt->writing);
+ /* Allocate data buffer and first indirect block on first write */
+ if (lt->buffer == NULL)
+ lt->buffer = (char *) palloc(BLCKSZ);
+ if (lt->indirect == NULL)
+ {
+ lt->indirect = (IndirectBlock *) palloc(sizeof(IndirectBlock));
+ lt->indirect->nextSlot = 0;
+ lt->indirect->nextup = NULL;
+ }
+
while (size > 0)
{
if (lt->pos >= BLCKSZ)
long datablocknum;
Assert(tapenum >= 0 && tapenum < lts->nTapes);
- lt = lts->tapes[tapenum];
+ lt = <s->tapes[tapenum];
if (!forWrite)
{
Assert(!lt->writing && !lt->frozen);
/* Must truncate the indirect-block hierarchy down to one level. */
- for (ib = lt->indirect->nextup; ib != NULL; ib = nextib)
+ if (lt->indirect)
{
- nextib = ib->nextup;
- pfree(ib);
+ for (ib = lt->indirect->nextup; ib != NULL; ib = nextib)
+ {
+ nextib = ib->nextup;
+ pfree(ib);
+ }
+ lt->indirect->nextSlot = 0;
+ lt->indirect->nextup = NULL;
}
- lt->indirect->nextSlot = 0;
- lt->indirect->nextup = NULL;
lt->writing = true;
lt->dirty = false;
lt->numFullBlocks = 0L;
size_t nthistime;
Assert(tapenum >= 0 && tapenum < lts->nTapes);
- lt = lts->tapes[tapenum];
+ lt = <s->tapes[tapenum];
Assert(!lt->writing);
while (size > 0)
long datablocknum;
Assert(tapenum >= 0 && tapenum < lts->nTapes);
- lt = lts->tapes[tapenum];
+ lt = <s->tapes[tapenum];
Assert(lt->writing);
/*
int newpos;
Assert(tapenum >= 0 && tapenum < lts->nTapes);
- lt = lts->tapes[tapenum];
+ lt = <s->tapes[tapenum];
Assert(lt->frozen);
/*
LogicalTape *lt;
Assert(tapenum >= 0 && tapenum < lts->nTapes);
- lt = lts->tapes[tapenum];
+ lt = <s->tapes[tapenum];
Assert(lt->frozen);
Assert(offset >= 0 && offset <= BLCKSZ);
LogicalTape *lt;
Assert(tapenum >= 0 && tapenum < lts->nTapes);
- lt = lts->tapes[tapenum];
+ lt = <s->tapes[tapenum];
*blocknum = lt->curBlockNumber;
*offset = lt->pos;
}