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

📄 vacuum.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	if (use_own_xacts)	{		/* matches the StartTransaction in PostgresMain() */		CommitTransactionCommand();	}	/* Turn vacuum cost accounting on or off */	PG_TRY();	{		ListCell   *cur;		VacuumCostActive = (VacuumCostDelay > 0);		VacuumCostBalance = 0;		/*		 * Loop to process each selected relation.		 */		foreach(cur, relations)		{			Oid			relid = lfirst_oid(cur);			if (vacstmt->vacuum)			{				if (!vacuum_rel(relid, vacstmt, RELKIND_RELATION))					all_rels = false;	/* forget about updating dbstats */			}			if (vacstmt->analyze)			{				MemoryContext old_context = NULL;				/*				 * If using separate xacts, start one for analyze. Otherwise,				 * we can use the outer transaction, but we still need to call				 * analyze_rel in a memory context that will be cleaned up on				 * return (else we leak memory while processing multiple				 * tables).				 */				if (use_own_xacts)				{					StartTransactionCommand();					/* functions in indexes may want a snapshot set */					ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());				}				else					old_context = MemoryContextSwitchTo(anl_context);				/*				 * Tell the buffer replacement strategy that vacuum is causing				 * the IO				 */				StrategyHintVacuum(true);				analyze_rel(relid, vacstmt);				StrategyHintVacuum(false);				if (use_own_xacts)					CommitTransactionCommand();				else				{					MemoryContextSwitchTo(old_context);					MemoryContextResetAndDeleteChildren(anl_context);				}			}		}	}	PG_CATCH();	{		/* Make sure cost accounting is turned off after error */		VacuumCostActive = false;		PG_RE_THROW();	}	PG_END_TRY();	/* Turn off vacuum cost accounting */	VacuumCostActive = false;	/*	 * Finish up processing.	 */	if (use_own_xacts)	{		/* here, we are not in a transaction */		/*		 * This matches the CommitTransaction waiting for us in		 * PostgresMain().		 */		StartTransactionCommand();		/*		 * Re-establish the transaction snapshot.  This is wasted effort		 * when we are called as a normal utility command, because the		 * new transaction will be dropped immediately by PostgresMain();		 * but it's necessary if we are called from autovacuum because		 * autovacuum might continue on to do an ANALYZE-only call.		 */		ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());	}	if (vacstmt->vacuum)	{		/*		 * If it was a database-wide VACUUM, print FSM usage statistics (we		 * don't make you be superuser to see these).		 */		if (all_rels)			PrintFreeSpaceMapStatistics(elevel);		/*		 * If we completed a database-wide VACUUM without skipping any		 * relations, update the database's pg_database row with info about		 * the transaction IDs used, and try to truncate pg_clog.		 */		if (all_rels)		{			vac_update_dbstats(MyDatabaseId,							   initialOldestXmin, initialFreezeLimit);			vac_truncate_clog(initialOldestXmin, initialFreezeLimit);		}	}	/*	 * Clean up working storage --- note we must do this after	 * StartTransactionCommand, else we might be trying to delete the active	 * context!	 */	MemoryContextDelete(vac_context);	vac_context = NULL;	if (anl_context)		MemoryContextDelete(anl_context);}/* * Build a list of Oids for each relation to be processed * * The list is built in vac_context so that it will survive across our * per-relation transactions. */static List *get_rel_oids(List *relids, const RangeVar *vacrel, const char *stmttype){	List	   *oid_list = NIL;	MemoryContext oldcontext;	/* List supplied by VACUUM's caller? */	if (relids)		return relids;	if (vacrel)	{		/* Process a specific relation */		Oid			relid;		relid = RangeVarGetRelid(vacrel, false);		/* Make a relation list entry for this guy */		oldcontext = MemoryContextSwitchTo(vac_context);		oid_list = lappend_oid(oid_list, relid);		MemoryContextSwitchTo(oldcontext);	}	else	{		/* Process all plain relations listed in pg_class */		Relation	pgclass;		HeapScanDesc scan;		HeapTuple	tuple;		ScanKeyData key;		ScanKeyInit(&key,					Anum_pg_class_relkind,					BTEqualStrategyNumber, F_CHAREQ,					CharGetDatum(RELKIND_RELATION));		pgclass = heap_open(RelationRelationId, AccessShareLock);		scan = heap_beginscan(pgclass, SnapshotNow, 1, &key);		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)		{			/* Make a relation list entry for this guy */			oldcontext = MemoryContextSwitchTo(vac_context);			oid_list = lappend_oid(oid_list, HeapTupleGetOid(tuple));			MemoryContextSwitchTo(oldcontext);		}		heap_endscan(scan);		heap_close(pgclass, AccessShareLock);	}	return oid_list;}/* * vacuum_set_xid_limits() -- compute oldest-Xmin and freeze cutoff points */voidvacuum_set_xid_limits(VacuumStmt *vacstmt, bool sharedRel,					  TransactionId *oldestXmin,					  TransactionId *freezeLimit){	TransactionId limit;	*oldestXmin = GetOldestXmin(sharedRel);	Assert(TransactionIdIsNormal(*oldestXmin));	if (vacstmt->freeze)	{		/* FREEZE option: use oldest Xmin as freeze cutoff too */		limit = *oldestXmin;	}	else	{		/*		 * Normal case: freeze cutoff is well in the past, to wit, about		 * halfway to the wrap horizon		 */		limit = GetCurrentTransactionId() - (MaxTransactionId >> 2);	}	/*	 * Be careful not to generate a "permanent" XID	 */	if (!TransactionIdIsNormal(limit))		limit = FirstNormalTransactionId;	/*	 * Ensure sane relationship of limits	 */	if (TransactionIdFollows(limit, *oldestXmin))	{		ereport(WARNING,				(errmsg("oldest xmin is far in the past"),				 errhint("Close open transactions soon to avoid wraparound problems.")));		limit = *oldestXmin;	}	*freezeLimit = limit;}/* *	vac_update_relstats() -- update statistics for one relation * *		Update the whole-relation statistics that are kept in its pg_class *		row.  There are additional stats that will be updated if we are *		doing ANALYZE, but we always update these stats.  This routine works *		for both index and heap relation entries in pg_class. * *		We violate no-overwrite semantics here by storing new values for the *		statistics columns directly into the pg_class tuple that's already on *		the page.  The reason for this is that if we updated these tuples in *		the usual way, vacuuming pg_class itself wouldn't work very well --- *		by the time we got done with a vacuum cycle, most of the tuples in *		pg_class would've been obsoleted.  Of course, this only works for *		fixed-size never-null columns, but these are. * *		This routine is shared by full VACUUM, lazy VACUUM, and stand-alone *		ANALYZE. */voidvac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,					bool hasindex){	Relation	rd;	HeapTupleData rtup;	HeapTuple	ctup;	Form_pg_class pgcform;	Buffer		buffer;	/*	 * update number of tuples and number of pages in pg_class	 */	rd = heap_open(RelationRelationId, RowExclusiveLock);	ctup = SearchSysCache(RELOID,						  ObjectIdGetDatum(relid),						  0, 0, 0);	if (!HeapTupleIsValid(ctup))		elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",			 relid);	/* get the buffer cache tuple */	rtup.t_self = ctup->t_self;	ReleaseSysCache(ctup);	if (!heap_fetch(rd, SnapshotNow, &rtup, &buffer, false, NULL))		elog(ERROR, "pg_class entry for relid %u vanished during vacuuming",			 relid);	/* ensure no one else does this at the same time */	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);	/* overwrite the existing statistics in the tuple */	pgcform = (Form_pg_class) GETSTRUCT(&rtup);	pgcform->relpages = (int32) num_pages;	pgcform->reltuples = (float4) num_tuples;	pgcform->relhasindex = hasindex;	/*	 * If we have discovered that there are no indexes, then there's no	 * primary key either.	This could be done more thoroughly...	 */	if (!hasindex)		pgcform->relhaspkey = false;	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);	/*	 * Invalidate the tuple in the catcaches; this also arranges to flush the	 * relation's relcache entry.  (If we fail to commit for some reason, no	 * flush will occur, but no great harm is done since there are no	 * noncritical state updates here.)	 */	CacheInvalidateHeapTuple(rd, &rtup);	/* Write the buffer */	WriteBuffer(buffer);	heap_close(rd, RowExclusiveLock);}/* *	vac_update_dbstats() -- update statistics for one database * *		Update the whole-database statistics that are kept in its pg_database *		row, and the flat-file copy of pg_database. * *		We violate no-overwrite semantics here by storing new values for the *		statistics columns directly into the tuple that's already on the page. *		As with vac_update_relstats, this avoids leaving dead tuples behind *		after a VACUUM. * *		This routine is shared by full and lazy VACUUM.  Note that it is only *		applied after a database-wide VACUUM operation. */static voidvac_update_dbstats(Oid dbid,				   TransactionId vacuumXID,				   TransactionId frozenXID){	Relation	relation;	ScanKeyData entry[1];	HeapScanDesc scan;	HeapTuple	tuple;	Form_pg_database dbform;	relation = heap_open(DatabaseRelationId, RowExclusiveLock);	/* Must use a heap scan, since there's no syscache for pg_database */	ScanKeyInit(&entry[0],				ObjectIdAttributeNumber,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(dbid));	scan = heap_beginscan(relation, SnapshotNow, 1, entry);	tuple = heap_getnext(scan, ForwardScanDirection);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "could not find tuple for database %u", dbid);	/* ensure no one else does this at the same time */	LockBuffer(scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);	dbform = (Form_pg_database) GETSTRUCT(tuple);	/* overwrite the existing statistics in the tuple */	dbform->datvacuumxid = vacuumXID;	dbform->datfrozenxid = frozenXID;	LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);	/* invalidate the tuple in the cache and write the buffer */	CacheInvalidateHeapTuple(relation, tuple);	WriteNoReleaseBuffer(scan->rs_cbuf);	heap_endscan(scan);	heap_close(relation, RowExclusiveLock);	/* Mark the flat-file copy of pg_database for update at commit */	database_file_update_needed();}/* *	vac_truncate_clog() -- attempt to truncate the commit log * *		Scan pg_database to determine the system-wide oldest datvacuumxid, *		and use it to truncate the transaction commit log (pg_clog). *		Also update the XID wrap limit point maintained by varsup.c. * *		We also generate a warning if the system-wide oldest datfrozenxid *		seems to be in danger of wrapping around.  This is a long-in-advance *		warning; if we start getting uncomfortably close, GetNewTransactionId *		will generate more-annoying warnings, and ultimately refuse to issue *		any more new XIDs. * *		The passed XIDs are simply the ones I just wrote into my pg_database *		entry.	They're used to initialize the "min" calculations. * *		This routine is shared by full and lazy VACUUM.  Note that it is only *		applied after a database-wide VACUUM operation. */static voidvac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID){	TransactionId myXID = GetCurrentTransactionId();	Relation	relation;	HeapScanDesc scan;	HeapTuple	tuple;	int32		age;	NameData	oldest_datname;	bool		vacuumAlreadyWrapped = false;	bool		frozenAlreadyWrapped = false;	/* init oldest_datname to sync with my frozenXID */	namestrcpy(&oldest_datname, get_database_name(MyDatabaseId));	/*	 * Note: the "already wrapped" cases should now be impossible due to the

⌨️ 快捷键说明

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