mirror of
https://github.com/postgres/postgres.git
synced 2025-07-27 12:41:57 +03:00
Use a nonblocking socket for FE/BE communication and block using latches.
This allows to introduce more elaborate handling of interrupts while reading from a socket. Currently some interrupt handlers have to do significant work from inside signal handlers, and it's very hard to correctly write code to do so. Generic signal handler limitations, combined with the fact that we can't safely jump out of a signal handler while reading from the client have prohibited implementation of features like timeouts for idle-in-transaction. Additionally we use the latch code to wait in a couple places where we previously only had waiting code on windows as other platforms just busy looped. This can increase the number of systemcalls happening during FE/BE communication. Benchmarks so far indicate that the impact isn't very high, and there's room for optimization in the latch code. The chance of cleaning up the usage of latches gives us, seem to outweigh the risk of small performance regressions. This commit theoretically can't used without the next patch in the series, as WaitLatchOrSocket is not defined to be fully signal safe. As we already do that in some cases though, it seems better to keep the commits separate, so they're easier to understand. Author: Andres Freund Reviewed-By: Heikki Linnakangas
This commit is contained in:
@ -181,6 +181,22 @@ pq_init(void)
|
||||
PqCommReadingMsg = false;
|
||||
DoingCopyOut = false;
|
||||
on_proc_exit(socket_close, 0);
|
||||
|
||||
/*
|
||||
* In backends (as soon as forked) we operate the underlying socket in
|
||||
* nonblocking mode and use latches to implement blocking semantics if
|
||||
* needed. That allows us to provide safely interruptible reads.
|
||||
*
|
||||
* Use COMMERROR on failure, because ERROR would try to send the error to
|
||||
* the client, which might require changing the mode again, leading to
|
||||
* infinite recursion.
|
||||
*/
|
||||
#ifndef WIN32
|
||||
if (!pg_set_noblock(MyProcPort->sock))
|
||||
ereport(COMMERROR,
|
||||
(errmsg("could not set socket to nonblocking mode: %m")));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
@ -820,31 +836,6 @@ socket_set_nonblocking(bool nonblocking)
|
||||
(errcode(ERRCODE_CONNECTION_DOES_NOT_EXIST),
|
||||
errmsg("there is no client connection")));
|
||||
|
||||
if (MyProcPort->noblock == nonblocking)
|
||||
return;
|
||||
|
||||
#ifdef WIN32
|
||||
pgwin32_noblock = nonblocking ? 1 : 0;
|
||||
#else
|
||||
|
||||
/*
|
||||
* Use COMMERROR on failure, because ERROR would try to send the error to
|
||||
* the client, which might require changing the mode again, leading to
|
||||
* infinite recursion.
|
||||
*/
|
||||
if (nonblocking)
|
||||
{
|
||||
if (!pg_set_noblock(MyProcPort->sock))
|
||||
ereport(COMMERROR,
|
||||
(errmsg("could not set socket to nonblocking mode: %m")));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pg_set_block(MyProcPort->sock))
|
||||
ereport(COMMERROR,
|
||||
(errmsg("could not set socket to blocking mode: %m")));
|
||||
}
|
||||
#endif
|
||||
MyProcPort->noblock = nonblocking;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user