⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 freespace.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
			}		}		pfree(data);	}read_failed:	/* Clean up */	LWLockRelease(FreeSpaceLock);	FreeFile(fp);	/* Remove cache file before it can become stale; see notes above */	unlink(cachefilename);}/* * Internal routines.  These all assume the caller holds the FreeSpaceLock. *//* * Lookup a relation in the hash table.  If not present, return NULL. * * The relation's position in the LRU list is not changed. */static FSMRelation *lookup_fsm_rel(RelFileNode *rel){	FSMRelation *fsmrel;	fsmrel = (FSMRelation *) hash_search(FreeSpaceMap->relHash,										 (void *) rel,										 HASH_FIND,										 NULL);	if (!fsmrel)		return NULL;	return fsmrel;}/* * Lookup a relation in the hash table, creating an entry if not present. * * On successful lookup, the relation is moved to the front of the LRU list. */static FSMRelation *create_fsm_rel(RelFileNode *rel){	FSMRelation *fsmrel;	bool		found;	fsmrel = (FSMRelation *) hash_search(FreeSpaceMap->relHash,										 (void *) rel,										 HASH_ENTER,										 &found);	if (!fsmrel)		ereport(ERROR,				(errcode(ERRCODE_OUT_OF_MEMORY),				 errmsg("out of shared memory")));	if (!found)	{		/* New hashtable entry, initialize it (hash_search set the key) */		fsmrel->isIndex = false;	/* until we learn different */		fsmrel->avgRequest = INITIAL_AVERAGE;		fsmrel->lastPageCount = 0;		fsmrel->firstChunk = -1;	/* no space allocated */		fsmrel->storedPages = 0;		fsmrel->nextPage = 0;		/* Discard lowest-priority existing rel, if we are over limit */		if (FreeSpaceMap->numRels >= MaxFSMRelations)			delete_fsm_rel(FreeSpaceMap->usageListTail);		/* Add new entry at front of LRU list */		link_fsm_rel_usage(fsmrel);		fsmrel->nextPhysical = NULL;	/* not in physical-storage list */		fsmrel->priorPhysical = NULL;		FreeSpaceMap->numRels++;		/* sumRequests is unchanged because request must be zero */	}	else	{		/* Existing entry, move to front of LRU list */		if (fsmrel->priorUsage != NULL)		{			unlink_fsm_rel_usage(fsmrel);			link_fsm_rel_usage(fsmrel);		}	}	return fsmrel;}/* * Remove an existing FSMRelation entry. */static voiddelete_fsm_rel(FSMRelation *fsmrel){	FSMRelation *result;	FreeSpaceMap->sumRequests -= fsm_calc_request(fsmrel);	unlink_fsm_rel_usage(fsmrel);	unlink_fsm_rel_storage(fsmrel);	FreeSpaceMap->numRels--;	result = (FSMRelation *) hash_search(FreeSpaceMap->relHash,										 (void *) &(fsmrel->key),										 HASH_REMOVE,										 NULL);	if (!result)		elog(ERROR, "FreeSpaceMap hashtable corrupted");}/* * Reallocate space for a FSMRelation. * * This is shared code for RecordRelationFreeSpace and RecordIndexFreeSpace. * The return value is the actual new allocation, in chunks. */static intrealloc_fsm_rel(FSMRelation *fsmrel, int nPages, bool isIndex){	int			myRequest;	int			myAlloc;	int			curAlloc;	/*	 * Delete any existing entries, and update request status.	 */	fsmrel->storedPages = 0;	FreeSpaceMap->sumRequests -= fsm_calc_request(fsmrel);	fsmrel->lastPageCount = nPages;	fsmrel->isIndex = isIndex;	myRequest = fsm_calc_request(fsmrel);	FreeSpaceMap->sumRequests += myRequest;	myAlloc = fsm_calc_target_allocation(myRequest);	/*	 * Need to reallocate space if (a) my target allocation is more than	 * my current allocation, AND (b) my actual immediate need	 * (myRequest+1 chunks) is more than my current allocation. Otherwise	 * just store the new data in-place.	 */	curAlloc = fsm_current_allocation(fsmrel);	if (myAlloc > curAlloc && (myRequest + 1) > curAlloc && nPages > 0)	{		/* Remove entry from storage list, and compact */		unlink_fsm_rel_storage(fsmrel);		compact_fsm_storage();		/* Reattach to end of storage list */		link_fsm_rel_storage(fsmrel);		/* And allocate storage */		fsmrel->firstChunk = FreeSpaceMap->usedChunks;		FreeSpaceMap->usedChunks += myAlloc;		curAlloc = myAlloc;		/* Watch out for roundoff error */		if (FreeSpaceMap->usedChunks > FreeSpaceMap->totalChunks)		{			FreeSpaceMap->usedChunks = FreeSpaceMap->totalChunks;			curAlloc = FreeSpaceMap->totalChunks - fsmrel->firstChunk;		}	}	return curAlloc;}/* * Link a FSMRelation into the LRU list (always at the head). */static voidlink_fsm_rel_usage(FSMRelation *fsmrel){	fsmrel->priorUsage = NULL;	fsmrel->nextUsage = FreeSpaceMap->usageList;	FreeSpaceMap->usageList = fsmrel;	if (fsmrel->nextUsage != NULL)		fsmrel->nextUsage->priorUsage = fsmrel;	else		FreeSpaceMap->usageListTail = fsmrel;}/* * Delink a FSMRelation from the LRU list. */static voidunlink_fsm_rel_usage(FSMRelation *fsmrel){	if (fsmrel->priorUsage != NULL)		fsmrel->priorUsage->nextUsage = fsmrel->nextUsage;	else		FreeSpaceMap->usageList = fsmrel->nextUsage;	if (fsmrel->nextUsage != NULL)		fsmrel->nextUsage->priorUsage = fsmrel->priorUsage;	else		FreeSpaceMap->usageListTail = fsmrel->priorUsage;	/*	 * We don't bother resetting fsmrel's links, since it's about to be	 * deleted or relinked at the head.	 */}/* * Link a FSMRelation into the storage-order list (always at the tail). */static voidlink_fsm_rel_storage(FSMRelation *fsmrel){	fsmrel->nextPhysical = NULL;	fsmrel->priorPhysical = FreeSpaceMap->lastRel;	if (FreeSpaceMap->lastRel != NULL)		FreeSpaceMap->lastRel->nextPhysical = fsmrel;	else		FreeSpaceMap->firstRel = fsmrel;	FreeSpaceMap->lastRel = fsmrel;}/* * Delink a FSMRelation from the storage-order list, if it's in it. */static voidunlink_fsm_rel_storage(FSMRelation *fsmrel){	if (fsmrel->priorPhysical != NULL || FreeSpaceMap->firstRel == fsmrel)	{		if (fsmrel->priorPhysical != NULL)			fsmrel->priorPhysical->nextPhysical = fsmrel->nextPhysical;		else			FreeSpaceMap->firstRel = fsmrel->nextPhysical;		if (fsmrel->nextPhysical != NULL)			fsmrel->nextPhysical->priorPhysical = fsmrel->priorPhysical;		else			FreeSpaceMap->lastRel = fsmrel->priorPhysical;	}	/* mark as not in list, since we may not put it back immediately */	fsmrel->nextPhysical = NULL;	fsmrel->priorPhysical = NULL;	/* Also mark it as having no storage */	fsmrel->firstChunk = -1;	fsmrel->storedPages = 0;}/* * Look to see if a page with at least the specified amount of space is * available in the given FSMRelation.	If so, return its page number, * and advance the nextPage counter so that the next inquiry will return * a different page if possible; also update the entry to show that the * requested space is not available anymore.  Return InvalidBlockNumber * if no success. */static BlockNumberfind_free_space(FSMRelation *fsmrel, Size spaceNeeded){	FSMPageData *info;	int			pagesToCheck,	/* outer loop counter */				pageIndex;		/* current page index */	if (fsmrel->isIndex)		elog(ERROR, "find_free_space called for an index relation");	info = (FSMPageData *)		(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);	pageIndex = fsmrel->nextPage;	/* Last operation may have left nextPage pointing past end */	if (pageIndex >= fsmrel->storedPages)		pageIndex = 0;	for (pagesToCheck = fsmrel->storedPages; pagesToCheck > 0; pagesToCheck--)	{		FSMPageData *page = info + pageIndex;		Size		spaceAvail = FSMPageGetSpace(page);		/* Check this page */		if (spaceAvail >= spaceNeeded)		{			/*			 * Found what we want --- adjust the entry, and update			 * nextPage.			 */			FSMPageSetSpace(page, spaceAvail - spaceNeeded);			fsmrel->nextPage = pageIndex + 1;			return FSMPageGetPageNum(page);		}		/* Advance pageIndex, wrapping around if needed */		if (++pageIndex >= fsmrel->storedPages)			pageIndex = 0;	}	return InvalidBlockNumber;	/* nothing found */}/* * As above, but for index case --- we only deal in whole pages. */static BlockNumberfind_index_free_space(FSMRelation *fsmrel){	IndexFSMPageData *info;	BlockNumber result;	/*	 * If isIndex isn't set, it could be that RecordIndexFreeSpace() has	 * never yet been called on this relation, and we're still looking at	 * the default setting from create_fsm_rel().  If so, just act as	 * though there's no space.	 */	if (!fsmrel->isIndex)	{		if (fsmrel->storedPages == 0)			return InvalidBlockNumber;		elog(ERROR, "find_index_free_space called for a non-index relation");	}	/*	 * For indexes, there's no need for the nextPage state variable; we	 * just remove and return the first available page.  (We could save	 * cycles here by returning the last page, but it seems better to	 * encourage re-use of lower-numbered pages.)	 */	if (fsmrel->storedPages <= 0)		return InvalidBlockNumber;		/* no pages available */	info = (IndexFSMPageData *)		(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);	result = IndexFSMPageGetPageNum(info);	fsmrel->storedPages--;	memmove(info, info + 1, fsmrel->storedPages * sizeof(IndexFSMPageData));	return result;}/* * fsm_record_free_space - guts of RecordFreeSpace operation (now only * provided as part of RecordAndGetPageWithFreeSpace). */static voidfsm_record_free_space(FSMRelation *fsmrel, BlockNumber page, Size spaceAvail){	int			pageIndex;	if (fsmrel->isIndex)		elog(ERROR, "fsm_record_free_space called for an index relation");	if (lookup_fsm_page_entry(fsmrel, page, &pageIndex))	{		/* Found an existing entry for page; update it */		FSMPageData *info;		info = (FSMPageData *)			(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);		info += pageIndex;		FSMPageSetSpace(info, spaceAvail);	}	else	{		/*		 * No existing entry; ignore the call.	We used to add the page to		 * the FSM --- but in practice, if the page hasn't got enough		 * space to satisfy the caller who's kicking it back to us, then		 * it's probably uninteresting to everyone else as well.		 */	}}/* * Look for an entry for a specific page (block number) in a FSMRelation. * Returns TRUE if a matching entry exists, else FALSE. * * The output argument *outPageIndex is set to indicate where the entry exists * (if TRUE result) or could be inserted (if FALSE result). */static boollookup_fsm_page_entry(FSMRelation *fsmrel, BlockNumber page,					  int *outPageIndex){	/* Check for empty relation */	if (fsmrel->storedPages <= 0)	{		*outPageIndex = 0;		return false;	}	/* Do binary search */	if (fsmrel->isIndex)	{		IndexFSMPageData *info;		int			low,					high;		info = (IndexFSMPageData *)			(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);		low = 0;		high = fsmrel->storedPages - 1;		while (low <= high)		{			int			middle;			BlockNumber probe;			middle = low + (high - low) / 2;			probe = IndexFSMPageGetPageNum(info + middle);			if (probe == page)			{				*outPageIndex = middle;				return true;			}			else if (probe < page)				low = middle + 1;			else				high = middle - 1;		}		*outPageIndex = low;		return false;	}	else	{		FSMPageData *info;		int			low,					high;		info = (FSMPageData *)			(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);		low = 0;		high = fsmrel->storedPages - 1;		while (low <= high)		{			int			middle;			BlockNumber probe;			middle = low + (high - low) / 2;			probe = FSMPageGetPageNum(info + middle);			if (probe == page)			{				*outPageIndex = middle;				return true;			}			else if (probe < page)				low = middle + 1;			else				high = middle - 1;		}		*outPageIndex = low;		return false;	}}/* * Re-pack the FSM storage arena, dropping data if necessary to meet the * current allocation target for each relation.  At conclusion, all available * space in the arena will be coalesced at the end. */static voidcompact_fsm_storage(void){	int			nextChunkIndex = 0;	bool		did_push = false;	FSMRelation *fsmrel;	for (fsmrel = FreeSpaceMap->firstRel;		 fsmrel != NULL;		 fsmrel = fsmrel->nextPhysical)	{		int			newAlloc;		int			newAllocPages;		int			newChunkIndex;		int			oldChunkIndex;		int			curChunks;		char	   *newLocation;		char	   *oldLocation;		/*		 * Calculate target allocation, make sure we don't overrun due to		 * roundoff error		 */		newAlloc = fsm_calc_target_allocation(fsm_calc_request(fsmrel));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -