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

📄 relcache.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * relcache.c *	  POSTGRES relation descriptor cache code * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.230.2.3 2006/01/19 20:28:48 tgl Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES *		RelationCacheInitialize			- initialize relcache *		RelationCacheInitializePhase2	- finish initializing relcache *		RelationIdGetRelation			- get a reldesc by relation id *		RelationIdCacheGetRelation		- get a cached reldesc by relid *		RelationClose					- close an open relation * * NOTES *		The following code contains many undocumented hacks.  Please be *		careful.... */#include "postgres.h"#include <sys/file.h>#include <fcntl.h>#include <unistd.h>#include "access/genam.h"#include "access/heapam.h"#include "catalog/catalog.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_amop.h"#include "catalog/pg_amproc.h"#include "catalog/pg_attrdef.h"#include "catalog/pg_attribute.h"#include "catalog/pg_authid.h"#include "catalog/pg_constraint.h"#include "catalog/pg_index.h"#include "catalog/pg_namespace.h"#include "catalog/pg_opclass.h"#include "catalog/pg_proc.h"#include "catalog/pg_rewrite.h"#include "catalog/pg_type.h"#include "commands/trigger.h"#include "miscadmin.h"#include "optimizer/clauses.h"#include "optimizer/planmain.h"#include "optimizer/prep.h"#include "storage/fd.h"#include "storage/smgr.h"#include "utils/builtins.h"#include "utils/catcache.h"#include "utils/fmgroids.h"#include "utils/inval.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/relcache.h"#include "utils/resowner.h"#include "utils/syscache.h"#include "utils/typcache.h"/* * name of relcache init file, used to speed up backend startup */#define RELCACHE_INIT_FILENAME	"pg_internal.init"#define RELCACHE_INIT_FILEMAGIC		0x573262	/* version ID value *//* *		hardcoded tuple descriptors.  see include/catalog/pg_attribute.h */static FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};static FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute};static FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc};static FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type};static FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index};/* *		Hash tables that index the relation cache * *		We used to index the cache by both name and OID, but now there *		is only an index by OID. */typedef struct relidcacheent{	Oid			reloid;	Relation	reldesc;} RelIdCacheEnt;static HTAB *RelationIdCache;/* * This flag is false until we have prepared the critical relcache entries * that are needed to do indexscans on the tables read by relcache building. */bool		criticalRelcachesBuilt = false;/* * This flag is set if we discover that we need to write a new relcache * cache file at the end of startup. */static bool needNewCacheFile = false;/* * This counter counts relcache inval events received since backend startup * (but only for rels that are actually in cache).	Presently, we use it only * to detect whether data about to be written by write_relcache_init_file() * might already be obsolete. */static long relcacheInvalsReceived = 0L;/* * This list remembers the OIDs of the relations cached in the relcache * init file. */static List *initFileRelationIds = NIL;/* * This flag lets us optimize away work in AtEO(Sub)Xact_RelationCache(). */static bool need_eoxact_work = false;/* *		macros to manipulate the lookup hashtables */#define RelationCacheInsert(RELATION)	\do { \	RelIdCacheEnt *idhentry; bool found; \	idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \										   (void *) &(RELATION->rd_id), \										   HASH_ENTER, \										   &found); \	/* used to give notice if found -- now just keep quiet */ \	idhentry->reldesc = RELATION; \} while(0)#define RelationIdCacheLookup(ID, RELATION) \do { \	RelIdCacheEnt *hentry; \	hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \										 (void *) &(ID), HASH_FIND,NULL); \	if (hentry) \		RELATION = hentry->reldesc; \	else \		RELATION = NULL; \} while(0)#define RelationCacheDelete(RELATION) \do { \	RelIdCacheEnt *idhentry; \	idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \										   (void *) &(RELATION->rd_id), \										   HASH_REMOVE, NULL); \	if (idhentry == NULL) \		elog(WARNING, "trying to delete a rd_id reldesc that does not exist"); \} while(0)/* * Special cache for opclass-related information * * Note: only default-subtype operators and support procs get cached */typedef struct opclasscacheent{	Oid			opclassoid;		/* lookup key: OID of opclass */	bool		valid;			/* set TRUE after successful fill-in */	StrategyNumber numStrats;	/* max # of strategies (from pg_am) */	StrategyNumber numSupport;	/* max # of support procs (from pg_am) */	Oid		   *operatorOids;	/* strategy operators' OIDs */	RegProcedure *supportProcs; /* support procs */} OpClassCacheEnt;static HTAB *OpClassCache = NULL;/* non-export function prototypes */static void RelationClearRelation(Relation relation, bool rebuild);static void RelationReloadClassinfo(Relation relation);static void RelationFlushRelation(Relation relation);static bool load_relcache_init_file(void);static void write_relcache_init_file(void);static void formrdesc(const char *relationName, Oid relationReltype,		  bool hasoids, int natts, FormData_pg_attribute *att);static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK);static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);static void RelationBuildTupleDesc(Relation relation);static Relation RelationBuildDesc(Oid targetRelId, Relation oldrelation);static void RelationInitPhysicalAddr(Relation relation);static TupleDesc GetPgIndexDescriptor(void);static void AttrDefaultFetch(Relation relation);static void CheckConstraintFetch(Relation relation);static List *insert_ordered_oid(List *list, Oid datum);static void IndexSupportInitialize(oidvector *indclass,					   Oid *indexOperator,					   RegProcedure *indexSupport,					   StrategyNumber maxStrategyNumber,					   StrategyNumber maxSupportNumber,					   AttrNumber maxAttributeNumber);static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,				  StrategyNumber numStrats,				  StrategyNumber numSupport);/* *		ScanPgRelation * *		this is used by RelationBuildDesc to find a pg_class *		tuple matching targetRelId. * *		NB: the returned tuple has been copied into palloc'd storage *		and must eventually be freed with heap_freetuple. */static HeapTupleScanPgRelation(Oid targetRelId, bool indexOK){	HeapTuple	pg_class_tuple;	Relation	pg_class_desc;	SysScanDesc pg_class_scan;	ScanKeyData key[1];	/*	 * form a scan key	 */	ScanKeyInit(&key[0],				ObjectIdAttributeNumber,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(targetRelId));	/*	 * Open pg_class and fetch a tuple.  Force heap scan if we haven't yet	 * built the critical relcache entries (this includes initdb and startup	 * without a pg_internal.init file).  The caller can also force a heap	 * scan by setting indexOK == false.	 */	pg_class_desc = heap_open(RelationRelationId, AccessShareLock);	pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId,									   indexOK && criticalRelcachesBuilt,									   SnapshotNow,									   1, key);	pg_class_tuple = systable_getnext(pg_class_scan);	/*	 * Must copy tuple before releasing buffer.	 */	if (HeapTupleIsValid(pg_class_tuple))		pg_class_tuple = heap_copytuple(pg_class_tuple);	/* all done */	systable_endscan(pg_class_scan);	heap_close(pg_class_desc, AccessShareLock);	return pg_class_tuple;}/* *		AllocateRelationDesc * *		This is used to allocate memory for a new relation descriptor *		and initialize the rd_rel field. * *		If 'relation' is NULL, allocate a new RelationData object. *		If not, reuse the given object (that path is taken only when *		we have to rebuild a relcache entry during RelationClearRelation). */static RelationAllocateRelationDesc(Relation relation, Form_pg_class relp){	MemoryContext oldcxt;	Form_pg_class relationForm;	/* Relcache entries must live in CacheMemoryContext */	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);	/*	 * allocate space for new relation descriptor, if needed	 */	if (relation == NULL)		relation = (Relation) palloc(sizeof(RelationData));	/*	 * clear all fields of reldesc	 */	MemSet(relation, 0, sizeof(RelationData));	relation->rd_targblock = InvalidBlockNumber;	/* make sure relation is marked as having no open file yet */	relation->rd_smgr = NULL;	/*	 * Copy the relation tuple form	 *	 * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE.	 * relacl is NOT stored in the relcache --- there'd be little point in it,	 * since we don't copy the tuple's nullvalues bitmap and hence wouldn't	 * know if the value is valid ... bottom line is that relacl *cannot* be	 * retrieved from the relcache.  Get it from the syscache if you need it.	 */	relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);	memcpy(relationForm, relp, CLASS_TUPLE_SIZE);	/* initialize relation tuple form */	relation->rd_rel = relationForm;	/* and allocate attribute tuple form storage */	relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,											   relationForm->relhasoids);	MemoryContextSwitchTo(oldcxt);	return relation;}/* *		RelationBuildTupleDesc * *		Form the relation's tuple descriptor from information in *		the pg_attribute, pg_attrdef & pg_constraint system catalogs. */static voidRelationBuildTupleDesc(Relation relation){	HeapTuple	pg_attribute_tuple;	Relation	pg_attribute_desc;	SysScanDesc pg_attribute_scan;	ScanKeyData skey[2];	int			need;	TupleConstr *constr;	AttrDefault *attrdef = NULL;	int			ndef = 0;	/* copy some fields from pg_class row to rd_att */	relation->rd_att->tdtypeid = relation->rd_rel->reltype;	relation->rd_att->tdtypmod = -1;	/* unnecessary, but... */	relation->rd_att->tdhasoid = relation->rd_rel->relhasoids;	constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext,												sizeof(TupleConstr));	constr->has_not_null = false;	/*	 * Form a scan key that selects only user attributes (attnum > 0).	 * (Eliminating system attribute rows at the index level is lots faster	 * than fetching them.)	 */	ScanKeyInit(&skey[0],				Anum_pg_attribute_attrelid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(RelationGetRelid(relation)));	ScanKeyInit(&skey[1],				Anum_pg_attribute_attnum,				BTGreaterStrategyNumber, F_INT2GT,				Int16GetDatum(0));	/*	 * Open pg_attribute and begin a scan.	Force heap scan if we haven't yet	 * built the critical relcache entries (this includes initdb and startup	 * without a pg_internal.init file).	 */	pg_attribute_desc = heap_open(AttributeRelationId, AccessShareLock);	pg_attribute_scan = systable_beginscan(pg_attribute_desc,										   AttributeRelidNumIndexId,										   criticalRelcachesBuilt,										   SnapshotNow,										   2, skey);	/*	 * add attribute data to relation->rd_att	 */	need = relation->rd_rel->relnatts;	while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))	{		Form_pg_attribute attp;		attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);		if (attp->attnum <= 0 ||			attp->attnum > relation->rd_rel->relnatts)			elog(ERROR, "invalid attribute number %d for %s",				 attp->attnum, RelationGetRelationName(relation));		memcpy(relation->rd_att->attrs[attp->attnum - 1],			   attp,			   ATTRIBUTE_TUPLE_SIZE);		/* Update constraint/default info */		if (attp->attnotnull)			constr->has_not_null = true;		if (attp->atthasdef)		{			if (attrdef == NULL)				attrdef = (AttrDefault *)					MemoryContextAllocZero(CacheMemoryContext,										   relation->rd_rel->relnatts *										   sizeof(AttrDefault));			attrdef[ndef].adnum = attp->attnum;			attrdef[ndef].adbin = NULL;			ndef++;		}		need--;		if (need == 0)			break;	}	/*	 * end the scan and close the attribute relation	 */	systable_endscan(pg_attribute_scan);	heap_close(pg_attribute_desc, AccessShareLock);	if (need != 0)		elog(ERROR, "catalog is missing %d attribute(s) for relid %u",			 need, RelationGetRelid(relation));	/*	 * The attcacheoff values we read from pg_attribute should all be -1	 * ("unknown").  Verify this if assert checking is on.	They will be	 * computed when and if needed during tuple access.	 */#ifdef USE_ASSERT_CHECKING	{		int			i;		for (i = 0; i < relation->rd_rel->relnatts; i++)			Assert(relation->rd_att->attrs[i]->attcacheoff == -1);	}#endif	/*	 * However, we can easily set the attcacheoff value for the first	 * attribute: it must be zero.	This eliminates the need for special cases	 * for attnum=1 that used to exist in fastgetattr() and index_getattr().	 */	if (relation->rd_rel->relnatts > 0)

⌨️ 快捷键说明

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