]> granicus.if.org Git - postgresql/commitdiff
Modify sinval so that InvalidateSharedInvalid() does not hold
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 4 Sep 1999 18:36:45 +0000 (18:36 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 4 Sep 1999 18:36:45 +0000 (18:36 +0000)
the SInval spinlock while it is calling the passed invalFunction or
resetFunction.  This is necessary to avoid deadlock with lmgr change;
InvalidateSharedInvalid can be called recursively now.  It should be
a good performance improvement anyway --- holding a spinlock for more
than a very short interval is a no-no.

src/backend/storage/ipc/sinval.c
src/backend/storage/ipc/sinvaladt.c
src/include/storage/sinvaladt.h

index 21585cc2406191606b20107032afe9cfeb26b2f9..e993cef74aa8c05945ab9cf320ef13154110e188 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.16 1999/07/15 22:39:49 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.17 1999/09/04 18:36:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,9 +21,9 @@
 #include "storage/sinval.h"
 #include "storage/sinvaladt.h"
 
-extern SISeg *shmInvalBuffer;  /* the shared buffer segment, set by */
-
/* SISegmentAttach()                     */
+extern SISeg *shmInvalBuffer;  /* the shared buffer segment, set by
+                                                                * SISegmentAttach()
                                                               */
 extern BackendId MyBackendId;
 extern BackendTag MyBackendTag;
 
@@ -127,21 +127,20 @@ RegisterSharedInvalid(int cacheId,                /* XXX */
                ItemPointerSetInvalid(&newInvalid.pointerData);
 
        SpinAcquire(SInvalLock);
-       if (!SISetDataEntry(shmInvalBuffer, &newInvalid))
+       while (!SISetDataEntry(shmInvalBuffer, &newInvalid))
        {
                /* buffer full */
                /* release a message, mark process cache states to be invalid */
                SISetProcStateInvalid(shmInvalBuffer);
 
-               if (!SIDelDataEntry(shmInvalBuffer))
+               if (!SIDelDataEntries(shmInvalBuffer, 1))
                {
                        /* inconsistent buffer state -- shd never happen */
                        SpinRelease(SInvalLock);
                        elog(FATAL, "RegisterSharedInvalid: inconsistent buffer state");
                }
 
-               /* write again */
-               SISetDataEntry(shmInvalBuffer, &newInvalid);
+               /* loop around to try write again */
        }
        SpinRelease(SInvalLock);
 }
@@ -157,13 +156,41 @@ RegisterSharedInvalid(int cacheId,                /* XXX */
 /*     should be called by a backend                                                                                   */
 /****************************************************************************/
 void
-                       InvalidateSharedInvalid(void (*invalFunction) (),
-                                                                       void (*resetFunction) ())
+InvalidateSharedInvalid(void (*invalFunction) (),
+                                               void (*resetFunction) ())
 {
-       SpinAcquire(SInvalLock);
-       SIReadEntryData(shmInvalBuffer, MyBackendId,
-                                       invalFunction, resetFunction);
+       SharedInvalidData       data;
+       int                                     getResult;
+       bool                            gotMessage = false;
 
-       SIDelExpiredDataEntries(shmInvalBuffer);
-       SpinRelease(SInvalLock);
+       for (;;)
+       {
+               SpinAcquire(SInvalLock);
+               getResult = SIGetDataEntry(shmInvalBuffer, MyBackendId, &data);
+               SpinRelease(SInvalLock);
+               if (getResult == 0)
+                       break;                          /* nothing more to do */
+               if (getResult < 0)
+               {
+                       /* got a reset message */
+                       elog(NOTICE, "InvalidateSharedInvalid: cache state reset");
+                       resetFunction();
+               }
+               else
+               {
+                       /* got a normal data message */
+                       invalFunction(data.cacheId,
+                                                 data.hashIndex,
+                                                 &data.pointerData);
+               }
+               gotMessage = true;
+       }
+
+       /* If we got any messages, try to release dead messages */
+       if (gotMessage)
+       {
+               SpinAcquire(SInvalLock);
+               SIDelExpiredDataEntries(shmInvalBuffer);
+               SpinRelease(SInvalLock);
+       }
 }
index cffc4aac229a0ab5f8240302bcd8147ca94ca352..2e64d027f31c7c7eb7b78967b7991c400286046d 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.23 1999/07/17 20:17:44 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.24 1999/09/04 18:36:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -450,20 +450,11 @@ SIGetLastDataEntry(SISeg *segP)
 /************************************************************************/
 /* SIGetNextDataEntry(segP, offset)  returns next data entry                   */
 /************************************************************************/
-static SISegEntry *
-SIGetNextDataEntry(SISeg *segP, Offset offset)
-{
-       SISegEntry *eP;
-
-       if (offset == InvalidOffset)
-               return NULL;
-
-       eP = (SISegEntry *) ((Pointer) segP +
-                                                SIGetStartEntrySection(segP) +
-                                                offset);
-       return eP;
-}
-
+#define SIGetNextDataEntry(segP,offset) \
+       (((offset) == InvalidOffset) ? (SISegEntry *) NULL : \
+        (SISegEntry *) ((Pointer) (segP) + \
+                                        (segP)->startEntrySection + \
+                                        (Offset) (offset)))
 
 /************************************************************************/
 /* SIGetNthDataEntry(segP, n)  returns the n-th data entry in chain    */
@@ -566,31 +557,38 @@ SIDecProcLimit(SISeg *segP, int num)
 
 
 /************************************************************************/
-/* SIDelDataEntry(segP)                - free the FIRST entry                                          */
+/* SIDelDataEntries(segP, n)           - free the FIRST n entries                      */
 /************************************************************************/
 bool
-SIDelDataEntry(SISeg *segP)
+SIDelDataEntries(SISeg *segP, int n)
 {
-       SISegEntry *e1P;
+       int                     i;
+
+       if (n <= 0)
+               return false;
 
-       if (!SIDecNumEntries(segP, 1))
+       if (!SIDecNumEntries(segP, n))
        {
-               /* no entries in buffer */
+               /* not that many entries in buffer */
                return false;
        }
 
-       e1P = SIGetFirstDataEntry(segP);
-       SISetStartEntryChain(segP, e1P->next);
-       if (SIGetStartEntryChain(segP) == InvalidOffset)
+       for (i = 1; i <= n; i++)
        {
-               /* it was the last entry */
-               SISetEndEntryChain(segP, InvalidOffset);
+               SISegEntry *e1P = SIGetFirstDataEntry(segP);
+               SISetStartEntryChain(segP, e1P->next);
+               if (SIGetStartEntryChain(segP) == InvalidOffset)
+               {
+                       /* it was the last entry */
+                       SISetEndEntryChain(segP, InvalidOffset);
+               }
+               /* free the entry */
+               e1P->isfree = true;
+               e1P->next = SIGetStartFreeSpace(segP);
+               SISetStartFreeSpace(segP, SIEntryOffset(segP, e1P));
        }
-       /* free the entry */
-       e1P->isfree = true;
-       e1P->next = SIGetStartFreeSpace(segP);
-       SISetStartFreeSpace(segP, SIEntryOffset(segP, e1P));
-       SIDecProcLimit(segP, 1);
+
+       SIDecProcLimit(segP, n);
        return true;
 }
 
@@ -621,51 +619,51 @@ SISetProcStateInvalid(SISeg *segP)
 }
 
 /************************************************************************/
-/* SIReadEntryData(segP, backendId, function)                                                  */
-/*                                             - marks messages to be read by id                               */
-/*                                               and executes function                                                 */
+/* SIGetDataEntry(segP, backendId, data)                                                               */
+/*             get next SI message for specified backend, if there is one              */
+/*                                                                                                                                             */
+/*             Possible return values:                                                                                 */
+/*                     0: no SI message available                                                                      */
+/*                     1: next SI message has been extracted into *data                        */
+/*                             (there may be more messages available after this one!)  */
+/*                -1: SI reset message extracted                                                               */
 /************************************************************************/
-void
-SIReadEntryData(SISeg *segP,
-                               int backendId,
-                               void (*invalFunction) (),
-                               void (*resetFunction) ())
+int
+SIGetDataEntry(SISeg *segP, int backendId,
+                          SharedInvalidData *data)
 {
-       int                     i = 0;
-       SISegEntry *data;
+       SISegEntry *msg;
 
        Assert(segP->procState[backendId - 1].tag == MyBackendTag);
 
-       if (!segP->procState[backendId - 1].resetState)
+       if (segP->procState[backendId - 1].resetState)
        {
-               /* invalidate data, but only those, you have not seen yet !! */
-               /* therefore skip read messages */
-               data = SIGetNthDataEntry(segP,
-                                                  SIGetProcStateLimit(segP, backendId - 1) + 1);
-               while (data != NULL)
-               {
-                       i++;
-                       segP->procState[backendId - 1].limit++;         /* one more message read */
-                       invalFunction(data->entryData.cacheId,
-                                                 data->entryData.hashIndex,
-                                                 &data->entryData.pointerData);
-                       data = SIGetNextDataEntry(segP, data->next);
-               }
-               /* SIDelExpiredDataEntries(segP); */
-       }
-       else
-       {
-               /* backend must not read messages, its own state has to be reset         */
-               elog(NOTICE, "SIReadEntryData: cache state reset");
-               resetFunction();                /* XXXX call it here, parameters? */
-
                /* new valid state--mark all messages "read" */
                segP->procState[backendId - 1].resetState = false;
                segP->procState[backendId - 1].limit = SIGetNumEntries(segP);
+               return -1;
        }
-       /* check whether we can remove dead messages                                                    */
-       if (i > MAXNUMMESSAGES)
-               elog(FATAL, "SIReadEntryData: Invalid segment state");
+
+       /* Get next message for this backend, if any */
+
+       /* This is fairly inefficient if there are many messages,
+        * but normally there should not be...
+        */
+       msg = SIGetNthDataEntry(segP,
+                                                       SIGetProcStateLimit(segP, backendId - 1) + 1);
+
+       if (msg == NULL)
+               return 0;                               /* nothing to read */
+
+       *data = msg->entryData;         /* return contents of message */
+
+       segP->procState[backendId - 1].limit++;         /* one more message read */
+
+       /* There may be other backends that haven't read the message,
+        * so we cannot delete it here.
+        * SIDelExpiredDataEntries() should be called to remove dead messages.
+        */
+       return 1;                                       /* got a message */
 }
 
 /************************************************************************/
@@ -688,15 +686,12 @@ SIDelExpiredDataEntries(SISeg *segP)
                                min = h;
                }
        }
