inval.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 736 行 · 第 1/2 页
C
736 行
* private support functions * ---------------------------------------------------------------- *//* * RegisterCatcacheInvalidation * * Register an invalidation event for a catcache tuple entry. */static voidRegisterCatcacheInvalidation(int cacheId, uint32 hashValue, ItemPointer tuplePtr, Oid dbId){ AddCatcacheInvalidationMessage(&CurrentCmdInvalidMsgs, cacheId, hashValue, tuplePtr, dbId);}/* * RegisterRelcacheInvalidation * * As above, but register a relcache invalidation event. */static voidRegisterRelcacheInvalidation(Oid dbId, Oid relId){ AddRelcacheInvalidationMessage(&CurrentCmdInvalidMsgs, dbId, relId); /* * If the relation being invalidated is one of those cached in the * relcache init file, mark that we need to zap that file at commit. */ if (RelationIdIsInInitFile(relId)) RelcacheInitFileInval = true;}/* * LocalExecuteInvalidationMessage * * Process a single invalidation message (which could be either type). * Only the local caches are flushed; this does not transmit the message * to other backends. */static voidLocalExecuteInvalidationMessage(SharedInvalidationMessage *msg){ int i; if (msg->id >= 0) { if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == 0) { CatalogCacheIdInvalidate(msg->cc.id, msg->cc.hashValue, &msg->cc.tuplePtr); for (i = 0; i < cache_callback_count; i++) { struct CACHECALLBACK *ccitem = cache_callback_list + i; if (ccitem->id == msg->cc.id) (*ccitem->function) (ccitem->arg, InvalidOid); } } } else if (msg->id == SHAREDINVALRELCACHE_ID) { if (msg->rc.dbId == MyDatabaseId || msg->rc.dbId == 0) { RelationIdInvalidateRelationCacheByRelationId(msg->rc.relId); for (i = 0; i < cache_callback_count; i++) { struct CACHECALLBACK *ccitem = cache_callback_list + i; if (ccitem->id == SHAREDINVALRELCACHE_ID) (*ccitem->function) (ccitem->arg, msg->rc.relId); } } } else elog(FATAL, "unrecognized SI message id: %d", msg->id);}/* * InvalidateSystemCaches * * This blows away all tuples in the system catalog caches and * all the cached relation descriptors (and closes their files too). * Relation descriptors that have positive refcounts are then rebuilt. * * We call this when we see a shared-inval-queue overflow signal, * since that tells us we've lost some shared-inval messages and hence * don't know what needs to be invalidated. */static voidInvalidateSystemCaches(void){ int i; ResetCatalogCaches(); RelationCacheInvalidate(); for (i = 0; i < cache_callback_count; i++) { struct CACHECALLBACK *ccitem = cache_callback_list + i; (*ccitem->function) (ccitem->arg, InvalidOid); }}/* * PrepareForTupleInvalidation * Detect whether invalidation of this tuple implies invalidation * of catalog/relation cache entries; if so, register inval events. */static voidPrepareForTupleInvalidation(Relation relation, HeapTuple tuple, void (*CacheIdRegisterFunc) (int, uint32, ItemPointer, Oid), void (*RelationIdRegisterFunc) (Oid, Oid)){ Oid tupleRelId; Oid relationId; if (IsBootstrapProcessingMode()) return; /* * We only need to worry about invalidation for tuples that are in * system relations; user-relation tuples are never in catcaches and * can't affect the relcache either. */ if (!IsSystemRelation(relation)) return; /* * TOAST tuples can likewise be ignored here. Note that TOAST tables * are considered system relations so they are not filtered by the * above test. */ if (IsToastRelation(relation)) return; /* * First let the catcache do its thing */ PrepareToInvalidateCacheTuple(relation, tuple, CacheIdRegisterFunc); /* * Now, is this tuple one of the primary definers of a relcache entry? */ tupleRelId = RelationGetRelid(relation); if (tupleRelId == RelOid_pg_class) relationId = HeapTupleGetOid(tuple); else if (tupleRelId == RelOid_pg_attribute) relationId = ((Form_pg_attribute) GETSTRUCT(tuple))->attrelid; else return; /* * Yes. We need to register a relcache invalidation event for the * relation identified by relationId. * * KLUGE ALERT: we always send the relcache event with MyDatabaseId, even * if the rel in question is shared. This essentially means that only * backends in this same database will react to the relcache flush * request. This is in fact appropriate, since only those backends * could see our pg_class or pg_attribute change anyway. It looks a * bit ugly though. */ (*RelationIdRegisterFunc) (MyDatabaseId, relationId);}/* ---------------------------------------------------------------- * public functions * ---------------------------------------------------------------- *//* * AcceptInvalidationMessages * Read and process invalidation messages from the shared invalidation * message queue. * * Note: * This should be called as the first step in processing a transaction. */voidAcceptInvalidationMessages(void){ ReceiveSharedInvalidMessages(LocalExecuteInvalidationMessage, InvalidateSystemCaches);}/* * AtEOXactInvalidationMessages * Process queued-up invalidation messages at end of transaction. * * If isCommit, we must send out the messages in our PriorCmdInvalidMsgs list * to the shared invalidation message queue. Note that these will be read * not only by other backends, but also by our own backend at the next * transaction start (via AcceptInvalidationMessages). This means that * we can skip immediate local processing of anything that's still in * CurrentCmdInvalidMsgs, and just send that list out too. * * If not isCommit, we are aborting, and must locally process the messages * in PriorCmdInvalidMsgs. No messages need be sent to other backends, * since they'll not have seen our changed tuples anyway. We can forget * about CurrentCmdInvalidMsgs too, since those changes haven't touched * the caches yet. * * In any case, reset the various lists to empty. We need not physically * free memory here, since TopTransactionContext is about to be emptied * anyway. * * Note: * This should be called as the last step in processing a transaction. */voidAtEOXactInvalidationMessages(bool isCommit){ if (isCommit) { /* * Relcache init file invalidation requires processing both before * and after we send the SI messages. However, we need not do * anything unless we committed. */ if (RelcacheInitFileInval) RelationCacheInitFileInvalidate(true); AppendInvalidationMessages(&PriorCmdInvalidMsgs, &CurrentCmdInvalidMsgs); ProcessInvalidationMessages(&PriorCmdInvalidMsgs, SendSharedInvalidMessage); if (RelcacheInitFileInval) RelationCacheInitFileInvalidate(false); } else { ProcessInvalidationMessages(&PriorCmdInvalidMsgs, LocalExecuteInvalidationMessage); } RelcacheInitFileInval = false; DiscardInvalidationMessages(&PriorCmdInvalidMsgs, false); DiscardInvalidationMessages(&CurrentCmdInvalidMsgs, false);}/* * CommandEndInvalidationMessages * Process queued-up invalidation messages at end of one command * in a transaction. * * Here, we send no messages to the shared queue, since we don't know yet if * we will commit. We do need to locally process the CurrentCmdInvalidMsgs * list, so as to flush our caches of any entries we have outdated in the * current command. We then move the current-cmd list over to become part * of the prior-cmds list. * * The isCommit = false case is not currently used, but may someday be * needed to support rollback to a savepoint within a transaction. * * Note: * This should be called during CommandCounterIncrement(), * after we have advanced the command ID. */voidCommandEndInvalidationMessages(bool isCommit){ if (isCommit) { ProcessInvalidationMessages(&CurrentCmdInvalidMsgs, LocalExecuteInvalidationMessage); AppendInvalidationMessages(&PriorCmdInvalidMsgs, &CurrentCmdInvalidMsgs); } else { /* XXX what needs to be done here? */ }}/* * CacheInvalidateHeapTuple * Register the given tuple for invalidation at end of command * (ie, current command is outdating this tuple). */voidCacheInvalidateHeapTuple(Relation relation, HeapTuple tuple){ PrepareForTupleInvalidation(relation, tuple, RegisterCatcacheInvalidation, RegisterRelcacheInvalidation);}/* * CacheInvalidateRelcache * Register invalidation of the specified relation's relcache entry * at end of command. * * This is used in places that need to force relcache rebuild but aren't * changing any of the tuples recognized as contributors to the relcache * entry by PrepareForTupleInvalidation. (An example is dropping an index.) */voidCacheInvalidateRelcache(Oid relationId){ /* See KLUGE ALERT in PrepareForTupleInvalidation */ RegisterRelcacheInvalidation(MyDatabaseId, relationId);}/* * CacheRegisterSyscacheCallback * Register the specified function to be called for all future * invalidation events in the specified cache. * * NOTE: currently, the OID argument to the callback routine is not * provided for syscache callbacks; the routine doesn't really get any * useful info as to exactly what changed. It should treat every call * as a "cache flush" request. */voidCacheRegisterSyscacheCallback(int cacheid, CacheCallbackFunction func, Datum arg){ if (cache_callback_count >= MAX_CACHE_CALLBACKS) elog(FATAL, "out of cache_callback_list slots"); cache_callback_list[cache_callback_count].id = cacheid; cache_callback_list[cache_callback_count].function = func; cache_callback_list[cache_callback_count].arg = arg; ++cache_callback_count;}/* * CacheRegisterRelcacheCallback * Register the specified function to be called for all future * relcache invalidation events. The OID of the relation being * invalidated will be passed to the function. * * NOTE: InvalidOid will be passed if a cache reset request is received. * In this case the called routines should flush all cached state. */voidCacheRegisterRelcacheCallback(CacheCallbackFunction func, Datum arg){ if (cache_callback_count >= MAX_CACHE_CALLBACKS) elog(FATAL, "out of cache_callback_list slots"); cache_callback_list[cache_callback_count].id = SHAREDINVALRELCACHE_ID; cache_callback_list[cache_callback_count].function = func; cache_callback_list[cache_callback_count].arg = arg; ++cache_callback_count;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?