]> granicus.if.org Git - postgresql/commitdiff
Reduce the number of semaphores used under --disable-spinlocks.
authorRobert Haas <rhaas@postgresql.org>
Wed, 8 Jan 2014 23:49:14 +0000 (18:49 -0500)
committerRobert Haas <rhaas@postgresql.org>
Wed, 8 Jan 2014 23:58:00 +0000 (18:58 -0500)
Instead of allocating a semaphore from the operating system for every
spinlock, allocate a fixed number of semaphores (by default, 1024)
from the operating system and multiplex all the spinlocks that get
created onto them.  This could self-deadlock if a process attempted
to acquire more than one spinlock at a time, but since processes
aren't supposed to execute anything other than short stretches of
straight-line code while holding a spinlock, that shouldn't happen.

One motivation for this change is that, with the introduction of
dynamic shared memory, it may be desirable to create spinlocks that
last for less than the lifetime of the server.  Without this change,
attempting to use such facilities under --disable-spinlocks would
quickly exhaust any supply of available semaphores.  Quite apart
from that, it's desirable to contain the quantity of semaphores
needed to run the server simply on convenience grounds, since using
too many may make it harder to get PostgreSQL running on a new
platform, which is mostly the point of --disable-spinlocks in the
first place.

Patch by me; review by Tom Lane.

src/backend/postmaster/postmaster.c
src/backend/storage/ipc/ipci.c
src/backend/storage/ipc/shmem.c
src/backend/storage/lmgr/spin.c
src/include/pg_config_manual.h
src/include/storage/s_lock.h
src/include/storage/spin.h

index 377fa591a8b3abb2152f07352bbadc5317ac0e8f..a7e40cc4a5989953ecb6398f1265498ddf99e0eb 100644 (file)
@@ -471,6 +471,9 @@ typedef struct
        slock_t    *ShmemLock;
        VariableCache ShmemVariableCache;
        Backend    *ShmemBackendArray;
+#ifndef HAVE_SPINLOCKS
+       PGSemaphore     SpinlockSemaArray;
+#endif
        LWLock     *LWLockArray;
        slock_t    *ProcStructLock;
        PROC_HDR   *ProcGlobal;
@@ -5626,6 +5629,9 @@ save_backend_variables(BackendParameters *param, Port *port,
        param->ShmemVariableCache = ShmemVariableCache;
        param->ShmemBackendArray = ShmemBackendArray;
 
+#ifndef HAVE_SPINLOCKS
+       param->SpinlockSemaArray = SpinlockSemaArray;
+#endif
        param->LWLockArray = LWLockArray;
        param->ProcStructLock = ProcStructLock;
        param->ProcGlobal = ProcGlobal;
@@ -5854,6 +5860,9 @@ restore_backend_variables(BackendParameters *param, Port *port)
        ShmemVariableCache = param->ShmemVariableCache;
        ShmemBackendArray = param->ShmemBackendArray;
 
+#ifndef HAVE_SPINLOCKS
+       SpinlockSemaArray = param->SpinlockSemaArray;
+#endif
        LWLockArray = param->LWLockArray;
        ProcStructLock = param->ProcStructLock;
        ProcGlobal = param->ProcGlobal;
index 1c8783f2c085e8151f5d46798d59c4ff871f0fa7..3c04fc31baed54f45ddbe852f901554e1b154ee3 100644 (file)
@@ -105,6 +105,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
                 * need to be so careful during the actual allocation phase.
                 */
                size = 100000;
+               size = add_size(size, SpinlockSemaSize());
                size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE,
                                                                                                 sizeof(ShmemIndexEnt)));
                size = add_size(size, BufferShmemSize());
index e93b988ad743d49cbc284617e346bb2820468851..70b02ca8384b87354aebe96f59a36ebdd8d073e5 100644 (file)
@@ -116,9 +116,24 @@ InitShmemAllocation(void)
        Assert(shmhdr != NULL);
 
        /*
-        * Initialize the spinlock used by ShmemAlloc.  We have to do the space
-        * allocation the hard way, since obviously ShmemAlloc can't be called
-        * yet.
+        * If spinlocks are disabled, initialize emulation layer.  We have to do
+        * the space allocation the hard way, since obviously ShmemAlloc can't be
+        * called yet.
+        */
+#ifndef HAVE_SPINLOCKS
+       {
+               PGSemaphore spinsemas;
+
+               spinsemas = (PGSemaphore) (((char *) shmhdr) + shmhdr->freeoffset);
+               shmhdr->freeoffset += MAXALIGN(SpinlockSemaSize());
+               SpinlockSemaInit(spinsemas);
+               Assert(shmhdr->freeoffset <= shmhdr->totalsize);
+       }
+#endif
+
+       /*
+        * Initialize the spinlock used by ShmemAlloc; we have to do this the hard
+        * way, too, for the same reasons as above.
         */
        ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
        shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
