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 + -
显示快捷键?