logtape.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,024 行 · 第 1/3 页
C
1,024 行
} ltsRecordBlockNum(lts, indirect->nextup, indirblock); /* * Reset to fill another indirect block at this level. */ indirect->nextSlot = 0; } indirect->ptrs[indirect->nextSlot++] = blocknum;}/* * Reset a logical tape's indirect-block hierarchy after a write pass * to prepare for reading. We dump out partly-filled blocks except * at the top of the hierarchy, and we rewind each level to the start. * This call returns the first data block number, or -1L if the tape * is empty. * * Unless 'freezing' is true, release indirect blocks to the free pool after * reading them. */static longltsRewindIndirectBlock(LogicalTapeSet *lts, 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; /* * 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++];}/* * Rewind a previously-frozen indirect-block hierarchy for another read pass. * This call returns the first data block number, or -1L if the tape * is empty. */static longltsRewindFrozenIndirectBlock(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. */ 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++];}/* * Obtain next data block number in the forward direction, or -1L if no more. * * Unless 'frozen' is true, release indirect blocks to the free pool after * reading them. */static longltsRecallNextBlockNum(LogicalTapeSet *lts, 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) { 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++];}/* * Obtain next data block number in the reverse direction, or -1L if no more. * * Note this fetches the block# before the one last returned, no matter which * direction of call returned that one. If we fail, no change in state. * * This routine can only be used in 'frozen' state, so there's no need to * pass a parameter telling whether to release blocks ... we never do. */static longltsRecallPrevBlockNum(LogicalTapeSet *lts, IndirectBlock *indirect){ /* 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];}/* * Create a set of logical tapes in a temporary underlying file. * * Each tape is initialized in write state. */LogicalTapeSet *LogicalTapeSetCreate(int ntapes){ 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;}/* * Close a logical tape set and release all resources. */voidLogicalTapeSetClose(LogicalTapeSet *lts){ 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);}/* * Mark a logical tape set as not needing management of free space anymore. * * This should be called if the caller does not intend to write any more data * into the tape set, but is reading from un-frozen tapes. Since no more * writes are planned, remembering free blocks is no longer useful. Setting * this flag lets us avoid wasting time and space in ltsReleaseBlock(), which * is not designed to handle large numbers of free blocks. */voidLogicalTapeSetForgetFreeSpace(LogicalTapeSet *lts){ lts->forgetFreeSpace = true;}/* * Dump the dirty buffer of a logical tape. */static voidltsDumpBuffer(LogicalTapeSet *lts, LogicalTape *lt){ 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 */}/* * Write to a logical tape. * * There are no error returns; we ereport() on failure. */voidLogicalTapeWrite(LogicalTapeSet *lts, int tapenum, void *ptr, size_t size){ 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; }}/* * Rewind logical tape and switch from writing to reading or vice versa. * * Unless the tape has been "frozen" in read state, forWrite must be the * opposite of the previous tape state.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?