Rename and document some invalidation routines to make it clearer that

they don't themselves flush any cache entries, only add to to-do lists
that will be processed later.
This commit is contained in:
Tom Lane 2001-01-05 22:54:37 +00:00
parent 2fb6cc9045
commit 81d08fcffe
3 changed files with 106 additions and 50 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.73 2000/11/24 04:16:12 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.74 2001/01/05 22:54:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1047,17 +1047,36 @@ ReleaseCatCache(HeapTuple tuple)
} }
/* -------------------------------- /* --------------------------------
* RelationInvalidateCatalogCacheTuple() * PrepareToInvalidateCacheTuple()
* *
* Invalidate a tuple from a specific relation. This call determines the * This is part of a rather subtle chain of events, so pay attention:
* cache in question and calls CatalogCacheIdInvalidate(). It is -ok- *
* if the relation cannot be found, it simply means this backend has yet * When a tuple is updated or deleted, it cannot be flushed from the
* to open it. * catcaches immediately, for reasons explained at the top of inval.c.
* Instead we have to add entry(s) for the tuple to a list of pending tuple
* invalidations that will be done at the end of the command or transaction.
*
* The lists of tuples that need to be flushed are kept by inval.c. This
* routine is a helper routine for inval.c. Given a tuple belonging to
* the specified relation, find all catcaches it could be in, compute the
* correct hashindex for each such catcache, and call the specified function
* to record the cache id, hashindex, and tuple ItemPointer in inval.c's
* lists. CatalogCacheIdInvalidate will be called later, if appropriate,
* using the recorded information.
*
* Note that it is irrelevant whether the given tuple is actually loaded
* into the catcache at the moment. Even if it's not there now, it might
* be by the end of the command, so we have to be prepared to flush it.
*
* Also note that it's not an error if there are no catcaches for the
* specified relation. inval.c doesn't know exactly which rels have
* catcaches --- it will call this routine for any tuple that's in a
* system relation.
* -------------------------------- * --------------------------------
*/ */
void void
RelationInvalidateCatalogCacheTuple(Relation relation, PrepareToInvalidateCacheTuple(Relation relation,
HeapTuple tuple, HeapTuple tuple,
void (*function) (int, Index, ItemPointer)) void (*function) (int, Index, ItemPointer))
{ {
CatCache *ccp; CatCache *ccp;
@ -1069,13 +1088,13 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
Assert(RelationIsValid(relation)); Assert(RelationIsValid(relation));
Assert(HeapTupleIsValid(tuple)); Assert(HeapTupleIsValid(tuple));
Assert(PointerIsValid(function)); Assert(PointerIsValid(function));
CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called"); CACHE1_elog(DEBUG, "PrepareToInvalidateCacheTuple: called");
/* ---------------- /* ----------------
* for each cache * for each cache
* if the cache contains tuples from the specified relation * if the cache contains tuples from the specified relation
* call the invalidation function on the tuples * compute the tuple's hash index in this cache,
* in the proper hash bucket * and call the passed function to register the information.
* ---------------- * ----------------
*/ */

View File

@ -3,14 +3,41 @@
* inval.c * inval.c
* POSTGRES cache invalidation dispatcher code. * POSTGRES cache invalidation dispatcher code.
* *
* This is subtle stuff, so pay attention:
*
* When a tuple is updated or deleted, our time qualification rules consider
* that it is *still valid* so long as we are in the same command, ie,
* until the next CommandCounterIncrement() or transaction commit.
* (See utils/time/tqual.c.) At the command boundary, the old tuple stops
* being valid and the new version, if any, becomes valid. Therefore,
* we cannot simply flush a tuple from the system caches during heap_update()
* or heap_delete(). The tuple is still good at that point; what's more,
* even if we did flush it, it might be reloaded into the caches by a later
* request in the same command. So the correct behavior is to keep a list
* of outdated (updated/deleted) tuples and then do the required cache
* flushes at the next command boundary. Similarly, we need a list of
* inserted tuples (including new versions of updated tuples), which we will
* use to flush those tuples out of the caches if we abort the transaction.
* Notice that the first list lives only till command boundary, whereas the
* second lives till end of transaction. Finally, we need a third list of
* all tuples outdated in the current transaction; if we commit, we send
* those invalidation events to all other backends (via the SI message queue)
* so that they can flush obsolete entries from their caches.
*
* We do not need to register EVERY tuple operation in this way, just those
* on tuples in relations that have associated catcaches. Also, whenever
* we see an operation on a pg_class or pg_attribute tuple, we register
* a relcache flush operation for the relation described by that tuple.
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
*
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.38 2000/11/08 22:10:01 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.39 2001/01/05 22:54:37 tgl Exp $
* *
* Note - this code is real crufty... * Note - this code is real crufty... badly needs a rewrite to improve
* readability and portability. (Shouldn't assume Oid == Index, for example)
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -82,7 +109,8 @@ typedef InvalidationMessageData *InvalidationMessage;
* ---------------- * ----------------
* Invalidation info is divided into three parts. * Invalidation info is divided into three parts.
* 1) shared invalidation to be registered for all backends * 1) shared invalidation to be registered for all backends
* 2) local invalidation for the transaction itself * 2) local invalidation for the transaction itself (actually, just
* for the current command within the transaction)
* 3) rollback information for the transaction itself (in case we abort) * 3) rollback information for the transaction itself (in case we abort)
* ---------------- * ----------------
*/ */
@ -107,7 +135,9 @@ static LocalInvalid RollbackStack = EmptyLocalInvalid;
static InvalidationEntry InvalidationEntryAllocate(uint16 size); static InvalidationEntry InvalidationEntryAllocate(uint16 size);
static void LocalInvalidInvalidate(LocalInvalid invalid, void (*function) (), bool freemember); static void LocalInvalidInvalidate(LocalInvalid invalid,
void (*function) (InvalidationMessage),
bool freemember);
static LocalInvalid LocalInvalidRegister(LocalInvalid invalid, static LocalInvalid LocalInvalidRegister(LocalInvalid invalid,
InvalidationEntry entry); InvalidationEntry entry);
static void DiscardInvalidStack(LocalInvalid *invalid); static void DiscardInvalidStack(LocalInvalid *invalid);
@ -161,7 +191,7 @@ LocalInvalidRegister(LocalInvalid invalid,
*/ */
static void static void
LocalInvalidInvalidate(LocalInvalid invalid, LocalInvalidInvalidate(LocalInvalid invalid,
void (*function) (), void (*function) (InvalidationMessage),
bool freemember) bool freemember)
{ {
InvalidationEntryData *entryDataP; InvalidationEntryData *entryDataP;
@ -172,7 +202,7 @@ LocalInvalidInvalidate(LocalInvalid invalid,
&((InvalidationUserData *) invalid)->dataP[-1]; &((InvalidationUserData *) invalid)->dataP[-1];
if (PointerIsValid(function)) if (PointerIsValid(function))
(*function) ((Pointer) &entryDataP->userData); (*function) ((InvalidationMessage) &entryDataP->userData);
invalid = (Pointer) entryDataP->nextP; invalid = (Pointer) entryDataP->nextP;
@ -193,7 +223,9 @@ DiscardInvalidStack(LocalInvalid *invalid)
locinv = *invalid; locinv = *invalid;
*invalid = EmptyLocalInvalid; *invalid = EmptyLocalInvalid;
if (locinv) if (locinv)
LocalInvalidInvalidate(locinv, (void (*) ()) NULL, true); LocalInvalidInvalidate(locinv,
(void (*) (InvalidationMessage)) NULL,
true);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
@ -269,7 +301,7 @@ CacheIdRegisterSpecifiedLocalInvalid(LocalInvalid invalid,
* -------------------------------- * --------------------------------
*/ */
static void static void
CacheIdRegisterLocalInvalid(Index cacheId, CacheIdRegisterLocalInvalid(int cacheId,
Index hashIndex, Index hashIndex,
ItemPointer pointer) ItemPointer pointer)
{ {
@ -298,7 +330,8 @@ CacheIdRegisterLocalInvalid(Index cacheId,
* -------------------------------- * --------------------------------
*/ */
static void static void
CacheIdRegisterLocalRollback(Index cacheId, Index hashIndex, CacheIdRegisterLocalRollback(int cacheId,
Index hashIndex,
ItemPointer pointer) ItemPointer pointer)
{ {
@ -477,7 +510,7 @@ CacheIdInvalidate(Index cacheId,
* -------------------------------- * --------------------------------
*/ */
static void static void
ResetSystemCaches() ResetSystemCaches(void)
{ {
ResetSystemCache(); ResetSystemCache();
RelationCacheInvalidate(); RelationCacheInvalidate();
@ -585,13 +618,13 @@ InvalidationMessageCacheInvalidate(InvalidationMessage message)
} }
/* -------------------------------- /* --------------------------------
* RelationInvalidateRelationCache * PrepareToInvalidateRelationCache
* -------------------------------- * --------------------------------
*/ */
static void static void
RelationInvalidateRelationCache(Relation relation, PrepareToInvalidateRelationCache(Relation relation,
HeapTuple tuple, HeapTuple tuple,
void (*function) ()) void (*function) (Oid, Oid))
{ {
Oid relationId; Oid relationId;
Oid objectId; Oid objectId;
@ -614,7 +647,7 @@ RelationInvalidateRelationCache(Relation relation,
return; return;
/* ---------------- /* ----------------
* can't handle immediate relation descriptor invalidation * register the relcache-invalidation action in the appropriate list
* ---------------- * ----------------
*/ */
Assert(PointerIsValid(function)); Assert(PointerIsValid(function));
@ -629,11 +662,9 @@ RelationInvalidateRelationCache(Relation relation,
* *
* Note: * Note:
* This should be called as the first step in processing a transaction. * 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.
*/ */
void void
DiscardInvalid() DiscardInvalid(void)
{ {
/* ---------------- /* ----------------
* debugging stuff * debugging stuff
@ -694,7 +725,8 @@ RegisterInvalid(bool send)
* Causes invalidation immediately for the next command of the transaction. * Causes invalidation immediately for the next command of the transaction.
* *
* Note: * Note:
* This should be called in time of CommandCounterIncrement(). * This should be called during CommandCounterIncrement(),
* after we have advanced the command ID.
*/ */
void void
ImmediateLocalInvalidation(bool send) ImmediateLocalInvalidation(bool send)
@ -735,7 +767,7 @@ ImmediateLocalInvalidation(bool send)
} }
/* /*
* InvokeHeapTupleInvalidation * PrepareForTupleInvalidation
* Invoke functions for the tuple which register invalidation * Invoke functions for the tuple which register invalidation
* of catalog/relation cache. * of catalog/relation cache.
* Note: * Note:
@ -743,20 +775,21 @@ ImmediateLocalInvalidation(bool send)
* Assumes tuple is valid. * Assumes tuple is valid.
*/ */
#ifdef INVALIDDEBUG #ifdef INVALIDDEBUG
#define InvokeHeapTupleInvalidation_DEBUG1 \ #define PrepareForTupleInvalidation_DEBUG1 \
elog(DEBUG, "%s(%s, [%d,%d])", \ elog(DEBUG, "%s(%s, [%d,%d])", \
funcname,\ funcname,\
RelationGetPhysicalRelationName(relation), \ RelationGetPhysicalRelationName(relation), \
ItemPointerGetBlockNumber(&tuple->t_self), \ ItemPointerGetBlockNumber(&tuple->t_self), \
ItemPointerGetOffsetNumber(&tuple->t_self)) ItemPointerGetOffsetNumber(&tuple->t_self))
#else #else
#define InvokeHeapTupleInvalidation_DEBUG1 #define PrepareForTupleInvalidation_DEBUG1
#endif /* defined(INVALIDDEBUG) */ #endif /* defined(INVALIDDEBUG) */
static void static void
InvokeHeapTupleInvalidation(Relation relation, HeapTuple tuple, PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
void (*CacheIdRegisterFunc) (), void (*CacheIdRegisterFunc) (int, Index,
void (*RelationIdRegisterFunc) (), ItemPointer),
void (*RelationIdRegisterFunc) (Oid, Oid),
const char *funcname) const char *funcname)
{ {
/* ---------------- /* ----------------
@ -768,8 +801,11 @@ InvokeHeapTupleInvalidation(Relation relation, HeapTuple tuple,
if (IsBootstrapProcessingMode()) if (IsBootstrapProcessingMode())
return; return;
/* ---------------- /* ----------------
* this only works for system relations now * 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 (!IsSystemRelationName(NameStr(RelationGetForm(relation)->relname))) if (!IsSystemRelationName(NameStr(RelationGetForm(relation)->relname)))
@ -779,23 +815,24 @@ InvokeHeapTupleInvalidation(Relation relation, HeapTuple tuple,
* debugging stuff * debugging stuff
* ---------------- * ----------------
*/ */
InvokeHeapTupleInvalidation_DEBUG1; PrepareForTupleInvalidation_DEBUG1;
RelationInvalidateCatalogCacheTuple(relation, tuple, PrepareToInvalidateCacheTuple(relation, tuple,
CacheIdRegisterFunc); CacheIdRegisterFunc);
RelationInvalidateRelationCache(relation, tuple, PrepareToInvalidateRelationCache(relation, tuple,
RelationIdRegisterFunc); RelationIdRegisterFunc);
} }
/* /*
* RelationInvalidateHeapTuple * RelationInvalidateHeapTuple
* Causes the given tuple in a relation to be invalidated. * Register the given tuple for invalidation at end of command
* (ie, current command is outdating this tuple).
*/ */
void void
RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple) RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
{ {
InvokeHeapTupleInvalidation(relation, tuple, PrepareForTupleInvalidation(relation, tuple,
CacheIdRegisterLocalInvalid, CacheIdRegisterLocalInvalid,
RelationIdRegisterLocalInvalid, RelationIdRegisterLocalInvalid,
"RelationInvalidateHeapTuple"); "RelationInvalidateHeapTuple");
@ -803,13 +840,13 @@ RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
/* /*
* RelationMark4RollbackHeapTuple * RelationMark4RollbackHeapTuple
* keep the given tuple in a relation to be invalidated * Register the given tuple for invalidation in case of abort
* in case of abort. * (ie, current command is creating this tuple).
*/ */
void void
RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple) RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple)
{ {
InvokeHeapTupleInvalidation(relation, tuple, PrepareForTupleInvalidation(relation, tuple,
CacheIdRegisterLocalRollback, CacheIdRegisterLocalRollback,
RelationIdRegisterLocalRollback, RelationIdRegisterLocalRollback,
"RelationMark4RollbackHeapTuple"); "RelationMark4RollbackHeapTuple");

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catcache.h,v 1.29 2000/11/24 04:16:11 tgl Exp $ * $Id: catcache.h,v 1.30 2001/01/05 22:54:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -95,7 +95,7 @@ extern void ResetSystemCache(void);
extern void SystemCacheRelationFlushed(Oid relId); extern void SystemCacheRelationFlushed(Oid relId);
extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex, extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
ItemPointer pointer); ItemPointer pointer);
extern void RelationInvalidateCatalogCacheTuple(Relation relation, extern void PrepareToInvalidateCacheTuple(Relation relation,
HeapTuple tuple, HeapTuple tuple,
void (*function) (int, Index, ItemPointer)); void (*function) (int, Index, ItemPointer));