diff options
Diffstat (limited to 'src/backend/utils/cache/inval.c')
-rw-r--r-- | src/backend/utils/cache/inval.c | 221 |
1 files changed, 110 insertions, 111 deletions
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c index 4249bd33765..8792ec40842 100644 --- a/src/backend/utils/cache/inval.c +++ b/src/backend/utils/cache/inval.c @@ -39,8 +39,8 @@ * * In short, we need to remember until xact end every insert or delete * of a tuple that might be in the system caches. Updates are treated as - * two events, delete + insert, for simplicity. (There are cases where - * it'd be possible to record just one event, but we don't currently try.) + * two events, delete + insert, for simplicity. (If the update doesn't + * change the tuple hash value, catcache.c optimizes this into one event.) * * We do not need to register EVERY tuple operation in this way, just those * on tuples in relations that have associated catcaches. We do, however, @@ -314,14 +314,12 @@ AppendInvalidationMessageList(InvalidationChunk **destHdr, */ static void AddCatcacheInvalidationMessage(InvalidationListHeader *hdr, - int id, uint32 hashValue, - ItemPointer tuplePtr, Oid dbId) + int id, uint32 hashValue, Oid dbId) { SharedInvalidationMessage msg; Assert(id < CHAR_MAX); msg.cc.id = (int8) id; - msg.cc.tuplePtr = *tuplePtr; msg.cc.dbId = dbId; msg.cc.hashValue = hashValue; AddInvalidationMessage(&hdr->cclist, &msg); @@ -416,11 +414,10 @@ ProcessInvalidationMessagesMulti(InvalidationListHeader *hdr, static void RegisterCatcacheInvalidation(int cacheId, uint32 hashValue, - ItemPointer tuplePtr, Oid dbId) { AddCatcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, - cacheId, hashValue, tuplePtr, dbId); + cacheId, hashValue, dbId); } /* @@ -476,11 +473,9 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg) { if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid) { - CatalogCacheIdInvalidate(msg->cc.id, - msg->cc.hashValue, - &msg->cc.tuplePtr); + CatalogCacheIdInvalidate(msg->cc.id, msg->cc.hashValue); - CallSyscacheCallbacks(msg->cc.id, &msg->cc.tuplePtr); + CallSyscacheCallbacks(msg->cc.id, msg->cc.hashValue); } } else if (msg->id == SHAREDINVALCATALOG_ID) @@ -555,7 +550,7 @@ InvalidateSystemCaches(void) { struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i; - (*ccitem->function) (ccitem->arg, ccitem->id, NULL); + (*ccitem->function) (ccitem->arg, ccitem->id, 0); } for (i = 0; i < relcache_callback_count; i++) @@ -566,98 +561,6 @@ InvalidateSystemCaches(void) } } -/* - * PrepareForTupleInvalidation - * Detect whether invalidation of this tuple implies invalidation - * of catalog/relation cache entries; if so, register inval events. - */ -static void -PrepareForTupleInvalidation(Relation relation, HeapTuple tuple) -{ - Oid tupleRelId; - Oid databaseId; - Oid relationId; - - /* Do nothing during bootstrap */ - 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, - RegisterCatcacheInvalidation); - - /* - * Now, is this tuple one of the primary definers of a relcache entry? - */ - tupleRelId = RelationGetRelid(relation); - - if (tupleRelId == RelationRelationId) - { - Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple); - - relationId = HeapTupleGetOid(tuple); - if (classtup->relisshared) - databaseId = InvalidOid; - else - databaseId = MyDatabaseId; - } - else if (tupleRelId == AttributeRelationId) - { - Form_pg_attribute atttup = (Form_pg_attribute) GETSTRUCT(tuple); - - relationId = atttup->attrelid; - - /* - * KLUGE ALERT: we always send the relcache event with MyDatabaseId, - * even if the rel in question is shared (which we can't easily tell). - * 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_attribute - * change anyway. It looks a bit ugly though. (In practice, shared - * relations can't have schema changes after bootstrap, so we should - * never come here for a shared rel anyway.) - */ - databaseId = MyDatabaseId; - } - else if (tupleRelId == IndexRelationId) - { - Form_pg_index indextup = (Form_pg_index) GETSTRUCT(tuple); - - /* - * When a pg_index row is updated, we should send out a relcache inval - * for the index relation. As above, we don't know the shared status - * of the index, but in practice it doesn't matter since indexes of - * shared catalogs can't have such updates. - */ - relationId = indextup->indexrelid; - databaseId = MyDatabaseId; - } - else - return; - - /* - * Yes. We need to register a relcache invalidation event. - */ - RegisterRelcacheInvalidation(databaseId, relationId); -} - /* ---------------------------------------------------------------- * public functions @@ -1056,11 +959,103 @@ CommandEndInvalidationMessages(void) * CacheInvalidateHeapTuple * Register the given tuple for invalidation at end of command * (ie, current command is creating or outdating this tuple). + * Also, detect whether a relcache invalidation is implied. + * + * For an insert or delete, tuple is the target tuple and newtuple is NULL. + * For an update, we are called just once, with tuple being the old tuple + * version and newtuple the new version. This allows avoidance of duplicate + * effort during an update. */ void -CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple) +CacheInvalidateHeapTuple(Relation relation, + HeapTuple tuple, + HeapTuple newtuple) { - PrepareForTupleInvalidation(relation, tuple); + Oid tupleRelId; + Oid databaseId; + Oid relationId; + + /* Do nothing during bootstrap */ + 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, newtuple, + RegisterCatcacheInvalidation); + + /* + * Now, is this tuple one of the primary definers of a relcache entry? + * + * Note we ignore newtuple here; we assume an update cannot move a tuple + * from being part of one relcache entry to being part of another. + */ + tupleRelId = RelationGetRelid(relation); + + if (tupleRelId == RelationRelationId) + { + Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple); + + relationId = HeapTupleGetOid(tuple); + if (classtup->relisshared) + databaseId = InvalidOid; + else + databaseId = MyDatabaseId; + } + else if (tupleRelId == AttributeRelationId) + { + Form_pg_attribute atttup = (Form_pg_attribute) GETSTRUCT(tuple); + + relationId = atttup->attrelid; + + /* + * KLUGE ALERT: we always send the relcache event with MyDatabaseId, + * even if the rel in question is shared (which we can't easily tell). + * 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_attribute + * change anyway. It looks a bit ugly though. (In practice, shared + * relations can't have schema changes after bootstrap, so we should + * never come here for a shared rel anyway.) + */ + databaseId = MyDatabaseId; + } + else if (tupleRelId == IndexRelationId) + { + Form_pg_index indextup = (Form_pg_index) GETSTRUCT(tuple); + + /* + * When a pg_index row is updated, we should send out a relcache inval + * for the index relation. As above, we don't know the shared status + * of the index, but in practice it doesn't matter since indexes of + * shared catalogs can't have such updates. + */ + relationId = indextup->indexrelid; + databaseId = MyDatabaseId; + } + else + return; + + /* + * Yes. We need to register a relcache invalidation event. + */ + RegisterRelcacheInvalidation(databaseId, relationId); } /* @@ -1094,7 +1089,7 @@ CacheInvalidateCatalog(Oid catalogId) * * 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.) + * entry by CacheInvalidateHeapTuple. (An example is dropping an index.) */ void CacheInvalidateRelcache(Relation relation) @@ -1216,10 +1211,14 @@ CacheInvalidateRelmap(Oid databaseId) * CacheRegisterSyscacheCallback * Register the specified function to be called for all future * invalidation events in the specified cache. The cache ID and the - * TID of the tuple being invalidated will be passed to the function. + * hash value of the tuple being invalidated will be passed to the + * function. * - * NOTE: NULL will be passed for the TID if a cache reset request is received. + * NOTE: Hash value zero will be passed if a cache reset request is received. * In this case the called routines should flush all cached state. + * Yes, there's a possibility of a false match to zero, but it doesn't seem + * worth troubling over, especially since most of the current callees just + * flush all cached state anyway. */ void CacheRegisterSyscacheCallback(int cacheid, @@ -1265,7 +1264,7 @@ CacheRegisterRelcacheCallback(RelcacheCallbackFunction func, * this module from knowing which catcache IDs correspond to which catalogs. */ void -CallSyscacheCallbacks(int cacheid, ItemPointer tuplePtr) +CallSyscacheCallbacks(int cacheid, uint32 hashvalue) { int i; @@ -1274,6 +1273,6 @@ CallSyscacheCallbacks(int cacheid, ItemPointer tuplePtr) struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i; if (ccitem->id == cacheid) - (*ccitem->function) (ccitem->arg, cacheid, tuplePtr); + (*ccitem->function) (ccitem->arg, cacheid, hashvalue); } } |