/* * CacheInvalidateRelcacheAll * Register invalidation of the whole relcache at the end of command. * * This is used by alter publication as changes in publications may affect * large number of tables. */ void CacheInvalidateRelcacheAll(void) { PrepareInvalidationState(); RegisterRelcacheInvalidation(InvalidOid, InvalidOid); }
/* * CacheInvalidateRelcacheByRelid * As above, but relation is identified by passing its OID. * This is the least efficient of the three options; use one of * the above routines if you have a Relation or pg_class tuple. */ void CacheInvalidateRelcacheByRelid(Oid relid) { HeapTuple tup; PrepareInvalidationState(); tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for relation %u", relid); CacheInvalidateRelcacheByTuple(tup); ReleaseSysCache(tup); }
/* * CacheInvalidateCatalog * Register invalidation of the whole content of a system catalog. * * This is normally used in VACUUM FULL/CLUSTER, where we haven't so much * changed any tuples as moved them around. Some uses of catcache entries * expect their TIDs to be correct, so we have to blow away the entries. * * Note: we expect caller to verify that the rel actually is a system * catalog. If it isn't, no great harm is done, just a wasted sinval message. */ void CacheInvalidateCatalog(Oid catalogId) { Oid databaseId; PrepareInvalidationState(); if (IsSharedRelation(catalogId)) databaseId = InvalidOid; else databaseId = MyDatabaseId; RegisterCatalogInvalidation(databaseId, catalogId); }
/* * CacheInvalidateRelcacheByTuple * As above, but relation is identified by passing its pg_class tuple. */ void CacheInvalidateRelcacheByTuple(HeapTuple classTuple) { Form_pg_class classtup = (Form_pg_class) GETSTRUCT(classTuple); Oid databaseId; Oid relationId; PrepareInvalidationState(); relationId = HeapTupleGetOid(classTuple); if (classtup->relisshared) databaseId = InvalidOid; else databaseId = MyDatabaseId; RegisterRelcacheInvalidation(databaseId, relationId); }
/* * 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 CacheInvalidateHeapTuple. (An example is dropping an index.) */ void CacheInvalidateRelcache(Relation relation) { Oid databaseId; Oid relationId; PrepareInvalidationState(); relationId = RelationGetRelid(relation); if (relation->rd_rel->relisshared) databaseId = InvalidOid; else databaseId = MyDatabaseId; RegisterRelcacheInvalidation(databaseId, relationId); }
/* * 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, HeapTuple newtuple) { 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 * catalogs; user-relation tuples are never in catcaches and can't affect * the relcache either. */ if (!IsCatalogRelation(relation)) return; /* * IsCatalogRelation() will return true for TOAST tables of system * catalogs, but we don't care about those, either. */ if (IsToastRelation(relation)) return; /* * If we're not prepared to queue invalidation messages for this * subtransaction level, get ready now. */ PrepareInvalidationState(); /* * First let the catcache do its thing */ tupleRelId = RelationGetRelid(relation); if (RelationInvalidatesSnapshotsOnly(tupleRelId)) { databaseId = IsSharedRelation(tupleRelId) ? InvalidOid : MyDatabaseId; RegisterSnapshotInvalidation(databaseId, tupleRelId); } else 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. */ 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); }