Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 73f6b9a

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 6cf1647 commit 73f6b9a

File tree

1 file changed

+21
-14
lines changed

1 file changed

+21
-14
lines changed

src/backend/storage/ipc/latch.c

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,9 +1452,9 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
14521452
int rc;
14531453

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

1502-
break;
1502+
if (returned_events == nevents)
1503+
break; /* output buffer full already */
1504+
1505+
/*
1506+
* Even though we already have an event, we'll poll just once with
1507+
* zero timeout to see what non-latch events we can fit into the
1508+
* output buffer at the same time.
1509+
*/
1510+
cur_timeout = 0;
1511+
timeout = 0;
15031512
}
15041513

15051514
/*
@@ -1508,18 +1517,16 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
15081517
* to retry, everything >= 1 is the number of returned events.
15091518
*/
15101519
rc = WaitEventSetWaitBlock(set, cur_timeout,
1511-
occurred_events, nevents);
1520+
occurred_events, nevents - returned_events);
15121521

1513-
if (set->latch)
1514-
{
1515-
Assert(set->latch->maybe_sleeping);
1522+
if (set->latch &&
1523+
set->latch->maybe_sleeping)
15161524
set->latch->maybe_sleeping = false;
1517-
}
15181525

15191526
if (rc == -1)
15201527
break; /* timeout occurred */
15211528
else
1522-
returned_events = rc;
1529+
returned_events += rc;
15231530

15241531
/* If we're not done, update cur_timeout for next iteration */
15251532
if (returned_events == 0 && timeout >= 0)
@@ -1607,7 +1614,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
16071614
/* Drain the signalfd. */
16081615
drain();
16091616

1610-
if (set->latch && set->latch->is_set)
1617+
if (set->latch && set->latch->maybe_sleeping && set->latch->is_set)
16111618
{
16121619
occurred_events->fd = PGINVALID_SOCKET;
16131620
occurred_events->events = WL_LATCH_SET;
@@ -1766,7 +1773,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
17661773
if (cur_event->events == WL_LATCH_SET &&
17671774
cur_kqueue_event->filter == EVFILT_SIGNAL)
17681775
{
1769-
if (set->latch && set->latch->is_set)
1776+
if (set->latch && set->latch->maybe_sleeping && set->latch->is_set)
17701777
{
17711778
occurred_events->fd = PGINVALID_SOCKET;
17721779
occurred_events->events = WL_LATCH_SET;
@@ -1891,7 +1898,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
18911898
/* There's data in the self-pipe, clear it. */
18921899
drain();
18931900

1894-
if (set->latch && set->latch->is_set)
1901+
if (set->latch && set->latch->maybe_sleeping && set->latch->is_set)
18951902
{
18961903
occurred_events->fd = PGINVALID_SOCKET;
18971904
occurred_events->events = WL_LATCH_SET;
@@ -2107,7 +2114,7 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
21072114
if (!ResetEvent(set->handles[cur_event->pos + 1]))
21082115
elog(ERROR, "ResetEvent failed: error code %lu", GetLastError());
21092116

2110-
if (set->latch && set->latch->is_set)
2117+
if (set->latch && set->latch->maybe_sleeping && set->latch->is_set)
21112118
{
21122119
occurred_events->fd = PGINVALID_SOCKET;
21132120
occurred_events->events = WL_LATCH_SET;

0 commit comments

Comments
 (0)