#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?"))); }