relcache.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,282 行 · 第 1/5 页

C
2,282
字号
/*------------------------------------------------------------------------- * * relcache.c *	  POSTGRES relation descriptor cache code * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.190 2003/09/25 06:58:05 petere Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES *		RelationCacheInitialize			- initialize relcache *		RelationCacheInitializePhase2	- finish initializing relcache *		RelationIdGetRelation			- get a reldesc by relation id *		RelationSysNameGetRelation		- get a reldesc by system rel name *		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 <errno.h>#include <sys/file.h>#include <fcntl.h>#include <unistd.h>#include "access/genam.h"#include "access/heapam.h"#include "access/istrat.h"#include "catalog/catalog.h"#include "catalog/catname.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_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 "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/relcache.h"#include "utils/syscache.h"/* * name of relcache init file, used to speed up backend startup */#define RELCACHE_INIT_FILENAME	"pg_internal.init"/* *		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};/* *		Hash tables that index the relation cache * *		Relations are looked up two ways, by OID and by name, *		thus there are two hash tables for referencing them. * *		The OID index covers all relcache entries.	The name index *		covers *only* system relations (only those in PG_CATALOG_NAMESPACE). */static HTAB *RelationIdCache;static HTAB *RelationSysNameCache;/* * Bufmgr uses RelFileNode for lookup. Actually, I would like to do * not pass Relation to bufmgr & beyond at all and keep some cache * in smgr, but no time to do it right way now.		-- vadim 10/22/2000 */static HTAB *RelationNodeCache;/* * 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;/* *		RelationBuildDescInfo exists so code can be shared *		between RelationIdGetRelation() and RelationSysNameGetRelation() */typedef struct RelationBuildDescInfo{	int			infotype;		/* lookup by id or by name */#define INFO_RELID 1#define INFO_RELNAME 2	union	{		Oid			info_id;	/* relation object id */		char	   *info_name;	/* system relation name */	}			i;} RelationBuildDescInfo;typedef struct relidcacheent{	Oid			reloid;	Relation	reldesc;} RelIdCacheEnt;typedef struct relnamecacheent{	NameData	relname;	Relation	reldesc;} RelNameCacheEnt;typedef struct relnodecacheent{	RelFileNode relnode;	Relation	reldesc;} RelNodeCacheEnt;/* *		macros to manipulate the lookup hashtables */#define RelationCacheInsert(RELATION)	\do { \	RelIdCacheEnt *idhentry; RelNodeCacheEnt *nodentry; bool found; \	idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \										   (void *) &(RELATION->rd_id), \										   HASH_ENTER, \										   &found); \	if (idhentry == NULL) \		ereport(ERROR, \				(errcode(ERRCODE_OUT_OF_MEMORY), \				 errmsg("out of memory"))); \	/* used to give notice if found -- now just keep quiet */ \	idhentry->reldesc = RELATION; \	nodentry = (RelNodeCacheEnt*)hash_search(RelationNodeCache, \										   (void *) &(RELATION->rd_node), \										   HASH_ENTER, \										   &found); \	if (nodentry == NULL) \		ereport(ERROR, \				(errcode(ERRCODE_OUT_OF_MEMORY), \				 errmsg("out of memory"))); \	/* used to give notice if found -- now just keep quiet */ \	nodentry->reldesc = RELATION; \	if (IsSystemNamespace(RelationGetNamespace(RELATION))) \	{ \		char *relname = RelationGetRelationName(RELATION); \		RelNameCacheEnt *namehentry; \		namehentry = (RelNameCacheEnt*)hash_search(RelationSysNameCache, \												   relname, \												   HASH_ENTER, \												   &found); \		if (namehentry == NULL) \			ereport(ERROR, \					(errcode(ERRCODE_OUT_OF_MEMORY), \					 errmsg("out of memory"))); \		/* used to give notice if found -- now just keep quiet */ \		namehentry->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 RelationSysNameCacheLookup(NAME, RELATION) \do { \	RelNameCacheEnt *hentry; \	hentry = (RelNameCacheEnt*)hash_search(RelationSysNameCache, \										   (void *) (NAME), HASH_FIND,NULL); \	if (hentry) \		RELATION = hentry->reldesc; \	else \		RELATION = NULL; \} while(0)#define RelationNodeCacheLookup(NODE, RELATION) \do { \	RelNodeCacheEnt *hentry; \	hentry = (RelNodeCacheEnt*)hash_search(RelationNodeCache, \										   (void *)&(NODE), HASH_FIND,NULL); \	if (hentry) \		RELATION = hentry->reldesc; \	else \		RELATION = NULL; \} while(0)#define RelationCacheDelete(RELATION) \do { \	RelIdCacheEnt *idhentry; RelNodeCacheEnt *nodentry; \	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"); \	nodentry = (RelNodeCacheEnt*)hash_search(RelationNodeCache, \										   (void *)&(RELATION->rd_node), \										   HASH_REMOVE, NULL); \	if (nodentry == NULL) \		elog(WARNING, "trying to delete a rd_node reldesc that does not exist"); \	if (IsSystemNamespace(RelationGetNamespace(RELATION))) \	{ \		char *relname = RelationGetRelationName(RELATION); \		RelNameCacheEnt *namehentry; \		namehentry = (RelNameCacheEnt*)hash_search(RelationSysNameCache, \												   relname, \												   HASH_REMOVE, NULL); \		if (namehentry == NULL) \			elog(WARNING, "trying to delete a relname reldesc that does not exist"); \	} \} while(0)/* * Special cache for opclass-related information */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 *operatorProcs;	/* strategy operators' procs */	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 Relation RelationSysNameCacheGetRelation(const char *relationName);static bool load_relcache_init_file(void);static void write_relcache_init_file(void);static void formrdesc(const char *relationName, int natts,		  FormData_pg_attribute *att);static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo, bool indexOK);static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,					   Relation relation);static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,				  Relation oldrelation);static void AttrDefaultFetch(Relation relation);static void CheckConstraintFetch(Relation relation);static List *insert_ordered_oid(List *list, Oid datum);static void IndexSupportInitialize(Form_pg_index iform,					   IndexStrategy indexStrategy,					   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 either a relation name or a relation id *		as specified in buildinfo. * *		NB: the returned tuple has been copied into palloc'd storage *		and must eventually be freed with heap_freetuple. */static HeapTupleScanPgRelation(RelationBuildDescInfo buildinfo, bool indexOK){	HeapTuple	pg_class_tuple;	Relation	pg_class_desc;	const char *indexRelname;	SysScanDesc pg_class_scan;	ScanKeyData key[2];	int			nkeys;	/*	 * form a scan key	 */	switch (buildinfo.infotype)	{		case INFO_RELID:			ScanKeyEntryInitialize(&key[0], 0,								   ObjectIdAttributeNumber,								   F_OIDEQ,								   ObjectIdGetDatum(buildinfo.i.info_id));			nkeys = 1;			indexRelname = ClassOidIndex;			break;		case INFO_RELNAME:			ScanKeyEntryInitialize(&key[0], 0,								   Anum_pg_class_relname,								   F_NAMEEQ,								   NameGetDatum(buildinfo.i.info_name));			ScanKeyEntryInitialize(&key[1], 0,								   Anum_pg_class_relnamespace,								   F_OIDEQ,								 ObjectIdGetDatum(PG_CATALOG_NAMESPACE));			nkeys = 2;			indexRelname = ClassNameNspIndex;			break;		default:			elog(ERROR, "unrecognized buildinfo type: %d",				 buildinfo.infotype);			return NULL;		/* keep compiler quiet */	}	/*	 * 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_openr(RelationRelationName, AccessShareLock);	pg_class_scan = systable_beginscan(pg_class_desc, indexRelname,									   indexOK && criticalRelcachesBuilt,									   SnapshotNow,									   nkeys, 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((char *) relation, 0, sizeof(RelationData));	relation->rd_targblock = InvalidBlockNumber;	/* make sure relation is marked as having no open file yet */	relation->rd_fd = -1;	/*	 * 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((char *) relationForm, (char *) 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. */

⌨️ 快捷键说明

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