relcache.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,134 行 · 第 1/5 页

C
2,134
字号
/*------------------------------------------------------------------------- * * relcache.c *	  POSTGRES relation descriptor cache code * * Portions Copyright (c) 1996-2008, 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.266.2.4 2008/08/10 19:02:46 tgl Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES *		RelationCacheInitialize			- initialize relcache (to empty) *		RelationCacheInitializePhase2	- finish initializing relcache *		RelationIdGetRelation			- get a reldesc by relation id *		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 "access/reloptions.h"#include "access/xact.h"#include "catalog/catalog.h"#include "catalog/index.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_authid.h"#include "catalog/pg_constraint.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 "optimizer/var.h"#include "rewrite/rewriteDefine.h"#include "storage/fd.h"#include "storage/smgr.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/inval.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		0x573264	/* 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 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 operators and support procs get cached, ie, those with * lefttype = righttype = opcintype. */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			opcfamily;		/* OID of opclass's family */	Oid			opcintype;		/* OID of opclass's declared input type */	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 RelationReloadIndexInfo(Relation relation);static void RelationFlushRelation(Relation relation);static bool load_relcache_init_file(void);static void write_relcache_init_file(void);static void write_item(const void *data, Size len, FILE *fp);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 RelationParseRelOptions(Relation relation, HeapTuple tuple);static void RelationBuildTupleDesc(Relation relation);static Relation RelationBuildDesc(Oid targetRelId, Relation oldrelation);static void RelationInitPhysicalAddr(Relation relation);static TupleDesc GetPgClassDescriptor(void);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,					   Oid *opFamily,					   Oid *opcInType,					   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.  The caller must hold at least *		AccessShareLock on the target relid to prevent concurrent-update *		scenarios --- else our SnapshotNow scan might fail to find any *		version that it thinks is live. * *		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. The	 * variable-length fields (relacl, reloptions) are NOT stored in the	 * relcache --- there'd be little point in it, since we don't copy the	 * tuple's nulls bitmap and hence wouldn't know if the values are valid.	 * Bottom line is that relacl *cannot* be retrieved from the relcache. Get	 * it from the syscache if you need it.  The same goes for the original	 * form of reloptions (however, we do store the parsed form of reloptions	 * in rd_options).	 */	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);	/* which we mark as a reference-counted tupdesc */	relation->rd_att->tdrefcount = 1;	MemoryContextSwitchTo(oldcxt);	return relation;}/* * RelationParseRelOptions *		Convert pg_class.reloptions into pre-parsed rd_options * * tuple is the real pg_class tuple (not rd_rel!) for relation * * Note: rd_rel and (if an index) rd_am must be valid already */static voidRelationParseRelOptions(Relation relation, HeapTuple tuple){	Datum		datum;	bool		isnull;	bytea	   *options;	relation->rd_options = NULL;	/* Fall out if relkind should not have options */	switch (relation->rd_rel->relkind)	{		case RELKIND_RELATION:		case RELKIND_TOASTVALUE:		case RELKIND_UNCATALOGED:		case RELKIND_INDEX:			break;		default:			return;	}	/*	 * Fetch reloptions from tuple; have to use a hardwired descriptor because	 * we might not have any other for pg_class yet (consider executing this	 * code for pg_class itself)	 */	datum = fastgetattr(tuple,						Anum_pg_class_reloptions,						GetPgClassDescriptor(),						&isnull);	if (isnull)		return;	/* Parse into appropriate format; don't error out here */	switch (relation->rd_rel->relkind)	{		case RELKIND_RELATION:		case RELKIND_TOASTVALUE:		case RELKIND_UNCATALOGED:			options = heap_reloptions(relation->rd_rel->relkind, datum,									  false);			break;		case RELKIND_INDEX:			options = index_reloptions(relation->rd_am->amoptions, datum,									   false);			break;		default:			Assert(false);		/* can't get here */			options = NULL;		/* keep compiler quiet */			break;	}	/* Copy parsed data into CacheMemoryContext */	if (options)	{		relation->rd_options = MemoryContextAlloc(CacheMemoryContext,												  VARSIZE(options));		memcpy(relation->rd_options, options, VARSIZE(options));	}}/* *		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... */

⌨️ 快捷键说明

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