Rename and document some invalidation routines to make it clearer that
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 5 Jan 2001 22:54:37 +0000 (22:54 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 5 Jan 2001 22:54:37 +0000 (22:54 +0000)
they don't themselves flush any cache entries, only add to to-do lists
that will be processed later.

src/backend/utils/cache/catcache.c
src/backend/utils/cache/inval.c
src/include/utils/catcache.h

index 3e1c428a532728d68ebd5d439951da0ebe8d550e..d8e31f3967b13877070cbe55c6caad94daacac88 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
- * cache in question and calls CatalogCacheIdInvalidate().  It is -ok-
- * if the relation cannot be found, it simply means this backend has yet
- * to open it.
+ * This is part of a rather subtle chain of events, so pay attention:
+ *
+ * When a tuple is updated or deleted, it cannot be flushed from the
+ * 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
-RelationInvalidateCatalogCacheTuple(Relation relation,
-                                   HeapTuple tuple,
+PrepareToInvalidateCacheTuple(Relation relation,
+                             HeapTuple tuple,
                              void (*function) (int, Index, ItemPointer))
 {
    CatCache   *ccp;
@@ -1069,13 +1088,13 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
    Assert(RelationIsValid(relation));
    Assert(HeapTupleIsValid(tuple));
    Assert(PointerIsValid(function));
-   CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called");
+   CACHE1_elog(DEBUG, "PrepareToInvalidateCacheTuple: called");
 
    /* ----------------
     *  for each cache
     *     if the cache contains tuples from the specified relation
-    *         call the invalidation function on the tuples
-    *         in the proper hash bucket
+    *         compute the tuple's hash index in this cache,
+    *         and call the passed function to register the information.
     * ----------------
     */
 
index 8f4fd626f8b7fe68563b5dc023fe9c5ad0ea3c80..37f2c8416c473f5507859acb79b9946b058b742a 100644 (file)
@@ -3,14 +3,41 @@
  * inval.c
  *   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) 1994, Regents of the University of California
  *
- *
  * 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.
  * 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)
  * ----------------
  */
@@ -107,7 +135,9 @@ static LocalInvalid RollbackStack = EmptyLocalInvalid;
 
 
 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,
                     InvalidationEntry entry);
 static void DiscardInvalidStack(LocalInvalid *invalid);
