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 = &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;}/* * 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 = &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);}/* * 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 = &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;	}}/* * 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 + -
显示快捷键?