Skip to content

Commit 44f400f

Browse files
committed
Fix latch event policy that hid socket events.
If a WaitEventSetWait() caller asks for multiple events, an already set latch would previously prevent other events from being reported at the same time. Now, we'll also poll the kernel for other events that would fit in the caller's output buffer with a zero wait time. This policy change doesn't affect callers that ask for only one event. The main caller affected is the postmaster. If its latch is set extremely frequently by backends launching workers and workers exiting, we don't want it to handle only those jobs and ignore incoming client connections. Back-patch to 16 where the postmaster began using the API. The fast-return policy changed here is older than that, but doesn't cause any known problems in earlier releases. Reported-by: Nathan Bossart <nathandbossart@gmail.com> Reviewed-by: Nathan Bossart <nathandbossart@gmail.com> Discussion: https://postgr.es/m/Z1n5UpAiGDmFcMmd%40nathan
1 parent e6767c0 commit 44f400f

File tree

1 file changed

+21
-14
lines changed

1 file changed

+21
-14
lines changed

src/backend/storage/ipc/latch.c

+21-14
Original file line numberDiff line numberDiff line change
@@ -1458,9 +1458,9 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
14581458
int rc;
14591459

14601460
/*
1461-
* Check if the latch is set already. If so, leave the loop
1462-
* immediately, avoid blocking again. We don't attempt to report any
1463-
* other events that might also be satisfied.
1461+
* Check if the latch is set already first. If so, we either exit
1462+
* immediately or ask the kernel for further events available right
1463+
* now without waiting, depending on how many events the caller wants.
14641464
*
14651465
* If someone sets the latch between this and the
14661466
* WaitEventSetWaitBlock() below, the setter will write a byte to the
@@ -1505,7 +1505,16 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
15051505
/* could have been set above */
15061506
set->latch->maybe_sleeping = false;
15071507

1508-
break;
1508+
if (returned_events == nevents)
1509+
break; /* output buffer full already */
1510+
1511+
/*
1512+
* Even though we already have an event, we'll poll just once with
1513+
* zero timeout to see what non-latch events we can fit into the
1514+
* output buffer at the same time.
1515+
*/
1516+
cur_timeout = 0;
1517+
timeout = 0;
15091518
}
15101519

15111520
/*
@@ -1514,18 +1523,16 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
15141523
* to retry, everything >= 1 is the number of returned events.
15151524
*/
15161525
rc = WaitEventSetWaitBlock(set, cur_timeout,
1517-
occurred_events, nevents);
1526+
occurred_events, nevents - returned_events);
15181527

1519-
if (set->latch)
1520-
{
1521-
Assert(set->latch->maybe_sleeping);
1528+
if (set->latch &&
1529+
set->latch->maybe_sleeping)
15221530
set->latch->maybe_sleeping = false;
1523-
}
15241531

15251532
if (rc == -1)
15261533
break; /* timeout occurred */
15271534
else
1528-
returned_events = rc;
1535+
returned_events += rc;
15291536

15301537
/* If we're not done, update cur_timeout for next iteration */
15311538
if (returned_events == 0 && timeout >= 0)
@@ -1613,7 +1620,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
16131620
/* Drain the signalfd. */
16141621
drain();
16151622

1616-
if (set->latch && set->latch->is_set)
1623+
if (set->latch && set->latch->maybe_sleeping && set->latch->is_set)
16171624
{
16181625
occurred_events->fd = PGINVALID_SOCKET;
16191626
occurred_events->events = WL_LATCH_SET;
@@ -1772,7 +1779,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
17721779
if (cur_event->events == WL_LATCH_SET &&
17731780
cur_kqueue_event->filter == EVFILT_SIGNAL)
17741781
{
1775-
if (set->latch && set->latch->is_set)
1782+
if (set->latch && set->latch->maybe_sleeping && set->latch->is_set)
17761783
{
17771784
occurred_events->fd = PGINVALID_SOCKET;
17781785
occurred_events->events = WL_LATCH_SET;
@@ -1897,7 +1904,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
18971904
/* There's data in the self-pipe, clear it. */
18981905
drain();
18991906

1900-
if (set->latch && set->latch->is_set)
1907+
if (set->latch && set->latch->maybe_sleeping && set->latch->is_set)
19011908
{
19021909
occurred_events->fd = PGINVALID_SOCKET;
19031910
occurred_events->events = WL_LATCH_SET;
@@ -2113,7 +2120,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
21132120
if (!ResetEvent(set->handles[cur_event->pos + 1]))
21142121
elog(ERROR, "ResetEvent failed: error code %lu", GetLastError());
21152122

2116-
if (set->latch && set->latch->is_set)
2123+
if (set->latch && set->latch->maybe_sleeping && set->latch->is_set)
21172124
{
21182125
occurred_events->fd = PGINVALID_SOCKET;
21192126
occurred_events->events = WL_LATCH_SET;

0 commit comments

Comments
 (0)