-       if (min != 9999999)
+       if (min < 9999999 && min > 0)
        {
                /* we can remove min messages */
-               for (i = 1; i <= min; i++)
-               {
-                       /* this  adjusts also the state limits! */
-                       if (!SIDelDataEntry(segP))
-                               elog(FATAL, "SIDelExpiredDataEntries: Invalid segment state");
-               }
+               /* this adjusts also the state limits! */
+               if (!SIDelDataEntries(segP, min))
+                       elog(FATAL, "SIDelExpiredDataEntries: Invalid segment state");
        }
 }
 
@@ -784,8 +779,7 @@ SISegmentAttach(IpcMemoryId shmid)
        if (shmInvalBuffer == IpcMemAttachFailed)
        {
                /* XXX use validity function */
-               elog(NOTICE, "SISegmentAttach: Could not attach segment");
-               elog(FATAL, "SISegmentAttach: %m");
+               elog(FATAL, "SISegmentAttach: Could not attach segment: %m");
        }
 }
 
index 4885b7380c808231eedaa75aab39b14a1bcde525..e008e52d30fc57ea7c1240c9c4a89c369d418a05 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: sinvaladt.h,v 1.16 1999/07/16 17:07:38 momjian Exp $
+ * $Id: sinvaladt.h,v 1.17 1999/09/04 18:36:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -128,9 +128,9 @@ extern int  SISegmentInit(bool killExistingSegment, IPCKey key,
 
 extern bool SISetDataEntry(SISeg *segP, SharedInvalidData *data);
 extern void SISetProcStateInvalid(SISeg *segP);
-extern bool SIDelDataEntry(SISeg *segP);
-extern void SIReadEntryData(SISeg *segP, int backendId,
-                               void (*invalFunction) (), void (*resetFunction) ());
+extern int     SIGetDataEntry(SISeg *segP, int backendId,
+                                                  SharedInvalidData *data);
+extern bool SIDelDataEntries(SISeg *segP, int n);
 extern void SIDelExpiredDataEntries(SISeg *segP);
 
 #endif  /* SINVALADT_H */