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

📄 freespace.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
	/*	 * Note we don't record info about a relation unless there's already	 * an FSM entry for it, implying someone has done GetPageWithFreeSpace	 * 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;		FSMPageData *newLocation;		curAlloc = realloc_fsm_rel(fsmrel, nPages, false);		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)		{			int			i;			for (i = 0; i < nPages; i++)			{				BlockNumber page = pageSpaces[i].blkno;				Size		avail = pageSpaces[i].avail;				/* Check caller provides sorted data */				if (i > 0 && page <= pageSpaces[i - 1].blkno)					elog(ERROR, "free-space data is not in page order");				FSMPageSetPageNum(newLocation, page);				FSMPageSetSpace(newLocation, avail);				newLocation++;			}			fsmrel->storedPages = nPages;		}		else		{			pack_incoming_pages(newLocation, curAllocPages,								pageSpaces, nPages);			fsmrel->storedPages = curAllocPages;		}	}	LWLockRelease(FreeSpaceLock);}/* * GetFreeIndexPage - like GetPageWithFreeSpace, but for indexes */BlockNumberGetFreeIndexPage(RelFileNode *rel){	FSMRelation *fsmrel;	BlockNumber freepage;	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	/*	 * We always add a rel to the hashtable when it is inquired about.	 */	fsmrel = create_fsm_rel(rel);	freepage = find_index_free_space(fsmrel);	LWLockRelease(FreeSpaceLock);	return freepage;}/* * RecordIndexFreeSpace - like RecordRelationFreeSpace, but for indexes */voidRecordIndexFreeSpace(RelFileNode *rel,					 int nPages,					 BlockNumber *pages){	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, nPages, 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 lastPageCount 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. * * XXX when we implement tablespaces, target Oid will need to be tablespace * ID not database ID. */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.tblNode == 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;	int			numRels;	double		sumRequests;	double		needed;	LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);	/* Count total space used --- tedious, but seems useful */	for (fsmrel = FreeSpaceMap->firstRel;		 fsmrel != NULL;		 fsmrel = fsmrel->nextPhysical)		storedPages += fsmrel->storedPages;	/* Copy other stats before dropping lock */	numRels = FreeSpaceMap->numRels;	sumRequests = FreeSpaceMap->sumRequests;	LWLockRelease(FreeSpaceLock);	/* Convert stats to actual number of page slots needed */	needed = (sumRequests + numRels) * CHUNKPAGES;	ereport(elevel,			(errmsg("free space map: %d relations, %d pages stored; %.0f total pages needed",					numRels, storedPages, needed),			 errdetail("Allocated FSM size: %d relations + %d pages = %.0f kB shared memory.",					   MaxFSMRelations, MaxFSMPages,					   (double) FreeSpaceShmemSize() / 1024.0)));}/* * 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(void){	FILE	   *fp;	char		cachefilename[MAXPGPATH];	FsmCacheFileHeader header;	FSMRelation *fsmrel;	/* Try to create file */	snprintf(cachefilename, sizeof(cachefilename), "%s/%s",			 DataDir, FSM_CACHE_FILENAME);	unlink(cachefilename);		/* in case it exists w/wrong permissions */	fp = AllocateFile(cachefilename, PG_BINARY_W);	if (fp == NULL)	{		elog(LOG, "could not write \"%s\": %m", cachefilename);		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.lastPageCount = fsmrel->lastPageCount;		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);	FreeFile(fp);	return;write_failed:	elog(LOG, "could not write \"%s\": %m", cachefilename);	/* Clean up */	LWLockRelease(FreeSpaceLock);	FreeFile(fp);	/* Remove busted cache file */	unlink(cachefilename);}/* * 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;	char		cachefilename[MAXPGPATH];	FsmCacheFileHeader header;	int			relno;	/* Try to open file */	snprintf(cachefilename, sizeof(cachefilename), "%s/%s",			 DataDir, FSM_CACHE_FILENAME);	fp = AllocateFile(cachefilename, PG_BINARY_R);	if (fp == NULL)	{		if (errno != ENOENT)			elog(LOG, "could not read \"%s\": %m", cachefilename);		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\"", cachefilename);		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.lastPageCount < 0 ||			relheader.storedPages < 0)		{			elog(LOG, "bogus rel header in \"%s\"", cachefilename);			goto read_failed;		}		/* Make sure lastPageCount doesn't exceed current MaxFSMPages */		if (relheader.lastPageCount > MaxFSMPages)			relheader.lastPageCount = MaxFSMPages;		/* Read the per-page data */		nPages = relheader.storedPages;		if (relheader.isIndex)			len = nPages * sizeof(IndexFSMPageData);		else			len = nPages * sizeof(FSMPageData);		data = (char *) palloc(len + 1);		/* +1 to avoid palloc(0) */		if (fread(data, 1, len, fp) != len)		{			elog(LOG, "premature EOF in \"%s\"", cachefilename);			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.lastPageCount,								   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;

⌨️ 快捷键说明

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