#include "postgres.h"#include "storage/buffile.h"#include "utils/logtape.h"
Go to the source code of this file.
Data Structures | |
| struct | IndirectBlock |
| struct | LogicalTape |
| struct | LogicalTapeSet |
Defines | |
| #define | BLOCKS_PER_INDIR_BLOCK ((int) (BLCKSZ / sizeof(long))) |
Typedefs | |
| typedef struct IndirectBlock | IndirectBlock |
| typedef struct LogicalTape | LogicalTape |
Functions | |
| static void | ltsWriteBlock (LogicalTapeSet *lts, long blocknum, void *buffer) |
| static void | ltsReadBlock (LogicalTapeSet *lts, long blocknum, void *buffer) |
| static long | ltsGetFreeBlock (LogicalTapeSet *lts) |
| static void | ltsReleaseBlock (LogicalTapeSet *lts, long blocknum) |
| static void | ltsRecordBlockNum (LogicalTapeSet *lts, IndirectBlock *indirect, long blocknum) |
| static long | ltsRewindIndirectBlock (LogicalTapeSet *lts, IndirectBlock *indirect, bool freezing) |
| static long | ltsRewindFrozenIndirectBlock (LogicalTapeSet *lts, IndirectBlock *indirect) |
| static long | ltsRecallNextBlockNum (LogicalTapeSet *lts, IndirectBlock *indirect, bool frozen) |
| static long | ltsRecallPrevBlockNum (LogicalTapeSet *lts, IndirectBlock *indirect) |
| static void | ltsDumpBuffer (LogicalTapeSet *lts, LogicalTape *lt) |
| static int | freeBlocks_cmp (const void *a, const void *b) |
| LogicalTapeSet * | LogicalTapeSetCreate (int ntapes) |
| void | LogicalTapeSetClose (LogicalTapeSet *lts) |
| void | LogicalTapeSetForgetFreeSpace (LogicalTapeSet *lts) |
| void | LogicalTapeWrite (LogicalTapeSet *lts, int tapenum, void *ptr, size_t size) |
| void | LogicalTapeRewind (LogicalTapeSet *lts, int tapenum, bool forWrite) |
| size_t | LogicalTapeRead (LogicalTapeSet *lts, int tapenum, void *ptr, size_t size) |
| 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) |
| #define BLOCKS_PER_INDIR_BLOCK ((int) (BLCKSZ / sizeof(long))) |
Definition at line 87 of file logtape.c.
Referenced by ltsRecallNextBlockNum(), ltsRecallPrevBlockNum(), ltsRecordBlockNum(), and ltsRewindIndirectBlock().
| typedef struct IndirectBlock IndirectBlock |
| typedef struct LogicalTape LogicalTape |
| static int freeBlocks_cmp | ( | const void * | a, | |
| const void * | b | |||
| ) | [static] |
Definition at line 240 of file logtape.c.
Referenced by ltsGetFreeBlock().
{
long ablk = *((const long *) a);
long bblk = *((const long *) b);
/* can't just subtract because long might be wider than int */
if (ablk < bblk)
return 1;
if (ablk > bblk)
return -1;
return 0;
}
| 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 = <s->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 = <s->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 = <s->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 = <s->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 = <s->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 = <s->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 = <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;
}
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 = <s->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 = <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)
{
/* 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;
}
}
| static void ltsDumpBuffer | ( | LogicalTapeSet * | lts, | |
| LogicalTape * | lt | |||
| ) | [static] |
Definition at line 609 of file logtape.c.
References Assert, LogicalTape::buffer, LogicalTape::dirty, LogicalTape::indirect, ltsGetFreeBlock(), ltsRecordBlockNum(), and ltsWriteBlock().
Referenced by LogicalTapeFreeze(), LogicalTapeRewind(), and LogicalTapeWrite().
{
long datablock = ltsGetFreeBlock(lts);
Assert(lt->dirty);
ltsWriteBlock(lts, datablock, (void *) lt->buffer);
ltsRecordBlockNum(lts, lt->indirect, datablock);
lt->dirty = false;
/* Caller must do other state update as needed */
}
| static long ltsGetFreeBlock | ( | LogicalTapeSet * | lts | ) | [static] |
Definition at line 260 of file logtape.c.
References LogicalTapeSet::blocksSorted, LogicalTapeSet::freeBlocks, freeBlocks_cmp(), LogicalTapeSet::nFileBlocks, LogicalTapeSet::nFreeBlocks, and qsort.
Referenced by ltsDumpBuffer(), ltsRecordBlockNum(), and ltsRewindIndirectBlock().
{
/*
* If there are multiple free blocks, we select the one appearing last in
* freeBlocks[] (after sorting the array if needed). If there are none,
* assign the next block at the end of the file.
*/
if (lts->nFreeBlocks > 0)
{
if (!lts->blocksSorted)
{
qsort((void *) lts->freeBlocks, lts->nFreeBlocks,
sizeof(long), freeBlocks_cmp);
lts->blocksSorted = true;
}
return lts->freeBlocks[--lts->nFreeBlocks];
}
else
return lts->nFileBlocks++;
}
| static void ltsReadBlock | ( | LogicalTapeSet * | lts, | |
| long | blocknum, | |||
| void * | buffer | |||
| ) | [static] |
Definition at line 225 of file logtape.c.
References BufFileRead(), BufFileSeekBlock(), ereport, errcode_for_file_access(), errmsg(), ERROR, and LogicalTapeSet::pfile.
Referenced by LogicalTapeBackspace(), LogicalTapeFreeze(), LogicalTapeRead(), LogicalTapeRewind(), LogicalTapeSeek(), ltsRecallNextBlockNum(), ltsRecallPrevBlockNum(), ltsRewindFrozenIndirectBlock(), and ltsRewindIndirectBlock().
{
if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
BufFileRead(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
ereport(ERROR,
/* XXX is it okay to assume errno is correct? */
(errcode_for_file_access(),
errmsg("could not read block %ld of temporary file: %m",
blocknum)));
}
| static long ltsRecallNextBlockNum | ( | LogicalTapeSet * | lts, | |
| IndirectBlock * | indirect, | |||
| bool | frozen | |||
| ) | [static] |
Definition at line 445 of file logtape.c.
References BLOCKS_PER_INDIR_BLOCK, ltsReadBlock(), ltsReleaseBlock(), IndirectBlock::nextSlot, IndirectBlock::nextup, NULL, and IndirectBlock::ptrs.
Referenced by LogicalTapeRead(), and LogicalTapeSeek().
{
/* Handle case of never-written-to tape */
if (indirect == NULL)
return -1L;
if (indirect->nextSlot >= BLOCKS_PER_INDIR_BLOCK ||
indirect->ptrs[indirect->nextSlot] == -1L)
{
long indirblock;
if (indirect->nextup == NULL)
return -1L; /* nothing left at this level */
indirblock = ltsRecallNextBlockNum(lts, indirect->nextup, frozen);
if (indirblock == -1L)
return -1L; /* nothing left at this level */
ltsReadBlock(lts, indirblock, (void *) indirect->ptrs);
if (!frozen)
ltsReleaseBlock(lts, indirblock);
indirect->nextSlot = 0;
}
if (indirect->ptrs[indirect->nextSlot] == -1L)
return -1L;
return indirect->ptrs[indirect->nextSlot++];
}
| static long ltsRecallPrevBlockNum | ( | LogicalTapeSet * | lts, | |
| IndirectBlock * | indirect | |||
| ) | [static] |
Definition at line 483 of file logtape.c.
References BLOCKS_PER_INDIR_BLOCK, ltsReadBlock(), IndirectBlock::nextSlot, IndirectBlock::nextup, NULL, and IndirectBlock::ptrs.
Referenced by LogicalTapeBackspace(), and LogicalTapeSeek().
{
/* Handle case of never-written-to tape */
if (indirect == NULL)
return -1L;
if (indirect->nextSlot <= 1)
{
long indirblock;
if (indirect->nextup == NULL)
return -1L; /* nothing left at this level */
indirblock = ltsRecallPrevBlockNum(lts, indirect->nextup);
if (indirblock == -1L)
return -1L; /* nothing left at this level */
ltsReadBlock(lts, indirblock, (void *) indirect->ptrs);
/*
* The previous block would only have been written out if full, so we
* need not search it for a -1 sentinel.
*/
indirect->nextSlot = BLOCKS_PER_INDIR_BLOCK + 1;
}
indirect->nextSlot--;
return indirect->ptrs[indirect->nextSlot - 1];
}
| static void ltsRecordBlockNum | ( | LogicalTapeSet * | lts, | |
| IndirectBlock * | indirect, | |||
| long | blocknum | |||
| ) | [static] |
Definition at line 325 of file logtape.c.
References BLOCKS_PER_INDIR_BLOCK, ltsGetFreeBlock(), ltsWriteBlock(), IndirectBlock::nextSlot, IndirectBlock::nextup, NULL, palloc(), and IndirectBlock::ptrs.
Referenced by ltsDumpBuffer(), and ltsRewindIndirectBlock().
{
if (indirect->nextSlot >= BLOCKS_PER_INDIR_BLOCK)
{
/*
* This indirect block is full, so dump it out and recursively save
* its address in the next indirection level. Create a new
* indirection level if there wasn't one before.
*/
long indirblock = ltsGetFreeBlock(lts);
ltsWriteBlock(lts, indirblock, (void *) indirect->ptrs);
if (indirect->nextup == NULL)
{
indirect->nextup = (IndirectBlock *) palloc(sizeof(IndirectBlock));
indirect->nextup->nextSlot = 0;
indirect->nextup->nextup = NULL;
}
ltsRecordBlockNum(lts, indirect->nextup, indirblock);
/*
* Reset to fill another indirect block at this level.
*/
indirect->nextSlot = 0;
}
indirect->ptrs[indirect->nextSlot++] = blocknum;
}
| static void ltsReleaseBlock | ( | LogicalTapeSet * | lts, | |
| long | blocknum | |||
| ) | [static] |
Definition at line 285 of file logtape.c.
References LogicalTapeSet::blocksSorted, LogicalTapeSet::forgetFreeSpace, LogicalTapeSet::freeBlocks, LogicalTapeSet::freeBlocksLen, LogicalTapeSet::nFreeBlocks, and repalloc().
Referenced by LogicalTapeRead(), LogicalTapeRewind(), ltsRecallNextBlockNum(), and ltsRewindIndirectBlock().
{
int ndx;
/*
* Do nothing if we're no longer interested in remembering free space.
*/
if (lts->forgetFreeSpace)
return;
/*
* Enlarge freeBlocks array if full.
*/
if (lts->nFreeBlocks >= lts->freeBlocksLen)
{
lts->freeBlocksLen *= 2;
lts->freeBlocks = (long *) repalloc(lts->freeBlocks,
lts->freeBlocksLen * sizeof(long));
}
/*
* Add blocknum to array, and mark the array unsorted if it's no longer in
* decreasing order.
*/
ndx = lts->nFreeBlocks++;
lts->freeBlocks[ndx] = blocknum;
if (ndx > 0 && lts->freeBlocks[ndx - 1] < blocknum)
lts->blocksSorted = false;
}
| static long ltsRewindFrozenIndirectBlock | ( | LogicalTapeSet * | lts, | |
| IndirectBlock * | indirect | |||
| ) | [static] |
Definition at line 409 of file logtape.c.
References Assert, ltsReadBlock(), IndirectBlock::nextSlot, IndirectBlock::nextup, NULL, and IndirectBlock::ptrs.
Referenced by LogicalTapeRewind().
{
/* 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.
*/
if (indirect->nextup != NULL)
{
long indirblock;
indirblock = ltsRewindFrozenIndirectBlock(lts, indirect->nextup);
Assert(indirblock != -1L);
ltsReadBlock(lts, indirblock, (void *) indirect->ptrs);
}
/*
* Reset my next-block pointer, and then fetch a block number if any.
*/
indirect->nextSlot = 0;
if (indirect->ptrs[0] == -1L)
return -1L;
return indirect->ptrs[indirect->nextSlot++];
}
| static long ltsRewindIndirectBlock | ( | LogicalTapeSet * | lts, | |
| IndirectBlock * | indirect, | |||
| bool | freezing | |||
| ) | [static] |
Definition at line 365 of file logtape.c.
References Assert, BLOCKS_PER_INDIR_BLOCK, ltsGetFreeBlock(), ltsReadBlock(), ltsRecordBlockNum(), ltsReleaseBlock(), ltsWriteBlock(), IndirectBlock::nextSlot, IndirectBlock::nextup, NULL, and IndirectBlock::ptrs.
Referenced by LogicalTapeFreeze(), and LogicalTapeRewind().
{
/* 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;
/*
* If block is not topmost, write it out, and recurse to obtain address of
* first block in this hierarchy level. Read that one in.
*/
if (indirect->nextup != NULL)
{
long indirblock = ltsGetFreeBlock(lts);
ltsWriteBlock(lts, indirblock, (void *) indirect->ptrs);
ltsRecordBlockNum(lts, indirect->nextup, indirblock);
indirblock = ltsRewindIndirectBlock(lts, indirect->nextup, freezing);
Assert(indirblock != -1L);
ltsReadBlock(lts, indirblock, (void *) indirect->ptrs);
if (!freezing)
ltsReleaseBlock(lts, indirblock);
}
/*
* Reset my next-block pointer, and then fetch a block number if any.
*/
indirect->nextSlot = 0;
if (indirect->ptrs[0] == -1L)
return -1L;
return indirect->ptrs[indirect->nextSlot++];
}
| static void ltsWriteBlock | ( | LogicalTapeSet * | lts, | |
| long | blocknum, | |||
| void * | buffer | |||
| ) | [static] |
Definition at line 206 of file logtape.c.
References BufFileSeekBlock(), BufFileWrite(), ereport, errcode_for_file_access(), errhint(), errmsg(), ERROR, and LogicalTapeSet::pfile.
Referenced by ltsDumpBuffer(), ltsRecordBlockNum(), and ltsRewindIndirectBlock().
{
if (BufFileSeekBlock(lts->pfile, blocknum) != 0 ||
BufFileWrite(lts->pfile, buffer, BLCKSZ) != BLCKSZ)
ereport(ERROR,
/* XXX is it okay to assume errno is correct? */
(errcode_for_file_access(),
errmsg("could not write block %ld of temporary file: %m",
blocknum),
errhint("Perhaps out of disk space?")));
}
1.7.1