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

Commit 98a64d0

Browse files
committed
Introduce WaitEventSet API.
Commit ac1d794 ("Make idle backends exit if the postmaster dies.") introduced a regression on, at least, large linux systems. Constantly adding the same postmaster_alive_fds to the OSs internal datastructures for implementing poll/select can cause significant contention; leading to a performance regression of nearly 3x in one example. This can be avoided by using e.g. linux' epoll, which avoids having to add/remove file descriptors to the wait datastructures at a high rate. Unfortunately the current latch interface makes it hard to allocate any persistent per-backend resources. Replace, with a backward compatibility layer, WaitLatchOrSocket with a new WaitEventSet API. Users can allocate such a Set across multiple calls, and add more than one file-descriptor to wait on. The latter has been added because there's upcoming postgres features where that will be helpful. In addition to the previously existing poll(2), select(2), WaitForMultipleObjects() implementations also provide an epoll_wait(2) based implementation to address the aforementioned performance problem. Epoll is only available on linux, but that is the most likely OS for machines large enough (four sockets) to reproduce the problem. To actually address the aforementioned regression, create and use a long-lived WaitEventSet for FE/BE communication. There are additional places that would benefit from a long-lived set, but that's a task for another day. Thanks to Amit Kapila, who helped make the windows code I blindly wrote actually work. Reported-By: Dmitry Vasilyev Discussion: CAB-SwXZh44_2ybvS5Z67p_CDz=XFn4hNAD=CnMEF+QqkXwFrGg@mail.gmail.com 20160114143931.GG10941@awork2.anarazel.de
1 parent 72e2d21 commit 98a64d0

File tree

10 files changed

+1171
-530
lines changed

10 files changed

+1171
-530
lines changed

configure

+1-1
Original file line numberDiff line numberDiff line change
@@ -10193,7 +10193,7 @@ fi
1019310193
## Header files
1019410194
##
1019510195

10196-
for ac_header in atomic.h crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h pwd.h sys/ioctl.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/socket.h sys/sockio.h sys/tas.h sys/time.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h
10196+
for ac_header in atomic.h crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h pwd.h sys/epoll.h sys/ioctl.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/socket.h sys/sockio.h sys/tas.h sys/time.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h
1019710197
do :
1019810198
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
1019910199
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"

configure.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,7 @@ AC_SUBST(UUID_LIBS)
11831183
##
11841184

11851185
dnl sys/socket.h is required by AC_FUNC_ACCEPT_ARGTYPES
1186-
AC_CHECK_HEADERS([atomic.h crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h pwd.h sys/ioctl.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/socket.h sys/sockio.h sys/tas.h sys/time.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h])
1186+
AC_CHECK_HEADERS([atomic.h crypt.h dld.h fp_class.h getopt.h ieeefp.h ifaddrs.h langinfo.h mbarrier.h poll.h pwd.h sys/epoll.h sys/ioctl.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/socket.h sys/sockio.h sys/tas.h sys/time.h sys/un.h termios.h ucred.h utime.h wchar.h wctype.h])
11871187

11881188
# On BSD, test for net/if.h will fail unless sys/socket.h
11891189
# is included first.

src/backend/libpq/be-secure.c

+12-12
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,13 @@ secure_read(Port *port, void *ptr, size_t len)
140140
/* In blocking mode, wait until the socket is ready */
141141
if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
142142
{
143-
int w;
143+
WaitEvent event;
144144

145145
Assert(waitfor);
146146

147-
w = WaitLatchOrSocket(MyLatch,
148-
WL_LATCH_SET | WL_POSTMASTER_DEATH | waitfor,
149-
port->sock, 0);
147+
ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);
148+
149+
WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */, &event, 1);
150150

151151
/*
152152
* If the postmaster has died, it's not safe to continue running,
@@ -165,13 +165,13 @@ secure_read(Port *port, void *ptr, size_t len)
165165
* cycles checking for this very rare condition, and this should cause
166166
* us to exit quickly in most cases.)
167167
*/
168-
if (w & WL_POSTMASTER_DEATH)
168+
if (event.events & WL_POSTMASTER_DEATH)
169169
ereport(FATAL,
170170
(errcode(ERRCODE_ADMIN_SHUTDOWN),
171171
errmsg("terminating connection due to unexpected postmaster exit")));
172172

173173
/* Handle interrupt. */
174-
if (w & WL_LATCH_SET)
174+
if (event.events & WL_LATCH_SET)
175175
{
176176
ResetLatch(MyLatch);
177177
ProcessClientReadInterrupt(true);
@@ -241,22 +241,22 @@ secure_write(Port *port, void *ptr, size_t len)
241241

242242
if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
243243
{
244-
int w;
244+
WaitEvent event;
245245

246246
Assert(waitfor);
247247

248-
w = WaitLatchOrSocket(MyLatch,
249-
WL_LATCH_SET | WL_POSTMASTER_DEATH | waitfor,
250-
port->sock, 0);
248+
ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);
249+
250+
WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */, &event, 1);
251251

252252
/* See comments in secure_read. */
253-
if (w & WL_POSTMASTER_DEATH)
253+
if (event.events & WL_POSTMASTER_DEATH)
254254
ereport(FATAL,
255255
(errcode(ERRCODE_ADMIN_SHUTDOWN),
256256
errmsg("terminating connection due to unexpected postmaster exit")));
257257

258258
/* Handle interrupt. */
259-
if (w & WL_LATCH_SET)
259+
if (event.events & WL_LATCH_SET)
260260
{
261261
ResetLatch(MyLatch);
262262
ProcessClientWriteInterrupt(true);

src/backend/libpq/pqcomm.c

+5
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ pq_init(void)
201201
(errmsg("could not set socket to nonblocking mode: %m")));
202202
#endif
203203

204+
FeBeWaitSet = CreateWaitEventSet(TopMemoryContext, 3);
205+
AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE, MyProcPort->sock,
206+
NULL, NULL);
207+
AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, -1, MyLatch, NULL);
208+
AddWaitEventToSet(FeBeWaitSet, WL_POSTMASTER_DEATH, -1, NULL, NULL);
204209
}
205210

206211
/* --------------------------------

0 commit comments

Comments
 (0)