Beispiel #1
0
/*
 * Update the upper levels of the free space map all the way up to the root
 * to make sure we don't lose track of new blocks we just inserted.  This is
 * intended to be used after adding many new blocks to the relation; we judge
 * it not worth updating the upper levels of the tree every time data for
 * a single page changes, but for a bulk-extend it's worth it.
 */
void
UpdateFreeSpaceMap(Relation rel, BlockNumber startBlkNum,
					BlockNumber endBlkNum, Size freespace)
{
	int			new_cat = fsm_space_avail_to_cat(freespace);
	FSMAddress	addr;
	uint16		slot;
	BlockNumber	blockNum;
	BlockNumber	lastBlkOnPage;

	blockNum = startBlkNum;

	while (blockNum <= endBlkNum)
	{
		/*
		 * Find FSM address for this block; update tree all the way to the
		 * root.
		 */
		addr = fsm_get_location(blockNum, &slot);
		fsm_update_recursive(rel, addr, new_cat);

		/*
		 * Get the last block number on this FSM page.  If that's greater
		 * than or equal to our endBlkNum, we're done.  Otherwise, advance
		 * to the first block on the next page.
		 */
		lastBlkOnPage = fsm_get_lastblckno(rel, addr);
		if (lastBlkOnPage >= endBlkNum)
			break;
		blockNum = lastBlkOnPage + 1;
	}
}
Beispiel #2
0
/*
 * XLogRecordPageWithFreeSpace - like RecordPageWithFreeSpace, for use in
 *		WAL replay
 */
void
XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
							Size spaceAvail)
{
	int			new_cat = fsm_space_avail_to_cat(spaceAvail);
	FSMAddress	addr;
	uint16		slot;
	BlockNumber blkno;
	Buffer		buf;
	Page		page;

	/* Get the location of the FSM byte representing the heap block */
	addr = fsm_get_location(heapBlk, &slot);
	blkno = fsm_logical_to_physical(addr);

	/* If the page doesn't exist already, extend */
	buf = XLogReadBufferExtended(rnode, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR);
	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);

	page = BufferGetPage(buf);
	if (PageIsNew(page))
		PageInit(page, BLCKSZ, 0);

	if (fsm_set_avail(page, slot, new_cat))
		MarkBufferDirtyHint(buf, false);
	UnlockReleaseBuffer(buf);
}
Beispiel #3
0
/*
 * RecordPageWithFreeSpace - update info about a page.
 *
 * Note that if the new___ spaceAvail value is higher than the old value stored
 * in the FSM, the space might not become visible to searchers until the next
 * FreeSpaceMapVacuum call, which updates the upper level pages.
 */
void
RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, Size spaceAvail)
{
	int			new_cat = fsm_space_avail_to_cat(spaceAvail);
	FSMAddress	addr;
	uint16		slot;

	/* Get the location of the FSM byte representing the heap block */
	addr = fsm_get_location(heapBlk, &slot);

	fsm_set_and_search(rel, addr, slot, new_cat, 0);
}
Beispiel #4
0
/*
 * XLogRecordPageWithFreeSpace - like RecordPageWithFreeSpace, for use in
 *		WAL replay
 */
void
XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
							Size spaceAvail)
{
	int			new_cat = fsm_space_avail_to_cat(spaceAvail);
	FSMAddress	addr;
	uint16		slot;
	BlockNumber blkno;
	Buffer		buf;
	Page		page;
	bool		write_to_fsm;

	/* This is meant to mirror the logic in fsm_allow_writes() */
	if (heapBlk >= HEAP_FSM_CREATION_THRESHOLD)
		write_to_fsm = true;
	else
	{
		/* Open the relation at smgr level */
		SMgrRelation smgr = smgropen(rnode, InvalidBackendId);

		if (smgrexists(smgr, FSM_FORKNUM))
			write_to_fsm = true;
		else
		{
			BlockNumber heap_nblocks = smgrnblocks(smgr, MAIN_FORKNUM);

			if (heap_nblocks > HEAP_FSM_CREATION_THRESHOLD)
				write_to_fsm = true;
			else
				write_to_fsm = false;
		}
	}

	if (!write_to_fsm)
		return;

	/* Get the location of the FSM byte representing the heap block */
	addr = fsm_get_location(heapBlk, &slot);
	blkno = fsm_logical_to_physical(addr);

	/* If the page doesn't exist already, extend */
	buf = XLogReadBufferExtended(rnode, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR);
	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);

	page = BufferGetPage(buf);
	if (PageIsNew(page))
		PageInit(page, BLCKSZ, 0);

	if (fsm_set_avail(page, slot, new_cat))
		MarkBufferDirtyHint(buf, false);
	UnlockReleaseBuffer(buf);
}
Beispiel #5
0
/*
 * RecordAndGetPageWithFreeSpace - update info about a page and try again.
 *
 * We provide this combo form to save some locking overhead, compared to
 * separate RecordPageWithFreeSpace + GetPageWithFreeSpace calls. There's
 * also some effort to return a page close to the old page; if there's a
 * page with enough free space on the same FSM page where the old one page
 * is located, it is preferred.
 *
 * For very small heap relations that don't have a FSM, we update the local
 * map to indicate we have tried a page, and return the next page to try.
 */