index 08782178de9d08d805505852bce1341a85be6c13..3d116bc7a2e4467184939216ed0100e1e8f7d5d4 100644 (file)
 #include "storage/spin.h"
 
 
+PGSemaphore SpinlockSemaArray;
+
+/*
+ * Report the amount of shared memory needed to store semaphores for spinlock
+ * support.
+ */
+Size
+SpinlockSemaSize(void)
+{
+       return SpinlockSemas() * sizeof(PGSemaphoreData);
+}
+
 #ifdef HAVE_SPINLOCKS
 
 /*
@@ -52,22 +64,20 @@ SpinlockSemas(void)
 int
 SpinlockSemas(void)
 {
-       int                     nsemas;
-
-       /*
-        * It would be cleaner to distribute this logic into the affected modules,
-        * similar to the way shmem space estimation is handled.
-        *
-        * For now, though, there are few enough users of spinlocks that we just
-        * keep the knowledge here.
-        */
-       nsemas = NumLWLocks();          /* one for each lwlock */
-       nsemas += NBuffers;                     /* one for each buffer header */
-       nsemas += max_wal_senders;      /* one for each wal sender process */
-       nsemas += num_xloginsert_slots; /* one for each WAL insertion slot */
-       nsemas += 30;                           /* plus a bunch for other small-scale use */
-
-       return nsemas;
+       return NUM_SPINLOCK_SEMAPHORES;
+}
+
+/*
+ * Initialize semaphores.
+ */
+extern void
+SpinlockSemaInit(PGSemaphore spinsemas)
+{
+       int     i;
+
+       for (i = 0; i < NUM_SPINLOCK_SEMAPHORES; ++i)
+               PGSemaphoreCreate(&spinsemas[i]);
+       SpinlockSemaArray = spinsemas;
 }
 
 /*
@@ -77,13 +87,15 @@ SpinlockSemas(void)
 void
 s_init_lock_sema(volatile slock_t *lock)
 {
-       PGSemaphoreCreate((PGSemaphore) lock);
+       static int counter = 0;
+
+       *lock = (++counter) % NUM_SPINLOCK_SEMAPHORES;
 }
 
 void
 s_unlock_sema(volatile slock_t *lock)
 {
-       PGSemaphoreUnlock((PGSemaphore) lock);
+       PGSemaphoreUnlock(&SpinlockSemaArray[*lock]);
 }
 
 bool
@@ -98,7 +110,7 @@ int
 tas_sema(volatile slock_t *lock)
 {
        /* Note that TAS macros return 0 if *success* */
-       return !PGSemaphoreTryLock((PGSemaphore) lock);
+       return !PGSemaphoreTryLock(&SpinlockSemaArray[*lock]);
 }
 
 #endif   /* !HAVE_SPINLOCKS */
index 2387a434aa45ead4b1c8b14f86c94cf53d804b72..20c5ff0e90298f04e4ef4dbacf159d7593cfb9c0 100644 (file)
  */
 #define NUM_USER_DEFINED_LWLOCKS       4
 
+/*
+ * When we don't have native spinlocks, we use semaphores to simulate them.
+ * Decreasing this value reduces consumption of OS resources; increasing it
+ * may improve performance, but supplying a real spinlock implementation is
+ * probably far better.
+ */
+#define        NUM_SPINLOCK_SEMAPHORES         1024
+
 /*
  * Define this if you want to allow the lo_import and lo_export SQL
  * functions to be executed by ordinary users. By default these
index b52f0e7f8523ba5586e6cdb0af38dfa11707fe80..2297f772805d8d17e19e3735005b6d27cf4626fd 100644 (file)
@@ -915,7 +915,7 @@ spin_delay(void)
  * to fall foul of kernel limits on number of semaphores, so don't use this
  * unless you must!  The subroutines appear in spin.c.
  */
-typedef PGSemaphoreData slock_t;
+typedef int slock_t;
 
 extern bool s_lock_free_sema(volatile slock_t *lock);
 extern void s_unlock_sema(volatile slock_t *lock);
index e7201652499735595bcdd5021cb6c1e633fa71e3..2ac510db7a036931d6b24f723467fd936aaa3aa3 100644 (file)
 
 
 extern int     SpinlockSemas(void);
+extern Size    SpinlockSemaSize(void);
+
+#ifndef HAVE_SPINLOCKS
+extern void    SpinlockSemaInit(PGSemaphore);
+extern PGSemaphore     SpinlockSemaArray;
+#endif
 
 #endif   /* SPIN_H */