Optimize latches to send fewer signals.
authorThomas Munro <tmunro@postgresql.org>
Sun, 28 Feb 2021 22:51:15 +0000 (11:51 +1300)
committerThomas Munro <tmunro@postgresql.org>
Sun, 28 Feb 2021 23:44:12 +0000 (12:44 +1300)
Don't send signals to processes that aren't sleeping.

Author: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CA+hUKGJjxPDpzBE0a3hyUywBvaZuC89yx3jK9RFZgfv_KHU7gg@mail.gmail.com

src/backend/storage/ipc/latch.c
src/include/storage/latch.h

index 79b9627831fcadd07d6d0a4378a7f12988bc24aa..eacf8d51ea0833462966b151f46f099630e10ba2 100644 (file)
@@ -274,6 +274,7 @@ void
 InitLatch(Latch *latch)
 {
    latch->is_set = false;
+   latch->maybe_sleeping = false;
    latch->owner_pid = MyProcPid;
    latch->is_shared = false;
 
@@ -321,6 +322,7 @@ InitSharedLatch(Latch *latch)
 #endif
 
    latch->is_set = false;
+   latch->maybe_sleeping = false;
    latch->owner_pid = 0;
    latch->is_shared = true;
 }
@@ -523,6 +525,10 @@ SetLatch(Latch *latch)
 
    latch->is_set = true;
 
+   pg_memory_barrier();
+   if (!latch->maybe_sleeping)
+       return;
+
 #ifndef WIN32
 
    /*
@@ -589,6 +595,7 @@ ResetLatch(Latch *latch)
 {
    /* Only the owner should reset the latch */
    Assert(latch->owner_pid == MyProcPid);
+   Assert(latch->maybe_sleeping == false);
 
    latch->is_set = false;
 
@@ -1270,6 +1277,14 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
         * ordering, so that we cannot miss seeing is_set if a notification
         * has already been queued.
         */
+       if (set->latch && !set->latch->is_set)
+       {
+           /* about to sleep on a latch */
+           set->latch->maybe_sleeping = true;
+           pg_memory_barrier();
+           /* and recheck */
+       }
+
        if (set->latch && set->latch->is_set)
        {
            occurred_events->fd = PGINVALID_SOCKET;
@@ -1280,6 +1295,9 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
            occurred_events++;
            returned_events++;
 
+           /* could have been set above */
+           set->latch->maybe_sleeping = false;
+
            break;
        }
 
@@ -1291,6 +1309,12 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
        rc = WaitEventSetWaitBlock(set, cur_timeout,
                                   occurred_events, nevents);
 
+       if (set->latch)
+       {
+           Assert(set->latch->maybe_sleeping);
+           set->latch->maybe_sleeping = false;
+       }
+
        if (rc == -1)
            break;              /* timeout occurred */
        else
index 1468f30a8e00e50ed9bfa8983d6a40ffc8ca6fec..393591be03c098103e6bc0ede4061e05dc7066b0 100644 (file)
 typedef struct Latch
 {
    sig_atomic_t is_set;
+   sig_atomic_t maybe_sleeping;
    bool        is_shared;
    int         owner_pid;
 #ifdef WIN32