BlockNumber
RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage,
							  Size oldSpaceAvail, Size spaceNeeded)
{
	int			old_cat;
	int			search_cat;
	FSMAddress	addr;
	uint16		slot;
	int			search_slot;
	BlockNumber nblocks = InvalidBlockNumber;

	/* First try the local map, if it exists. */
	if (FSM_LOCAL_MAP_EXISTS)
	{
		Assert((rel->rd_rel->relkind == RELKIND_RELATION ||
				rel->rd_rel->relkind == RELKIND_TOASTVALUE) &&
			   fsm_local_map.map[oldPage] == FSM_LOCAL_AVAIL);

		fsm_local_map.map[oldPage] = FSM_LOCAL_NOT_AVAIL;
		return fsm_local_search();
	}

	if (!fsm_allow_writes(rel, oldPage, InvalidBlockNumber, &nblocks))
	{
		/*
		 * If we have neither a local map nor a FSM, we probably just tried
		 * the target block in the smgr relation entry and failed, so we'll
		 * need to create the local map.
		 */
		fsm_local_set(rel, nblocks);
		return fsm_local_search();
	}

	/* Normal FSM logic follows */

	old_cat = fsm_space_avail_to_cat(oldSpaceAvail);
	search_cat = fsm_space_needed_to_cat(spaceNeeded);

	/* Get the location of the FSM byte representing the heap block */
	addr = fsm_get_location(oldPage, &slot);

	search_slot = fsm_set_and_search(rel, addr, slot, old_cat, search_cat);

	/*
	 * If fsm_set_and_search found a suitable new block, return that.
	 * Otherwise, search as usual.
	 */
	if (search_slot != -1)
		return fsm_get_heap_blk(addr, search_slot);
	else
		return fsm_search(rel, search_cat);
}
Beispiel #6
0
/*
 * RecordPageWithFreeSpace - update info about a page.
 *
 * Note that if the new spaceAvail value is higher than the old value stored
 * in the FSM, the space might not become visible to searchers until the next
 * FreeSpaceMapVacuum call, which updates the upper level pages.
 *
 * Callers have no need for a local map.
 */
void
RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk,
						Size spaceAvail, BlockNumber nblocks)
{
	int			new_cat;
	FSMAddress	addr;
	uint16		slot;
	BlockNumber dummy;

	if (!fsm_allow_writes(rel, heapBlk, nblocks, &dummy))
		/* No FSM to update and no local map either */
		return;

	/* Get the location of the FSM byte representing the heap block */
	addr = fsm_get_location(heapBlk, &slot);

	new_cat = fsm_space_avail_to_cat(spaceAvail);
	fsm_set_and_search(rel, addr, slot, new_cat, 0);
}
Beispiel #7
0
/*
 * RecordAndGetPageWithFreeSpace - update info about a page and try again.
 *
 * We provide this combo form to save some locking overhead, compared to
 * separate RecordPageWithFreeSpace + GetPageWithFreeSpace calls. There's
 * also some effort to return a page close to the old page; if there's a
 * page with enough free space on the same FSM page where the old one page
 * is located, it is preferred.
 */
BlockNumber
RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage,
							  Size oldSpaceAvail, Size spaceNeeded)
{
	int			old_cat = fsm_space_avail_to_cat(oldSpaceAvail);
	int			search_cat = fsm_space_needed_to_cat(spaceNeeded);
	FSMAddress	addr;
	uint16		slot;
	int			search_slot;

	/* Get the location of the FSM byte representing the heap block */
	addr = fsm_get_location(oldPage, &slot);

	search_slot = fsm_set_and_search(rel, addr, slot, old_cat, search_cat);

	/*
	 * If fsm_set_and_search found a suitable new___ block, return that.
	 * Otherwise, search as usual.
	 */
	if (search_slot != -1)
		return fsm_get_heap_blk(addr, search_slot);
	else
		return fsm_search(rel, search_cat);
}