📄 inval.c
字号:
/*------------------------------------------------------------------------- * * inval.c * POSTGRES cache invalidation dispatcher code. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.23.2.1 1999/08/02 05:25:00 scrappy Exp $ * * Note - this code is real crufty... * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/catalog.h"#include "catalog/catname.h"#include "catalog/heap.h"#include "miscadmin.h"#include "storage/sinval.h"#include "utils/catcache.h"#include "utils/inval.h"#include "utils/relcache.h"static InvalidationEntry InvalidationEntryAllocate(uint16 size);static void LocalInvalidInvalidate(LocalInvalid invalid, void (*function) ());static LocalInvalid LocalInvalidRegister(LocalInvalid invalid, InvalidationEntry entry);static void getmyrelids(void);/* ---------------- * private invalidation structures * ---------------- */typedef struct CatalogInvalidationData{ Index cacheId; Index hashIndex; ItemPointerData pointerData;} CatalogInvalidationData;typedef struct RelationInvalidationData{ Oid relationId; Oid objectId;} RelationInvalidationData;typedef union AnyInvalidation{ CatalogInvalidationData catalog; RelationInvalidationData relation;} AnyInvalidation;typedef struct InvalidationMessageData{ char kind; AnyInvalidation any;} InvalidationMessageData;typedef InvalidationMessageData *InvalidationMessage;/* ---------------- * variables and macros * ---------------- */static LocalInvalid Invalid = EmptyLocalInvalid; /* XXX global */Oid MyRelationRelationId = InvalidOid;Oid MyAttributeRelationId = InvalidOid;Oid MyAMRelationId = InvalidOid;Oid MyAMOPRelationId = InvalidOid;#define ValidateHacks() \ if (!OidIsValid(MyRelationRelationId)) getmyrelids()/* ---------------------------------------------------------------- * "local" invalidation support functions * ---------------------------------------------------------------- *//* -------------------------------- * InvalidationEntryAllocate * Allocates an invalidation entry. * -------------------------------- */static InvalidationEntryInvalidationEntryAllocate(uint16 size){ InvalidationEntryData *entryDataP; entryDataP = (InvalidationEntryData *) malloc(sizeof(char *) + size); /* XXX alignment */ entryDataP->nextP = NULL; return (Pointer) &entryDataP->userData;}/* -------------------------------- * LocalInvalidRegister * Returns a new local cache invalidation state containing a new entry. * -------------------------------- */static LocalInvalidLocalInvalidRegister(LocalInvalid invalid, InvalidationEntry entry){ Assert(PointerIsValid(entry)); ((InvalidationUserData *) entry)->dataP[-1] = (InvalidationUserData *) invalid; return entry;}/* -------------------------------- * LocalInvalidInvalidate * Processes, then frees all entries in a local cache * invalidation state. * -------------------------------- */static voidLocalInvalidInvalidate(LocalInvalid invalid, void (*function) ()){ InvalidationEntryData *entryDataP; while (PointerIsValid(invalid)) { entryDataP = (InvalidationEntryData *) &((InvalidationUserData *) invalid)->dataP[-1]; if (PointerIsValid(function)) (*function) ((Pointer) &entryDataP->userData); invalid = (Pointer) entryDataP->nextP; /* help catch errors */ entryDataP->nextP = (InvalidationUserData *) NULL; free((Pointer) entryDataP); }}/* ---------------------------------------------------------------- * private support functions * ---------------------------------------------------------------- *//* -------------------------------- * CacheIdRegisterLocalInvalid * -------------------------------- */#ifdef INVALIDDEBUG#define CacheIdRegisterLocalInvalid_DEBUG1 \elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \ cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \ ItemPointerGetOffsetNumber(pointer))#else#define CacheIdRegisterLocalInvalid_DEBUG1#endif /* INVALIDDEBUG */static voidCacheIdRegisterLocalInvalid(Index cacheId, Index hashIndex, ItemPointer pointer){ InvalidationMessage message; /* ---------------- * debugging stuff * ---------------- */ CacheIdRegisterLocalInvalid_DEBUG1; /* ---------------- * create a message describing the system catalog tuple * we wish to invalidate. * ---------------- */ message = (InvalidationMessage) InvalidationEntryAllocate(sizeof(InvalidationMessageData)); message->kind = 'c'; message->any.catalog.cacheId = cacheId; message->any.catalog.hashIndex = hashIndex; ItemPointerCopy(pointer, &message->any.catalog.pointerData); /* ---------------- * Note: Invalid is a global variable * ---------------- */ Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry) message);}/* -------------------------------- * RelationIdRegisterLocalInvalid * -------------------------------- */static voidRelationIdRegisterLocalInvalid(Oid relationId, Oid objectId){ InvalidationMessage message; /* ---------------- * debugging stuff * ---------------- */#ifdef INVALIDDEBUG elog(DEBUG, "RelationRegisterLocalInvalid(%u, %u)", relationId, objectId);#endif /* defined(INVALIDDEBUG) */ /* ---------------- * create a message describing the relation descriptor * we wish to invalidate. * ---------------- */ message = (InvalidationMessage) InvalidationEntryAllocate(sizeof(InvalidationMessageData)); message->kind = 'r'; message->any.relation.relationId = relationId; message->any.relation.objectId = objectId; /* ---------------- * Note: Invalid is a global variable * ---------------- */ Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry) message);}/* -------------------------------- * getmyrelids * -------------------------------- */static voidgetmyrelids(){ MyRelationRelationId = RelnameFindRelid(RelationRelationName); Assert(RelationRelationName != InvalidOid); MyAttributeRelationId = RelnameFindRelid(AttributeRelationName); Assert(AttributeRelationName != InvalidOid); MyAMRelationId = RelnameFindRelid(AccessMethodRelationName); Assert(MyAMRelationId != InvalidOid); MyAMOPRelationId = RelnameFindRelid(AccessMethodOperatorRelationName); Assert(MyAMOPRelationId != InvalidOid);}/* -------------------------------- * CacheIdInvalidate * * This routine can invalidate a tuple in a system catalog cache * or a cached relation descriptor. You pay your money and you * take your chances... * -------------------------------- */#ifdef INVALIDDEBUG#define CacheIdInvalidate_DEBUG1 \elog(DEBUG, "CacheIdInvalidate(%d, %d, 0x%x[%d])", cacheId, hashIndex,\ pointer, ItemPointerIsValid(pointer))#else#define CacheIdInvalidate_DEBUG1#endif /* defined(INVALIDDEBUG) */static voidCacheIdInvalidate(Index cacheId, Index hashIndex, ItemPointer pointer){ /* ---------------- * assume that if the item pointer is valid, then we are * invalidating an item in the specified system catalog cache. * ---------------- */ if (ItemPointerIsValid(pointer)) { CatalogCacheIdInvalidate(cacheId, hashIndex, pointer); return; } CacheIdInvalidate_DEBUG1; ValidateHacks(); /* XXX */ /* ---------------- * if the cacheId is the oid of any of the tuples in the * following system relations, then assume we are invalidating * a relation descriptor * ---------------- */ if (cacheId == MyRelationRelationId) { RelationIdInvalidateRelationCacheByRelationId(hashIndex); return; } if (cacheId == MyAttributeRelationId) { RelationIdInvalidateRelationCacheByRelationId(hashIndex); return; } if (cacheId == MyAMRelationId) { RelationIdInvalidateRelationCacheByAccessMethodId(hashIndex); return; } if (cacheId == MyAMOPRelationId) { RelationIdInvalidateRelationCacheByAccessMethodId(InvalidOid); return; } /* ---------------- * Yow! the caller asked us to invalidate something else. * ---------------- */ elog(FATAL, "CacheIdInvalidate: cacheId=%d relation id?", cacheId);}/* -------------------------------- * ResetSystemCaches * * this blows away all tuples in the system catalog caches and * all the cached relation descriptors (and closes the files too). * -------------------------------- */static voidResetSystemCaches(){ ResetSystemCache(); RelationCacheInvalidate(false);}/* -------------------------------- * InvalidationMessageRegisterSharedInvalid * -------------------------------- */#ifdef INVALIDDEBUG#define InvalidationMessageRegisterSharedInvalid_DEBUG1 \elog(DEBUG,\ "InvalidationMessageRegisterSharedInvalid(c, %d, %d, [%d, %d])",\ message->any.catalog.cacheId,\ message->any.catalog.hashIndex,\ ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\ ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))#define InvalidationMessageRegisterSharedInvalid_DEBUG2 \ elog(DEBUG, \ "InvalidationMessageRegisterSharedInvalid(r, %u, %u)", \ message->any.relation.relationId, \ message->any.relation.objectId)#else#define InvalidationMessageRegisterSharedInvalid_DEBUG1#define InvalidationMessageRegisterSharedInvalid_DEBUG2#endif /* INVALIDDEBUG */static voidInvalidationMessageRegisterSharedInvalid(InvalidationMessage message){ Assert(PointerIsValid(message)); switch (message->kind) { case 'c': /* cached system catalog tuple */ InvalidationMessageRegisterSharedInvalid_DEBUG1; RegisterSharedInvalid(message->any.catalog.cacheId, message->any.catalog.hashIndex, &message->any.catalog.pointerData); break; case 'r': /* cached relation descriptor */ InvalidationMessageRegisterSharedInvalid_DEBUG2; RegisterSharedInvalid(message->any.relation.relationId, message->any.relation.objectId, (ItemPointer) NULL); break; default: elog(FATAL, "InvalidationMessageRegisterSharedInvalid: `%c' kind", message->kind); }}/* -------------------------------- * InvalidationMessageCacheInvalidate * -------------------------------- */#ifdef INVALIDDEBUG#define InvalidationMessageCacheInvalidate_DEBUG1 \elog(DEBUG, "InvalidationMessageCacheInvalidate(c, %d, %d, [%d, %d])",\ message->any.catalog.cacheId,\ message->any.catalog.hashIndex,\ ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\ ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))#define InvalidationMessageCacheInvalidate_DEBUG2 \ elog(DEBUG, "InvalidationMessageCacheInvalidate(r, %u, %u)", \ message->any.relation.relationId, \ message->any.relation.objectId)#else#define InvalidationMessageCacheInvalidate_DEBUG1#define InvalidationMessageCacheInvalidate_DEBUG2#endif /* defined(INVALIDDEBUG) */static voidInvalidationMessageCacheInvalidate(InvalidationMessage message){ Assert(PointerIsValid(message)); switch (message->kind) { case 'c': /* cached system catalog tuple */ InvalidationMessageCacheInvalidate_DEBUG1; CatalogCacheIdInvalidate(message->any.catalog.cacheId, message->any.catalog.hashIndex, &message->any.catalog.pointerData); break; case 'r': /* cached relation descriptor */ InvalidationMessageCacheInvalidate_DEBUG2; /* XXX ignore this--is this correct ??? */ break; default: elog(FATAL, "InvalidationMessageCacheInvalidate: `%c' kind", message->kind); }}/* -------------------------------- * RelationInvalidateRelationCache * -------------------------------- */static voidRelationInvalidateRelationCache(Relation relation, HeapTuple tuple, void (*function) ()){ Oid relationId; Oid objectId = (Oid) 0; /* ---------------- * get the relation object id * ---------------- */ ValidateHacks(); /* XXX */ relationId = RelationGetRelid(relation); /* ---------------- * * ---------------- */ if (relationId == MyRelationRelationId) objectId = tuple->t_data->t_oid; else if (relationId == MyAttributeRelationId) objectId = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid; else if (relationId == MyAMRelationId) objectId = tuple->t_data->t_oid; else if (relationId == MyAMOPRelationId) { ; /* objectId is unused */ } else return; /* ---------------- * can't handle immediate relation descriptor invalidation * ---------------- */ Assert(PointerIsValid(function)); (*function) (relationId, objectId);}/* * InitLocalInvalidateData * * Setup this before anything could ever get invalid! * Called by InitPostgres(); */voidInitLocalInvalidateData(){ ValidateHacks();}/* * DiscardInvalid * Causes the invalidated cache state to be discarded. * * Note: * This should be called as the first step in processing a transaction. * This should be called while waiting for a query from the front end * when other backends are active. */voidDiscardInvalid(){ /* ---------------- * debugging stuff * ---------------- */#ifdef INVALIDDEBUG elog(DEBUG, "DiscardInvalid called");#endif /* defined(INVALIDDEBUG) */ InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);}/* * RegisterInvalid * Causes registration of invalidated state with other backends iff true. * * Note: * This should be called as the last step in processing a transaction. */voidRegisterInvalid(bool send){ /* ---------------- * debugging stuff * ---------------- */#ifdef INVALIDDEBUG elog(DEBUG, "RegisterInvalid(%d) called", send);#endif /* defined(INVALIDDEBUG) */ /* ---------------- * Note: Invalid is a global variable * ---------------- */ if (send) LocalInvalidInvalidate(Invalid, InvalidationMessageRegisterSharedInvalid); else LocalInvalidInvalidate(Invalid, InvalidationMessageCacheInvalidate); Invalid = EmptyLocalInvalid;}/* * RelationIdInvalidateHeapTuple * Causes the given tuple in a relation to be invalidated. * * Note: * Assumes object id is valid. * Assumes tuple is valid. */#ifdef INVALIDDEBUG#define RelationInvalidateHeapTuple_DEBUG1 \elog(DEBUG, "RelationInvalidateHeapTuple(%s, [%d,%d])", \ RelationGetRelationName(relation), \ ItemPointerGetBlockNumber(&tuple->t_ctid), \ ItemPointerGetOffsetNumber(&tuple->t_ctid))#else#define RelationInvalidateHeapTuple_DEBUG1#endif /* defined(INVALIDDEBUG) */voidRelationInvalidateHeapTuple(Relation relation, HeapTuple tuple){ /* ---------------- * sanity checks * ---------------- */ Assert(RelationIsValid(relation)); Assert(HeapTupleIsValid(tuple)); if (IsBootstrapProcessingMode()) return; /* ---------------- * this only works for system relations now * ---------------- */ if (!IsSystemRelationName(RelationGetForm(relation)->relname.data)) return; /* ---------------- * debugging stuff * ---------------- */ RelationInvalidateHeapTuple_DEBUG1; RelationInvalidateCatalogCacheTuple(relation, tuple, CacheIdRegisterLocalInvalid); RelationInvalidateRelationCache(relation, tuple, RelationIdRegisterLocalInvalid);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -