Exemple #1
0
/*
 * Read from a logical tape.
 *
 * Early EOF is indicated by return value less than #bytes requested.
 */
size_t
LogicalTapeRead(LogicalTapeSet *lts, LogicalTape *lt, void *ptr, size_t size)
{
	size_t		nread = 0;
	size_t		nthistime;

	Assert(!lt->writing);

	if(lt->currPos.blkNum == -1)
		return nread;

	while (size > 0)
	{
		Assert(lt->currPos.offset <= lt->currBlk.payload_tail);
		if(lt->currPos.offset == lt->currBlk.payload_tail)
		{
			if(lt->currBlk.next_blk == -1)
			{
				if(!lt->frozen)
				{
					ltsReleaseBlock(lts, lt->currPos.blkNum);
					lt->firstBlkNum = -1L;
					lt->currPos.blkNum = -1L;
					lt->currPos.offset = 0;
				}
				return nread;
			}
			
			lt->currPos.blkNum = lt->currBlk.next_blk;
			lt->currPos.offset = 0;
			ltsReadBlock(lts, lt->currBlk.next_blk, &lt->currBlk);

			if(!lt->frozen)
			{
				ltsReleaseBlock(lts, lt->currBlk.prev_blk);
				lt->firstBlkNum = lt->currPos.blkNum;
			}
		}

		if(lt->currPos.offset < lt->currBlk.payload_tail)
		{
			nthistime = size > (lt->currBlk.payload_tail - lt->currPos.offset) ?
				lt->currBlk.payload_tail - lt->currPos.offset :
				size;

			memcpy(ptr, lt->currBlk.payload + lt->currPos.offset, nthistime);
			size -= nthistime;
			ptr = (void *) ((char *) ptr + nthistime);
			lt->currPos.offset += nthistime;
			nread += nthistime;
		}
	}

	return nread;
}
Exemple #2
0
/*
 * 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 long
ltsRecallNextBlockNum(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++];
}
Exemple #3
0
/*
 * Read from a logical tape.
 *
 * Early EOF is indicated by return value less than #bytes requested.
 */
size_t
LogicalTapeRead(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 = &lts->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;
}
Exemple #4
0
/*
 * 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 long
ltsRewindIndirectBlock(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++];
}
Exemple #5
0
/*
 * Read as many blocks as we can into the per-tape buffer.
 *
 * Returns true if anything was read, 'false' on EOF.
 */
static bool
ltsReadFillBuffer(LogicalTapeSet *lts, LogicalTape *lt)
{
	lt->pos = 0;
	lt->nbytes = 0;

	do
	{
		char	   *thisbuf = lt->buffer + lt->nbytes;
		long		datablocknum = lt->nextBlockNumber;

		/* Fetch next block number */
		if (datablocknum == -1L)
			break;				/* EOF */
		/* Apply worker offset, needed for leader tapesets */
		datablocknum += lt->offsetBlockNumber;

		/* Read the block */
		ltsReadBlock(lts, datablocknum, (void *) thisbuf);
		if (!lt->frozen)
			ltsReleaseBlock(lts, datablocknum);
		lt->curBlockNumber = lt->nextBlockNumber;

		lt->nbytes += TapeBlockGetNBytes(thisbuf);
		if (TapeBlockIsLast(thisbuf))
		{
			lt->nextBlockNumber = -1L;
			/* EOF */
			break;
		}
		else
			lt->nextBlockNumber = TapeBlockGetTrailer(thisbuf)->next;

		/* Advance to next block, if we have buffer space left */
	} while (lt->buffer_size - lt->nbytes > BLCKSZ);

	return (lt->nbytes > 0);
}
Exemple #6
0
/*
 * 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.
 */
void
LogicalTapeRewind(LogicalTapeSet *lts, int tapenum, bool forWrite)
{
	LogicalTape *lt;
	long		datablocknum;

	Assert(tapenum >= 0 && tapenum < lts->nTapes);
	lt = &lts->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;
	}
}