diff options
Diffstat (limited to 'src/backend/storage/ipc')
-rw-r--r-- | src/backend/storage/ipc/ipc.c | 9 | ||||
-rw-r--r-- | src/backend/storage/ipc/ipci.c | 20 | ||||
-rw-r--r-- | src/backend/storage/ipc/shmem.c | 145 | ||||
-rw-r--r-- | src/backend/storage/ipc/sinval.c | 65 | ||||
-rw-r--r-- | src/backend/storage/ipc/sinvaladt.c | 12 |
5 files changed, 150 insertions, 101 deletions
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index b5871a5e097..9d2b373a589 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.68 2001/09/04 00:22:34 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.69 2001/09/29 04:02:23 tgl Exp $ * * NOTES * @@ -34,7 +34,6 @@ #include <unistd.h> #include "storage/ipc.h" -#include "storage/s_lock.h" /* In Ultrix, sem.h and shm.h must be included AFTER ipc.h */ #ifdef HAVE_SYS_SEM_H #include <sys/sem.h> @@ -306,7 +305,7 @@ InternalIpcSemaphoreCreate(IpcSemaphoreKey semKey, if (errno == ENOSPC) fprintf(stderr, "\nThis error does *not* mean that you have run out of disk space.\n\n" - "It occurs either because system limit for the maximum number of\n" + "It occurs because either the system limit for the maximum number of\n" "semaphore sets (SEMMNI), or the system wide maximum number of\n" "semaphores (SEMMNS), would be exceeded. You need to raise the\n" "respective kernel parameter. Look into the PostgreSQL documentation\n" @@ -416,8 +415,8 @@ IpcSemaphoreLock(IpcSemaphoreId semId, int sem, bool interruptOK) * record acquiring the lock. (This is currently true for lockmanager * locks, since the process that granted us the lock did all the * necessary state updates. It's not true for SysV semaphores used to - * emulate spinlocks --- but our performance on such platforms is so - * horrible anyway that I'm not going to worry too much about it.) + * implement LW locks or emulate spinlocks --- but the wait time for + * such locks should not be very long, anyway.) */ do { diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 06988baf345..7dac93f3a03 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.42 2001/08/25 18:52:42 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.43 2001/09/29 04:02:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,6 +22,7 @@ #include "storage/bufmgr.h" #include "storage/freespace.h" #include "storage/lmgr.h" +#include "storage/lwlock.h" #include "storage/proc.h" #include "storage/sinval.h" #include "storage/spin.h" @@ -53,7 +54,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int maxBackends) size += LockShmemSize(maxBackends); size += XLOGShmemSize(); size += CLOGShmemSize(); - size += SLockShmemSize(); + size += LWLockShmemSize(); size += SInvalShmemSize(maxBackends); size += FreeSpaceShmemSize(); #ifdef STABLE_MEMORY_STORAGE @@ -74,14 +75,25 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int maxBackends) /* * First initialize spinlocks --- needed by InitShmemAllocation() */ - CreateSpinlocks(seghdr); + CreateSpinlocks(); /* - * Set up shmem.c hashtable + * Set up shared memory allocation mechanism */ InitShmemAllocation(seghdr); /* + * Now initialize LWLocks, which do shared memory allocation and + * are needed for InitShmemIndex. + */ + CreateLWLocks(); + + /* + * Set up shmem.c index hashtable + */ + InitShmemIndex(); + + /* * Set up xlog, clog, and buffers */ XLOGShmemInit(); diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index dd86609875e..0ad168680a1 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.58 2001/09/07 00:27:29 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.59 2001/09/29 04:02:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -61,8 +61,10 @@ #include "postgres.h" #include "access/transam.h" +#include "storage/spin.h" #include "utils/tqual.h" + /* shared memory global variables */ static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */ @@ -71,9 +73,7 @@ SHMEM_OFFSET ShmemBase; /* start address of shared memory */ static SHMEM_OFFSET ShmemEnd; /* end+1 address of shared memory */ -SPINLOCK ShmemLock; /* lock for shared memory allocation */ - -SPINLOCK ShmemIndexLock; /* lock for shmem index access */ +static slock_t *ShmemLock; /* spinlock for shared memory allocation */ static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */ @@ -81,63 +81,33 @@ static bool ShmemBootstrap = false; /* bootstrapping shmem index? */ /* - * InitShmemAllocation() --- set up shared-memory allocation and index table. + * InitShmemAllocation() --- set up shared-memory allocation. + * + * Note: the argument should be declared "PGShmemHeader *seghdr", + * but we use void to avoid having to include ipc.h in shmem.h. */ void -InitShmemAllocation(PGShmemHeader *seghdr) +InitShmemAllocation(void *seghdr) { - HASHCTL info; - int hash_flags; - ShmemIndexEnt *result, - item; - bool found; + PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr; /* Set up basic pointers to shared memory */ - ShmemSegHdr = seghdr; - ShmemBase = (SHMEM_OFFSET) seghdr; - ShmemEnd = ShmemBase + seghdr->totalsize; - - /* - * Since ShmemInitHash calls ShmemInitStruct, which expects the - * ShmemIndex hashtable to exist already, we have a bit of a - * circularity problem in initializing the ShmemIndex itself. We set - * ShmemBootstrap to tell ShmemInitStruct to fake it. - */ - ShmemIndex = (HTAB *) NULL; - ShmemBootstrap = true; - - /* create the shared memory shmem index */ - info.keysize = SHMEM_INDEX_KEYSIZE; - info.datasize = SHMEM_INDEX_DATASIZE; - hash_flags = HASH_ELEM; - - /* This will acquire the shmem index lock, but not release it. */ - ShmemIndex = ShmemInitHash("ShmemIndex", - SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE, - &info, hash_flags); - if (!ShmemIndex) - elog(FATAL, "InitShmemAllocation: couldn't initialize Shmem Index"); + ShmemSegHdr = shmhdr; + ShmemBase = (SHMEM_OFFSET) shmhdr; + ShmemEnd = ShmemBase + shmhdr->totalsize; /* - * Now, create an entry in the hashtable for the index itself. + * Initialize the spinlock used by ShmemAlloc. We have to do the + * space allocation the hard way, since ShmemAlloc can't be called yet. */ - MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE); - strncpy(item.key, "ShmemIndex", SHMEM_INDEX_KEYSIZE); + ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset); + shmhdr->freeoffset += MAXALIGN(sizeof(slock_t)); + Assert(shmhdr->freeoffset <= shmhdr->totalsize); - result = (ShmemIndexEnt *) - hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found); - if (!result) - elog(FATAL, "InitShmemAllocation: corrupted shmem index"); + SpinLockInit(ShmemLock); - Assert(ShmemBootstrap && !found); - - result->location = MAKE_OFFSET(ShmemIndex->hctl); - result->size = SHMEM_INDEX_SIZE; - - ShmemBootstrap = false; - - /* now release the lock acquired in ShmemInitStruct */ - SpinRelease(ShmemIndexLock); + /* ShmemIndex can't be set up yet (need LWLocks first) */ + ShmemIndex = (HTAB *) NULL; /* * Initialize ShmemVariableCache for transaction manager. @@ -167,9 +137,9 @@ ShmemAlloc(Size size) */ size = MAXALIGN(size); - Assert(ShmemSegHdr); + Assert(ShmemSegHdr != NULL); - SpinAcquire(ShmemLock); + SpinLockAcquire(ShmemLock); newFree = ShmemSegHdr->freeoffset + size; if (newFree <= ShmemSegHdr->totalsize) @@ -180,7 +150,7 @@ ShmemAlloc(Size size) else newSpace = NULL; - SpinRelease(ShmemLock); + SpinLockRelease(ShmemLock); if (!newSpace) elog(NOTICE, "ShmemAlloc: out of memory"); @@ -200,6 +170,60 @@ ShmemIsValid(unsigned long addr) } /* + * InitShmemIndex() --- set up shmem index table. + */ +void +InitShmemIndex(void) +{ + HASHCTL info; + int hash_flags; + ShmemIndexEnt *result, + item; + bool found; + + /* + * Since ShmemInitHash calls ShmemInitStruct, which expects the + * ShmemIndex hashtable to exist already, we have a bit of a + * circularity problem in initializing the ShmemIndex itself. We set + * ShmemBootstrap to tell ShmemInitStruct to fake it. + */ + ShmemBootstrap = true; + + /* create the shared memory shmem index */ + info.keysize = SHMEM_INDEX_KEYSIZE; + info.datasize = SHMEM_INDEX_DATASIZE; + hash_flags = HASH_ELEM; + + /* This will acquire the shmem index lock, but not release it. */ + ShmemIndex = ShmemInitHash("ShmemIndex", + SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE, + &info, hash_flags); + if (!ShmemIndex) + elog(FATAL, "InitShmemIndex: couldn't initialize Shmem Index"); + + /* + * Now, create an entry in the hashtable for the index itself. + */ + MemSet(item.key, 0, SHMEM_INDEX_KEYSIZE); + strncpy(item.key, "ShmemIndex", SHMEM_INDEX_KEYSIZE); + + result = (ShmemIndexEnt *) + hash_search(ShmemIndex, (char *) &item, HASH_ENTER, &found); + if (!result) + elog(FATAL, "InitShmemIndex: corrupted shmem index"); + + Assert(ShmemBootstrap && !found); + + result->location = MAKE_OFFSET(ShmemIndex->hctl); + result->size = SHMEM_INDEX_SIZE; + + ShmemBootstrap = false; + + /* now release the lock acquired in ShmemInitStruct */ + LWLockRelease(ShmemIndexLock); +} + +/* * ShmemInitHash -- Create/Attach to and initialize * shared memory hash table. * @@ -207,8 +231,7 @@ ShmemIsValid(unsigned long addr) * * assume caller is doing some kind of synchronization * so that two people dont try to create/initialize the - * table at once. Use SpinAlloc() to create a spinlock - * for the structure before creating the structure itself. + * table at once. */ HTAB * ShmemInitHash(char *name, /* table string name for shmem index */ @@ -283,7 +306,7 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr) strncpy(item.key, name, SHMEM_INDEX_KEYSIZE); item.location = BAD_LOCATION; - SpinAcquire(ShmemIndexLock); + LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE); if (!ShmemIndex) { @@ -306,7 +329,7 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr) if (!result) { - SpinRelease(ShmemIndexLock); + LWLockRelease(ShmemIndexLock); elog(ERROR, "ShmemInitStruct: Shmem Index corrupted"); return NULL; } @@ -320,7 +343,7 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr) */ if (result->size != size) { - SpinRelease(ShmemIndexLock); + LWLockRelease(ShmemIndexLock); elog(NOTICE, "ShmemInitStruct: ShmemIndex entry size is wrong"); /* let caller print its message too */ @@ -337,7 +360,7 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr) /* out of memory */ Assert(ShmemIndex); hash_search(ShmemIndex, (char *) &item, HASH_REMOVE, foundPtr); - SpinRelease(ShmemIndexLock); + LWLockRelease(ShmemIndexLock); *foundPtr = FALSE; elog(NOTICE, "ShmemInitStruct: cannot allocate '%s'", @@ -349,6 +372,6 @@ ShmemInitStruct(char *name, Size size, bool *foundPtr) } Assert(ShmemIsValid((unsigned long) structPtr)); - SpinRelease(ShmemIndexLock); + LWLockRelease(ShmemIndexLock); return structPtr; } diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c index 1d43b1ead44..24506b9729a 100644 --- a/src/backend/storage/ipc/sinval.c +++ b/src/backend/storage/ipc/sinval.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.40 2001/08/26 16:56:00 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.41 2001/09/29 04:02:24 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,8 +23,6 @@ #include "miscadmin.h" -SPINLOCK SInvalLock = (SPINLOCK) NULL; - /****************************************************************************/ /* CreateSharedInvalidationState() Initialize SI buffer */ /* */ @@ -33,7 +31,7 @@ SPINLOCK SInvalLock = (SPINLOCK) NULL; void CreateSharedInvalidationState(int maxBackends) { - /* SInvalLock must be initialized already, during spinlock init */ + /* SInvalLock must be initialized already, during LWLock init */ SIBufferInit(maxBackends); } @@ -46,9 +44,9 @@ InitBackendSharedInvalidationState(void) { int flag; - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_EXCLUSIVE); flag = SIBackendInit(shmInvalBuffer); - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); if (flag < 0) /* unexpected problem */ elog(FATAL, "Backend cache invalidation initialization failed"); if (flag == 0) /* expected problem: MaxBackends exceeded */ @@ -64,9 +62,9 @@ SendSharedInvalidMessage(SharedInvalidationMessage *msg) { bool insertOK; - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_EXCLUSIVE); insertOK = SIInsertDataEntry(shmInvalBuffer, msg); - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); if (!insertOK) elog(DEBUG, "SendSharedInvalidMessage: SI buffer overflow"); } @@ -86,9 +84,25 @@ ReceiveSharedInvalidMessages( for (;;) { - SpinAcquire(SInvalLock); + /* + * We can run SIGetDataEntry in parallel with other backends running + * SIGetDataEntry for themselves, since each instance will modify + * only fields of its own backend's ProcState, and no instance will + * look at fields of other backends' ProcStates. We express this + * by grabbing SInvalLock in shared mode. Note that this is not + * exactly the normal (read-only) interpretation of a shared lock! + * Look closely at the interactions before allowing SInvalLock to + * be grabbed in shared mode for any other reason! + * + * The routines later in this file that use shared mode are okay + * with this, because they aren't looking at the ProcState fields + * associated with SI message transfer; they only use the ProcState + * array as an easy way to find all the PROC structures. + */ + LWLockAcquire(SInvalLock, LW_SHARED); getResult = SIGetDataEntry(shmInvalBuffer, MyBackendId, &data); - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); + if (getResult == 0) break; /* nothing more to do */ if (getResult < 0) @@ -108,9 +122,9 @@ ReceiveSharedInvalidMessages( /* If we got any messages, try to release dead messages */ if (gotMessage) { - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_EXCLUSIVE); SIDelExpiredDataEntries(shmInvalBuffer); - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); } } @@ -149,7 +163,7 @@ DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself) ProcState *stateP = segP->procState; int index; - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_SHARED); for (index = 0; index < segP->lastBackend; index++) { @@ -170,7 +184,7 @@ DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself) } } - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); return result; } @@ -186,7 +200,7 @@ TransactionIdIsInProgress(TransactionId xid) ProcState *stateP = segP->procState; int index; - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_SHARED); for (index = 0; index < segP->lastBackend; index++) { @@ -206,7 +220,7 @@ TransactionIdIsInProgress(TransactionId xid) } } - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); return result; } @@ -237,7 +251,7 @@ GetOldestXmin(bool allDbs) result = GetCurrentTransactionId(); - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_SHARED); for (index = 0; index < segP->lastBackend; index++) { @@ -265,7 +279,7 @@ GetOldestXmin(bool allDbs) } } - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); return result; } @@ -298,7 +312,7 @@ GetSnapshotData(bool serializable) snapshot->xmin = GetCurrentTransactionId(); - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_SHARED); /* * There can be no more than lastBackend active transactions, so this @@ -307,15 +321,12 @@ GetSnapshotData(bool serializable) snapshot->xip = (TransactionId *) malloc(segP->lastBackend * sizeof(TransactionId)); if (snapshot->xip == NULL) - { - SpinRelease(SInvalLock); elog(ERROR, "Memory exhausted in GetSnapshotData"); - } /*-------------------- * Unfortunately, we have to call ReadNewTransactionId() after acquiring * SInvalLock above. It's not good because ReadNewTransactionId() does - * SpinAcquire(XidGenLockId), but *necessary*. We need to be sure that + * LWLockAcquire(XidGenLock), but *necessary*. We need to be sure that * no transactions exit the set of currently-running transactions * between the time we fetch xmax and the time we finish building our * snapshot. Otherwise we could have a situation like this: @@ -373,7 +384,7 @@ GetSnapshotData(bool serializable) if (serializable) MyProc->xmin = snapshot->xmin; - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); /* Serializable snapshot must be computed before any other... */ Assert(TransactionIdIsValid(MyProc->xmin)); @@ -439,7 +450,7 @@ GetUndoRecPtr(void) XLogRecPtr tempr; int index; - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_SHARED); for (index = 0; index < segP->lastBackend; index++) { @@ -458,7 +469,7 @@ GetUndoRecPtr(void) } } - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); return (urec); } @@ -470,7 +481,7 @@ GetUndoRecPtr(void) * knows that the backend isn't going to go away, so we do not bother with * locking. */ -struct proc * +struct PROC * BackendIdGetProc(BackendId procId) { SISeg *segP = shmInvalBuffer; diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c index 38096190091..d05a651097f 100644 --- a/src/backend/storage/ipc/sinvaladt.c +++ b/src/backend/storage/ipc/sinvaladt.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.40 2001/06/19 19:42:15 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.41 2001/09/29 04:02:24 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -83,7 +83,7 @@ SIBufferInit(int maxBackends) * <0 Some other failure (not currently used) * * NB: this routine, and all following ones, must be executed with the - * SInvalLock spinlock held, since there may be multiple backends trying + * SInvalLock lock held, since there may be multiple backends trying * to access the buffer. */ int @@ -152,7 +152,7 @@ CleanupInvalidationState(int status, Datum arg) Assert(PointerIsValid(segP)); - SpinAcquire(SInvalLock); + LWLockAcquire(SInvalLock, LW_EXCLUSIVE); /* Mark myself inactive */ segP->procState[MyBackendId - 1].nextMsgNum = -1; @@ -167,7 +167,7 @@ CleanupInvalidationState(int status, Datum arg) } segP->lastBackend = i; - SpinRelease(SInvalLock); + LWLockRelease(SInvalLock); } /* @@ -267,6 +267,10 @@ SISetProcStateInvalid(SISeg *segP) * 1: next SI message has been extracted into *data * (there may be more messages available after this one!) * -1: SI reset message extracted + * + * NB: this can run in parallel with other instances of SIGetDataEntry + * executing on behalf of other backends. See comments in sinval.c in + * ReceiveSharedInvalidMessages(). */ int SIGetDataEntry(SISeg *segP, int backendId, |