Commit 8add6d71 authored by Tom Lane's avatar Tom Lane

Modify sinval so that InvalidateSharedInvalid() does not hold

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.
parent ae01c7f5
......@@ -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) (),
InvalidateSharedInvalid(void (*invalFunction) (),
void (*resetFunction) ())
{
SharedInvalidData data;
int getResult;
bool gotMessage = false;
for (;;)
{
SpinAcquire(SInvalLock);
SIReadEntryData(shmInvalBuffer, MyBackendId,
invalFunction, resetFunction);
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);
}
}
......@@ -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,20 +557,25 @@ 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 (!SIDecNumEntries(segP, 1))
if (n <= 0)
return false;
if (!SIDecNumEntries(segP, n))
{
/* no entries in buffer */
/* not that many entries in buffer */
return false;
}
e1P = SIGetFirstDataEntry(segP);
for (i = 1; i <= n; i++)
{
SISegEntry *e1P = SIGetFirstDataEntry(segP);
SISetStartEntryChain(segP, e1P->next);
if (SIGetStartEntryChain(segP) == InvalidOffset)
{
......@@ -590,7 +586,9 @@ SIDelDataEntry(SISeg *segP)
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,16 +686,13 @@ 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))
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");
}
}
......
......@@ -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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment