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

📄 freespace.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 4 页
字号:
	FSMRelation *fsmrel;	/* Limit nPages to something sane */	if (nPages < 0)		nPages = 0;	else if (nPages > MaxFSMPages)		nPages = MaxFSMPages;	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	/*	 * Note we don't record info about a relation unless there's already an	 * FSM entry for it, implying someone has done GetFreeIndexPage for it.	 * Inactive rels thus will not clutter the map simply by being vacuumed.	 */	fsmrel = lookup_fsm_rel(rel);	if (fsmrel)	{		int			curAlloc;		int			curAllocPages;		int			i;		IndexFSMPageData *newLocation;		curAlloc = realloc_fsm_rel(fsmrel, interestingPages, true);		curAllocPages = curAlloc * INDEXCHUNKPAGES;		/*		 * If the data fits in our current allocation, just copy it; otherwise		 * must compress.  But compression is easy: we merely forget extra		 * pages.		 */		newLocation = (IndexFSMPageData *)			(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);		if (nPages > curAllocPages)			nPages = curAllocPages;		for (i = 0; i < nPages; i++)		{			BlockNumber page = pages[i];			/* Check caller provides sorted data */			if (i > 0 && page <= pages[i - 1])				elog(ERROR, "free-space data is not in page order");			IndexFSMPageSetPageNum(newLocation, page);			newLocation++;		}		fsmrel->storedPages = nPages;	}	LWLockRelease(FreeSpaceLock);}/* * FreeSpaceMapTruncateRel - adjust for truncation of a relation. * * We need to delete any stored data past the new relation length, so that * we don't bogusly return removed block numbers. */voidFreeSpaceMapTruncateRel(RelFileNode *rel, BlockNumber nblocks){	FSMRelation *fsmrel;	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	fsmrel = lookup_fsm_rel(rel);	if (fsmrel)	{		int			pageIndex;		/* Use lookup to locate first entry >= nblocks */		(void) lookup_fsm_page_entry(fsmrel, nblocks, &pageIndex);		/* Delete all such entries */		fsmrel->storedPages = pageIndex;		/* XXX should we adjust rel's interestingPages and sumRequests? */	}	LWLockRelease(FreeSpaceLock);}/* * FreeSpaceMapForgetRel - forget all about a relation. * * This is called when a relation is deleted.  Although we could just let * the rel age out of the map, it's better to reclaim and reuse the space * sooner. */voidFreeSpaceMapForgetRel(RelFileNode *rel){	FSMRelation *fsmrel;	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	fsmrel = lookup_fsm_rel(rel);	if (fsmrel)		delete_fsm_rel(fsmrel);	LWLockRelease(FreeSpaceLock);}/* * FreeSpaceMapForgetDatabase - forget all relations of a database. * * This is called during DROP DATABASE.  As above, might as well reclaim * map space sooner instead of later. */voidFreeSpaceMapForgetDatabase(Oid dbid){	FSMRelation *fsmrel,			   *nextrel;	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = nextrel)	{		nextrel = fsmrel->nextUsage;	/* in case we delete it */		if (fsmrel->key.dbNode == dbid)			delete_fsm_rel(fsmrel);	}	LWLockRelease(FreeSpaceLock);}/* * PrintFreeSpaceMapStatistics - print statistics about FSM contents * * The info is sent to ereport() with the specified message level.	This is * intended for use during VACUUM. */voidPrintFreeSpaceMapStatistics(int elevel){	FSMRelation *fsmrel;	int			storedPages = 0;	double		sumRequests = 0;	int			numRels;	double		needed;	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	/*	 * Count total space actually used, as well as the unclamped request total	 */	for (fsmrel = FreeSpaceMap->firstRel;		 fsmrel != NULL;		 fsmrel = fsmrel->nextPhysical)	{		storedPages += fsmrel->storedPages;		sumRequests += fsm_calc_request_unclamped(fsmrel);	}	/* Copy other stats before dropping lock */	numRels = FreeSpaceMap->numRels;	LWLockRelease(FreeSpaceLock);	/* Convert stats to actual number of page slots needed */	needed = (sumRequests + numRels) * CHUNKPAGES;	ereport(elevel,			(errmsg("free space map contains %d pages in %d relations",					storedPages, numRels),	errdetail("A total of %.0f page slots are in use (including overhead).\n"			  "%.0f page slots are required to track all free space.\n"		  "Current limits are:  %d page slots, %d relations, using %.0f kB.",			  Min(needed, MaxFSMPages),			  needed,			  MaxFSMPages, MaxFSMRelations,			  (double) FreeSpaceShmemSize() / 1024.0)));	CheckFreeSpaceMapStatistics(NOTICE, numRels, needed);	/* Print to server logs too because is deals with a config variable. */	CheckFreeSpaceMapStatistics(LOG, numRels, needed);}static voidCheckFreeSpaceMapStatistics(int elevel, int numRels, double needed){	if (numRels == MaxFSMRelations)		ereport(elevel,				(errmsg("max_fsm_relations(%d) equals the number of relations checked",						MaxFSMRelations),				 errhint("You have at least %d relations.  "						 "Consider increasing the configuration parameter \"max_fsm_relations\".",						 numRels)));	else if (needed > MaxFSMPages)		ereport(elevel,				(errmsg("number of page slots needed (%.0f) exceeds max_fsm_pages (%d)",						needed, MaxFSMPages),				 errhint("Consider increasing the configuration parameter \"max_fsm_pages\" "						 "to a value over %.0f.", needed)));}/* * DumpFreeSpaceMap - dump contents of FSM into a disk file for later reload * * This is expected to be called during database shutdown, after updates to * the FSM have stopped.  We lock the FreeSpaceLock but that's purely pro * forma --- if anyone else is still accessing FSM, there's a problem. */voidDumpFreeSpaceMap(int code, Datum arg){	FILE	   *fp;	FsmCacheFileHeader header;	FSMRelation *fsmrel;	/* Try to create file */	unlink(FSM_CACHE_FILENAME); /* in case it exists w/wrong permissions */	fp = AllocateFile(FSM_CACHE_FILENAME, PG_BINARY_W);	if (fp == NULL)	{		elog(LOG, "could not write \"%s\": %m", FSM_CACHE_FILENAME);		return;	}	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	/* Write file header */	MemSet(&header, 0, sizeof(header));	strcpy(header.label, FSM_CACHE_LABEL);	header.endian = FSM_CACHE_ENDIAN;	header.version = FSM_CACHE_VERSION;	header.numRels = FreeSpaceMap->numRels;	if (fwrite(&header, 1, sizeof(header), fp) != sizeof(header))		goto write_failed;	/* For each relation, in order from least to most recently used... */	for (fsmrel = FreeSpaceMap->usageListTail;		 fsmrel != NULL;		 fsmrel = fsmrel->priorUsage)	{		FsmCacheRelHeader relheader;		int			nPages;		/* Write relation header */		MemSet(&relheader, 0, sizeof(relheader));		relheader.key = fsmrel->key;		relheader.isIndex = fsmrel->isIndex;		relheader.avgRequest = fsmrel->avgRequest;		relheader.interestingPages = fsmrel->interestingPages;		relheader.storedPages = fsmrel->storedPages;		if (fwrite(&relheader, 1, sizeof(relheader), fp) != sizeof(relheader))			goto write_failed;		/* Write the per-page data directly from the arena */		nPages = fsmrel->storedPages;		if (nPages > 0)		{			Size		len;			char	   *data;			if (fsmrel->isIndex)				len = nPages * sizeof(IndexFSMPageData);			else				len = nPages * sizeof(FSMPageData);			data = (char *)				(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);			if (fwrite(data, 1, len, fp) != len)				goto write_failed;		}	}	/* Clean up */	LWLockRelease(FreeSpaceLock);	if (FreeFile(fp))	{		elog(LOG, "could not write \"%s\": %m", FSM_CACHE_FILENAME);		/* Remove busted cache file */		unlink(FSM_CACHE_FILENAME);	}	return;write_failed:	elog(LOG, "could not write \"%s\": %m", FSM_CACHE_FILENAME);	/* Clean up */	LWLockRelease(FreeSpaceLock);	FreeFile(fp);	/* Remove busted cache file */	unlink(FSM_CACHE_FILENAME);}/* * LoadFreeSpaceMap - load contents of FSM from a disk file * * This is expected to be called during database startup, before any FSM * updates begin.  We lock the FreeSpaceLock but that's purely pro * forma --- if anyone else is accessing FSM yet, there's a problem. * * Notes: no complaint is issued if no cache file is found.  If the file is * found, it is deleted after reading.	Thus, if we crash without a clean * shutdown, the next cycle of life starts with no FSM data.  To do otherwise, * we'd need to do significantly more validation in this routine, because of * the likelihood that what is in the dump file would be out-of-date, eg * there might be entries for deleted or truncated rels. */voidLoadFreeSpaceMap(void){	FILE	   *fp;	FsmCacheFileHeader header;	int			relno;	/* Try to open file */	fp = AllocateFile(FSM_CACHE_FILENAME, PG_BINARY_R);	if (fp == NULL)	{		if (errno != ENOENT)			elog(LOG, "could not read \"%s\": %m", FSM_CACHE_FILENAME);		return;	}	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	/* Read and verify file header */	if (fread(&header, 1, sizeof(header), fp) != sizeof(header) ||		strcmp(header.label, FSM_CACHE_LABEL) != 0 ||		header.endian != FSM_CACHE_ENDIAN ||		header.version != FSM_CACHE_VERSION ||		header.numRels < 0)	{		elog(LOG, "bogus file header in \"%s\"", FSM_CACHE_FILENAME);		goto read_failed;	}	/* For each relation, in order from least to most recently used... */	for (relno = 0; relno < header.numRels; relno++)	{		FsmCacheRelHeader relheader;		Size		len;		char	   *data;		FSMRelation *fsmrel;		int			nPages;		int			curAlloc;		int			curAllocPages;		/* Read and verify relation header, as best we can */		if (fread(&relheader, 1, sizeof(relheader), fp) != sizeof(relheader) ||			(relheader.isIndex != false && relheader.isIndex != true) ||			relheader.avgRequest >= BLCKSZ ||			relheader.storedPages < 0)		{			elog(LOG, "bogus rel header in \"%s\"", FSM_CACHE_FILENAME);			goto read_failed;		}		/* Read the per-page data */		nPages = relheader.storedPages;		if (relheader.isIndex)			len = nPages * sizeof(IndexFSMPageData);		else			len = nPages * sizeof(FSMPageData);		data = (char *) palloc(len);		if (fread(data, 1, len, fp) != len)		{			elog(LOG, "premature EOF in \"%s\"", FSM_CACHE_FILENAME);			pfree(data);			goto read_failed;		}		/*		 * Okay, create the FSM entry and insert data into it.	Since the rels		 * were stored in reverse usage order, at the end of the loop they		 * will be correctly usage-ordered in memory; and if MaxFSMRelations		 * is less than it used to be, we will correctly drop the least		 * recently used ones.		 */		fsmrel = create_fsm_rel(&relheader.key);		fsmrel->avgRequest = relheader.avgRequest;		curAlloc = realloc_fsm_rel(fsmrel, relheader.interestingPages,								   relheader.isIndex);		if (relheader.isIndex)		{			IndexFSMPageData *newLocation;			curAllocPages = curAlloc * INDEXCHUNKPAGES;			/*			 * If the data fits in our current allocation, just copy it;			 * otherwise must compress.  But compression is easy: we merely			 * forget extra pages.			 */			newLocation = (IndexFSMPageData *)				(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);			if (nPages > curAllocPages)				nPages = curAllocPages;			memcpy(newLocation, data, nPages * sizeof(IndexFSMPageData));			fsmrel->storedPages = nPages;		}		else		{			FSMPageData *newLocation;			curAllocPages = curAlloc * CHUNKPAGES;			/*			 * If the data fits in our current allocation, just copy it;			 * otherwise must compress.			 */			newLocation = (FSMPageData *)				(FreeSpaceMap->arena + fsmrel->firstChunk * CHUNKBYTES);			if (nPages <= curAllocPages)			{				memcpy(newLocation, data, nPages * sizeof(FSMPageData));				fsmrel->storedPages = nPages;			}			else			{				pack_existing_pages(newLocation, curAllocPages,									(FSMPageData *) data, nPages);				fsmrel->storedPages = curAllocPages;			}		}		pfree(data);	}read_failed:	/* Clean up */	LWLockRelease(FreeSpaceLock);	FreeFile(fp);	/* Remove cache file before it can become stale; see notes above */	unlink(FSM_CACHE_FILENAME);}/* * 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(FreeSpaceMapRelHash,										 (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(FreeSpaceMapRelHash,										 (void *) rel,										 HASH_ENTER,										 &found);

⌨️ 快捷键说明

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