Header And Logo

PostgreSQL
| The world's most advanced open source database.

Typedefs | Functions

logtape.h File Reference

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef struct LogicalTapeSet LogicalTapeSet

Functions

LogicalTapeSetLogicalTapeSetCreate (int ntapes)
void LogicalTapeSetClose (LogicalTapeSet *lts)
void LogicalTapeSetForgetFreeSpace (LogicalTapeSet *lts)
size_t LogicalTapeRead (LogicalTapeSet *lts, int tapenum, void *ptr, size_t size)
void LogicalTapeWrite (LogicalTapeSet *lts, int tapenum, void *ptr, size_t size)
void LogicalTapeRewind (LogicalTapeSet *lts, int tapenum, bool forWrite)
void LogicalTapeFreeze (LogicalTapeSet *lts, int tapenum)
bool LogicalTapeBackspace (LogicalTapeSet *lts, int tapenum, size_t size)
bool LogicalTapeSeek (LogicalTapeSet *lts, int tapenum, long blocknum, int offset)
void LogicalTapeTell (LogicalTapeSet *lts, int tapenum, long *blocknum, int *offset)
long LogicalTapeSetBlocks (LogicalTapeSet *lts)

Typedef Documentation

Definition at line 21 of file logtape.h.


Function Documentation

bool LogicalTapeBackspace ( LogicalTapeSet lts,
int  tapenum,
size_t  size 
)

Definition at line 876 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::curBlockNumber, elog, ERROR, LogicalTape::frozen, LogicalTape::indirect, ltsReadBlock(), ltsRecallPrevBlockNum(), LogicalTape::nbytes, LogicalTape::pos, and LogicalTapeSet::tapes.

Referenced by tuplesort_gettuple_common().

{
    LogicalTape *lt;
    long        nblocks;
    int         newpos;

    Assert(tapenum >= 0 && tapenum < lts->nTapes);
    lt = &lts->tapes[tapenum];
    Assert(lt->frozen);

    /*
     * Easy case for seek within current block.
     */
    if (size <= (size_t) lt->pos)
    {
        lt->pos -= (int) size;
        return true;
    }

    /*
     * Not-so-easy case.  Figure out whether it's possible at all.
     */
    size -= (size_t) lt->pos;   /* part within this block */
    nblocks = size / BLCKSZ;
    size = size % BLCKSZ;
    if (size)
    {
        nblocks++;
        newpos = (int) (BLCKSZ - size);
    }
    else
        newpos = 0;
    if (nblocks > lt->curBlockNumber)
        return false;           /* a seek too far... */

    /*
     * OK, we need to back up nblocks blocks.  This implementation would be
     * pretty inefficient for long seeks, but we really aren't expecting that
     * (a seek over one tuple is typical).
     */
    while (nblocks-- > 0)
    {
        long        datablocknum = ltsRecallPrevBlockNum(lts, lt->indirect);

        if (datablocknum == -1L)
            elog(ERROR, "unexpected end of tape");
        lt->curBlockNumber--;
        if (nblocks == 0)
        {
            ltsReadBlock(lts, datablocknum, (void *) lt->buffer);
            lt->nbytes = BLCKSZ;
        }
    }
    lt->pos = newpos;
    return true;
}

void LogicalTapeFreeze ( LogicalTapeSet lts,
int  tapenum 
)

Definition at line 833 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::curBlockNumber, LogicalTape::dirty, LogicalTape::frozen, LogicalTape::indirect, LogicalTape::lastBlockBytes, ltsDumpBuffer(), ltsReadBlock(), ltsRewindIndirectBlock(), LogicalTape::nbytes, LogicalTape::numFullBlocks, LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by mergeruns().

{
    LogicalTape *lt;
    long        datablocknum;

    Assert(tapenum >= 0 && tapenum < lts->nTapes);
    lt = &lts->tapes[tapenum];
    Assert(lt->writing);

    /*
     * Completion of a write phase.  Flush last partial data block, flush any
     * partial indirect blocks, rewind for nondestructive read.
     */
    if (lt->dirty)
        ltsDumpBuffer(lts, lt);
    lt->lastBlockBytes = lt->nbytes;
    lt->writing = false;
    lt->frozen = true;
    datablocknum = ltsRewindIndirectBlock(lts, lt->indirect, true);
    /* Read the first block, or reset if tape is empty */
    lt->curBlockNumber = 0L;
    lt->pos = 0;
    lt->nbytes = 0;
    if (datablocknum != -1L)
    {
        ltsReadBlock(lts, datablocknum, (void *) lt->buffer);
        lt->nbytes = (lt->curBlockNumber < lt->numFullBlocks) ?
            BLCKSZ : lt->lastBlockBytes;
    }
}

size_t LogicalTapeRead ( LogicalTapeSet lts,
int  tapenum,
void *  ptr,
size_t  size 
)

Definition at line 773 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::curBlockNumber, LogicalTape::frozen, LogicalTape::indirect, LogicalTape::lastBlockBytes, ltsReadBlock(), ltsRecallNextBlockNum(), ltsReleaseBlock(), LogicalTape::nbytes, LogicalTape::numFullBlocks, LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by getlen().

{
    LogicalTape *lt;
    size_t      nread = 0;
    size_t      nthistime;

    Assert(tapenum >= 0 && tapenum < lts->nTapes);
    lt = &lts->tapes[tapenum];
    Assert(!lt->writing);

    while (size > 0)
    {
        if (lt->pos >= lt->nbytes)
        {
            /* Try to load more data into buffer. */
            long        datablocknum = ltsRecallNextBlockNum(lts, lt->indirect,
                                                             lt->frozen);

            if (datablocknum == -1L)
                break;          /* EOF */
            lt->curBlockNumber++;
            lt->pos = 0;
            ltsReadBlock(lts, datablocknum, (void *) lt->buffer);
            if (!lt->frozen)
                ltsReleaseBlock(lts, datablocknum);
            lt->nbytes = (lt->curBlockNumber < lt->numFullBlocks) ?
                BLCKSZ : lt->lastBlockBytes;
            if (lt->nbytes <= 0)
                break;          /* EOF (possible here?) */
        }

        nthistime = lt->nbytes - lt->pos;
        if (nthistime > size)
            nthistime = size;
        Assert(nthistime > 0);

        memcpy(ptr, lt->buffer + lt->pos, nthistime);

        lt->pos += nthistime;
        ptr = (void *) ((char *) ptr + nthistime);
        size -= nthistime;
        nread += nthistime;
    }

    return nread;
}

void LogicalTapeRewind ( LogicalTapeSet lts,
int  tapenum,
bool  forWrite 
)

Definition at line 687 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::curBlockNumber, LogicalTape::dirty, LogicalTape::frozen, LogicalTape::indirect, LogicalTape::lastBlockBytes, ltsDumpBuffer(), ltsReadBlock(), ltsReleaseBlock(), ltsRewindFrozenIndirectBlock(), ltsRewindIndirectBlock(), LogicalTape::nbytes, IndirectBlock::nextSlot, IndirectBlock::nextup, NULL, LogicalTape::numFullBlocks, pfree(), LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by mergeruns(), and tuplesort_rescan().

{
    LogicalTape *lt;
    long        datablocknum;

    Assert(tapenum >= 0 && tapenum < lts->nTapes);
    lt = &lts->tapes[tapenum];

    if (!forWrite)
    {
        if (lt->writing)
        {
            /*
             * Completion of a write phase.  Flush last partial data block,
             * flush any partial indirect blocks, rewind for normal
             * (destructive) read.
             */
            if (lt->dirty)
                ltsDumpBuffer(lts, lt);
            lt->lastBlockBytes = lt->nbytes;
            lt->writing = false;
            datablocknum = ltsRewindIndirectBlock(lts, lt->indirect, false);
        }
        else
        {
            /*
             * This is only OK if tape is frozen; we rewind for (another) read
             * pass.
             */
            Assert(lt->frozen);
            datablocknum = ltsRewindFrozenIndirectBlock(lts, lt->indirect);
        }
        /* Read the first block, or reset if tape is empty */
        lt->curBlockNumber = 0L;
        lt->pos = 0;
        lt->nbytes = 0;
        if (datablocknum != -1L)
        {
            ltsReadBlock(lts, datablocknum, (void *) lt->buffer);
            if (!lt->frozen)
                ltsReleaseBlock(lts, datablocknum);
            lt->nbytes = (lt->curBlockNumber < lt->numFullBlocks) ?
                BLCKSZ : lt->lastBlockBytes;
        }
    }
    else
    {
        /*
         * Completion of a read phase.  Rewind and prepare for write.
         *
         * NOTE: we assume the caller has read the tape to the end; otherwise
         * untouched data and indirect blocks will not have been freed. We
         * could add more code to free any unread blocks, but in current usage
         * of this module it'd be useless code.
         */
        IndirectBlock *ib,
                   *nextib;

        Assert(!lt->writing && !lt->frozen);
        /* Must truncate the indirect-block hierarchy down to one level. */
        if (lt->indirect)
        {
            for (ib = lt->indirect->nextup; ib != NULL; ib = nextib)
            {
                nextib = ib->nextup;
                pfree(ib);
            }
            lt->indirect->nextSlot = 0;
            lt->indirect->nextup = NULL;
        }
        lt->writing = true;
        lt->dirty = false;
        lt->numFullBlocks = 0L;
        lt->lastBlockBytes = 0;
        lt->curBlockNumber = 0L;
        lt->pos = 0;
        lt->nbytes = 0;
    }
}

bool LogicalTapeSeek ( LogicalTapeSet lts,
int  tapenum,
long  blocknum,
int  offset 
)

Definition at line 942 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::curBlockNumber, elog, ERROR, LogicalTape::frozen, LogicalTape::indirect, LogicalTape::lastBlockBytes, ltsReadBlock(), ltsRecallNextBlockNum(), ltsRecallPrevBlockNum(), LogicalTape::nbytes, LogicalTape::numFullBlocks, LogicalTape::pos, and LogicalTapeSet::tapes.

Referenced by tuplesort_restorepos().

{
    LogicalTape *lt;

    Assert(tapenum >= 0 && tapenum < lts->nTapes);
    lt = &lts->tapes[tapenum];
    Assert(lt->frozen);
    Assert(offset >= 0 && offset <= BLCKSZ);

    /*
     * Easy case for seek within current block.
     */
    if (blocknum == lt->curBlockNumber && offset <= lt->nbytes)
    {
        lt->pos = offset;
        return true;
    }

    /*
     * Not-so-easy case.  Figure out whether it's possible at all.
     */
    if (blocknum < 0 || blocknum > lt->numFullBlocks ||
        (blocknum == lt->numFullBlocks && offset > lt->lastBlockBytes))
        return false;

    /*
     * OK, advance or back up to the target block.  This implementation would
     * be pretty inefficient for long seeks, but we really aren't expecting
     * that (a seek over one tuple is typical).
     */
    while (lt->curBlockNumber > blocknum)
    {
        long        datablocknum = ltsRecallPrevBlockNum(lts, lt->indirect);

        if (datablocknum == -1L)
            elog(ERROR, "unexpected end of tape");
        if (--lt->curBlockNumber == blocknum)
            ltsReadBlock(lts, datablocknum, (void *) lt->buffer);
    }
    while (lt->curBlockNumber < blocknum)
    {
        long        datablocknum = ltsRecallNextBlockNum(lts, lt->indirect,
                                                         lt->frozen);

        if (datablocknum == -1L)
            elog(ERROR, "unexpected end of tape");
        if (++lt->curBlockNumber == blocknum)
            ltsReadBlock(lts, datablocknum, (void *) lt->buffer);
    }
    lt->nbytes = (lt->curBlockNumber < lt->numFullBlocks) ?
        BLCKSZ : lt->lastBlockBytes;
    lt->pos = offset;
    return true;
}

long LogicalTapeSetBlocks ( LogicalTapeSet lts  ) 

Definition at line 1020 of file logtape.c.

References LogicalTapeSet::nFileBlocks.

Referenced by tuplesort_end(), and tuplesort_get_stats().

{
    return lts->nFileBlocks;
}

void LogicalTapeSetClose ( LogicalTapeSet lts  ) 

Definition at line 567 of file logtape.c.

References LogicalTape::buffer, BufFileClose(), LogicalTapeSet::freeBlocks, i, LogicalTape::indirect, IndirectBlock::nextup, LogicalTapeSet::nTapes, NULL, LogicalTapeSet::pfile, pfree(), and LogicalTapeSet::tapes.

Referenced by tuplesort_end().