@@ -161,7 +191,7 @@ LocalInvalidRegister(LocalInvalid invalid,
  */
 static void
 LocalInvalidInvalidate(LocalInvalid invalid,
-                      void (*function) (),
+                      void (*function) (InvalidationMessage),
                       bool freemember)
 {
    InvalidationEntryData *entryDataP;
@@ -172,7 +202,7 @@ LocalInvalidInvalidate(LocalInvalid invalid,
            &((InvalidationUserData *) invalid)->dataP[-1];
 
        if (PointerIsValid(function))
-           (*function) ((Pointer) &entryDataP->userData);
+           (*function) ((InvalidationMessage) &entryDataP->userData);
 
        invalid = (Pointer) entryDataP->nextP;
 
@@ -193,7 +223,9 @@ DiscardInvalidStack(LocalInvalid *invalid)
    locinv = *invalid;
    *invalid = EmptyLocalInvalid;
    if (locinv)
-       LocalInvalidInvalidate(locinv, (void (*) ()) NULL, true);
+       LocalInvalidInvalidate(locinv,
+                              (void (*) (InvalidationMessage)) NULL,
+                              true);
 }
 
 /* ----------------------------------------------------------------
@@ -269,7 +301,7 @@ CacheIdRegisterSpecifiedLocalInvalid(LocalInvalid invalid,
  * --------------------------------
  */
 static void
-CacheIdRegisterLocalInvalid(Index cacheId,
+CacheIdRegisterLocalInvalid(int cacheId,
                            Index hashIndex,
                            ItemPointer pointer)
 {
@@ -298,7 +330,8 @@ CacheIdRegisterLocalInvalid(Index cacheId,
  * --------------------------------
  */
 static void
-CacheIdRegisterLocalRollback(Index cacheId, Index hashIndex,
+CacheIdRegisterLocalRollback(int cacheId,
+                            Index hashIndex,
                             ItemPointer pointer)
 {
 
@@ -477,7 +510,7 @@ CacheIdInvalidate(Index cacheId,
  * --------------------------------
  */
 static void
-ResetSystemCaches()
+ResetSystemCaches(void)
 {
    ResetSystemCache();
    RelationCacheInvalidate();
@@ -585,13 +618,13 @@ InvalidationMessageCacheInvalidate(InvalidationMessage message)
 }
 
 /* --------------------------------
- *     RelationInvalidateRelationCache
+ *     PrepareToInvalidateRelationCache
  * --------------------------------
  */
 static void
-RelationInvalidateRelationCache(Relation relation,
-                               HeapTuple tuple,
-                               void (*function) ())
+PrepareToInvalidateRelationCache(Relation relation,
+                                HeapTuple tuple,
+                                void (*function) (Oid, Oid))
 {
    Oid         relationId;
    Oid         objectId;
@@ -614,7 +647,7 @@ RelationInvalidateRelationCache(Relation relation,
        return;
 
    /* ----------------
-    *    can't handle immediate relation descriptor invalidation
+    *  register the relcache-invalidation action in the appropriate list
     * ----------------
     */
    Assert(PointerIsValid(function));
@@ -629,11 +662,9 @@ RelationInvalidateRelationCache(Relation relation,
  *
  * 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.
  */
 void
-DiscardInvalid()
+DiscardInvalid(void)
 {
    /* ----------------
     *  debugging stuff
@@ -694,7 +725,8 @@ RegisterInvalid(bool send)
  *     Causes invalidation immediately for the next command of the transaction.
  *
  * Note:
- *     This should be called in time of CommandCounterIncrement().
+ *     This should be called during CommandCounterIncrement(),
+ *     after we have advanced the command ID.
  */
 void
 ImmediateLocalInvalidation(bool send)
@@ -735,7 +767,7 @@ ImmediateLocalInvalidation(bool send)
 }
 
 /*
- * InvokeHeapTupleInvalidation
+ * PrepareForTupleInvalidation
  *     Invoke functions for the tuple which register invalidation
  *     of catalog/relation cache.
  * Note:
@@ -743,20 +775,21 @@ ImmediateLocalInvalidation(bool send)
  *     Assumes tuple is valid.
  */
 #ifdef INVALIDDEBUG
-#define InvokeHeapTupleInvalidation_DEBUG1 \
+#define PrepareForTupleInvalidation_DEBUG1 \
 elog(DEBUG, "%s(%s, [%d,%d])", \
     funcname,\
     RelationGetPhysicalRelationName(relation), \
     ItemPointerGetBlockNumber(&tuple->t_self), \
     ItemPointerGetOffsetNumber(&tuple->t_self))
 #else
-#define InvokeHeapTupleInvalidation_DEBUG1
+#define PrepareForTupleInvalidation_DEBUG1
 #endif  /* defined(INVALIDDEBUG) */
 
 static void
-InvokeHeapTupleInvalidation(Relation relation, HeapTuple tuple,
-                           void (*CacheIdRegisterFunc) (),
-                           void (*RelationIdRegisterFunc) (),
+PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
+                           void (*CacheIdRegisterFunc) (int, Index,
+                                                        ItemPointer),
+                           void (*RelationIdRegisterFunc) (Oid, Oid),
                            const char *funcname)
 {
    /* ----------------
@@ -768,8 +801,11 @@ InvokeHeapTupleInvalidation(Relation relation, HeapTuple tuple,
 
    if (IsBootstrapProcessingMode())
        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)))
@@ -779,23 +815,24 @@ InvokeHeapTupleInvalidation(Relation relation, HeapTuple tuple,
     *  debugging stuff
     * ----------------
     */
-   InvokeHeapTupleInvalidation_DEBUG1;
+   PrepareForTupleInvalidation_DEBUG1;
 
-   RelationInvalidateCatalogCacheTuple(relation, tuple,
-                                       CacheIdRegisterFunc);
+   PrepareToInvalidateCacheTuple(relation, tuple,
+                                 CacheIdRegisterFunc);
 
-   RelationInvalidateRelationCache(relation, tuple,
-                                   RelationIdRegisterFunc);
+   PrepareToInvalidateRelationCache(relation, tuple,
+                                    RelationIdRegisterFunc);
 }
 
 /*
  * 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
 RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
 {
-   InvokeHeapTupleInvalidation(relation, tuple,
+   PrepareForTupleInvalidation(relation, tuple,
                                CacheIdRegisterLocalInvalid,
                                RelationIdRegisterLocalInvalid,
                                "RelationInvalidateHeapTuple");
@@ -803,13 +840,13 @@ RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
 
 /*
  * RelationMark4RollbackHeapTuple
- *     keep the given tuple in a relation to be invalidated
- *     in case of abort.
+ *     Register the given tuple for invalidation in case of abort
+ *     (ie, current command is creating this tuple).
  */
 void
 RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple)
 {
-   InvokeHeapTupleInvalidation(relation, tuple,
+   PrepareForTupleInvalidation(relation, tuple,
                                CacheIdRegisterLocalRollback,
                                RelationIdRegisterLocalRollback,
                                "RelationMark4RollbackHeapTuple");
index 70c988ca185b40c3b2cc341f8cae0fddc6a28c82..a24307bd90f91ddac5a32d42058edbb59da9b211 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * 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 CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
                                     ItemPointer pointer);
-extern void RelationInvalidateCatalogCacheTuple(Relation relation,
+extern void PrepareToInvalidateCacheTuple(Relation relation,
                                HeapTuple tuple,
                                void (*function) (int, Index, ItemPointer));