logtape.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,024 行 · 第 1/3 页
C
1,024 行
*/voidLogicalTapeRewind(LogicalTapeSet *lts, int tapenum, bool forWrite){ 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; }}/* * Read from a logical tape. * * Early EOF is indicated by return value less than #bytes requested. */size_tLogicalTapeRead(LogicalTapeSet *lts, int tapenum, void *ptr, size_t size){ 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;}/* * "Freeze" the contents of a tape so that it can be read multiple times * and/or read backwards. Once a tape is frozen, its contents will not * be released until the LogicalTapeSet is destroyed. This is expected * to be used only for the final output pass of a merge. * * This *must* be called just at the end of a write pass, before the * tape is rewound (after rewind is too late!). It performs a rewind * and switch to read mode "for free". An immediately following rewind- * for-read call is OK but not necessary. */voidLogicalTapeFreeze(LogicalTapeSet *lts, int tapenum){ 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; }}/* * Backspace the tape a given number of bytes. (We also support a more * general seek interface, see below.) * * *Only* a frozen-for-read tape can be backed up; we don't support * random access during write, and an unfrozen read tape may have * already discarded the desired data! * * Return value is TRUE if seek successful, FALSE if there isn't that much * data before the current point (in which case there's no state change). */boolLogicalTapeBackspace(LogicalTapeSet *lts, int tapenum, size_t size){ 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;}/* * Seek to an arbitrary position in a logical tape. * * *Only* a frozen-for-read tape can be seeked. * * Return value is TRUE if seek successful, FALSE if there isn't that much * data in the tape (in which case there's no state change). */boolLogicalTapeSeek(LogicalTapeSet *lts, int tapenum, long blocknum, int offset){ 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;}/* * Obtain current position in a form suitable for a later LogicalTapeSeek. * * NOTE: it'd be OK to do this during write phase with intention of using * the position for a seek after freezing. Not clear if anyone needs that. */voidLogicalTapeTell(LogicalTapeSet *lts, int tapenum, long *blocknum, int *offset){ LogicalTape *lt; Assert(tapenum >= 0 && tapenum < lts->nTapes); lt = <s->tapes[tapenum]; *blocknum = lt->curBlockNumber; *offset = lt->pos;}/* * Obtain total disk space currently used by a LogicalTapeSet, in blocks. */longLogicalTapeSetBlocks(LogicalTapeSet *lts){ return lts->nFileBlocks;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?