{
    LogicalTape *lt;
    IndirectBlock *ib,
               *nextib;
    int         i;

    BufFileClose(lts->pfile);
    for (i = 0; i < lts->nTapes; i++)
    {
        lt = &lts->tapes[i];
        for (ib = lt->indirect; ib != NULL; ib = nextib)
        {
            nextib = ib->nextup;
            pfree(ib);
        }
        if (lt->buffer)
            pfree(lt->buffer);
    }
    pfree(lts->freeBlocks);
    pfree(lts);
}

LogicalTapeSet* LogicalTapeSetCreate ( int  ntapes  ) 

Definition at line 518 of file logtape.c.

References Assert, LogicalTapeSet::blocksSorted, LogicalTape::buffer, BufFileCreateTemp(), LogicalTape::curBlockNumber, LogicalTape::dirty, LogicalTapeSet::forgetFreeSpace, LogicalTapeSet::freeBlocks, LogicalTapeSet::freeBlocksLen, LogicalTape::frozen, i, LogicalTape::indirect, LogicalTape::lastBlockBytes, LogicalTape::nbytes, LogicalTapeSet::nFileBlocks, LogicalTapeSet::nFreeBlocks, LogicalTapeSet::nTapes, LogicalTape::numFullBlocks, palloc(), LogicalTapeSet::pfile, LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by inittapes().

{
    LogicalTapeSet *lts;
    LogicalTape *lt;
    int         i;

    /*
     * 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));
    lts->pfile = BufFileCreateTemp(false);
    lts->nFileBlocks = 0L;
    lts->forgetFreeSpace = false;
    lts->blocksSorted = true;   /* a zero-length array is sorted ... */
    lts->freeBlocksLen = 32;    /* reasonable initial guess */
    lts->freeBlocks = (long *) palloc(lts->freeBlocksLen * sizeof(long));
    lts->nFreeBlocks = 0;
    lts->nTapes = ntapes;

    /*
     * 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 = &lts->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;
    }
    return lts;
}

void LogicalTapeSetForgetFreeSpace ( LogicalTapeSet lts  ) 

Definition at line 600 of file logtape.c.

References LogicalTapeSet::forgetFreeSpace.

Referenced by mergeruns().

{
    lts->forgetFreeSpace = true;
}

void LogicalTapeTell ( LogicalTapeSet lts,
int  tapenum,
long *  blocknum,
int *  offset 
)

Definition at line 1005 of file logtape.c.

References Assert, LogicalTape::curBlockNumber, LogicalTape::pos, and LogicalTapeSet::tapes.

Referenced by tuplesort_markpos().

{
    LogicalTape *lt;

    Assert(tapenum >= 0 && tapenum < lts->nTapes);
    lt = &lts->tapes[tapenum];
    *blocknum = lt->curBlockNumber;
    *offset = lt->pos;
}

void LogicalTapeWrite ( LogicalTapeSet lts,
int  tapenum,
void *  ptr,
size_t  size 
)

Definition at line 626 of file logtape.c.

References Assert, LogicalTape::buffer, LogicalTape::curBlockNumber, LogicalTape::dirty, elog, ERROR, LogicalTape::indirect, ltsDumpBuffer(), LogicalTape::nbytes, IndirectBlock::nextSlot, IndirectBlock::nextup, NULL, LogicalTape::numFullBlocks, palloc(), LogicalTape::pos, LogicalTapeSet::tapes, and LogicalTape::writing.

Referenced by markrunend(), writetup_cluster(), writetup_datum(), writetup_heap(), and writetup_index().

{
    LogicalTape *lt;
    size_t      nthistime;

    Assert(tapenum >= 0 && tapenum < lts->nTapes);
    lt = &lts->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)
        {
            /* Buffer full, dump it out */
            if (lt->dirty)
                ltsDumpBuffer(lts, lt);
            else
            {
                /* Hmm, went directly from reading to writing? */
                elog(ERROR, "invalid logtape state: should be dirty");
            }
            lt->numFullBlocks++;
            lt->curBlockNumber++;
            lt->pos = 0;
            lt->nbytes = 0;
        }

        nthistime = BLCKSZ - lt->pos;
        if (nthistime > size)
            nthistime = size;
        Assert(nthistime > 0);

        memcpy(lt->buffer + lt->pos, ptr, nthistime);

        lt->dirty = true;
        lt->pos += nthistime;
        if (lt->nbytes < lt->pos)
            lt->nbytes = lt->pos;
        ptr = (void *) ((char *) ptr + nthistime);
        size -= nthistime;
    }
}