From: Petr Jelinek <petr.jelinek@2ndquadrant.com>
To: Tom Lane <tgl@sss.pgh.pa.us>
To: Andrew Dunstan <andrew.dunstan@2ndquadrant.com>
Cc: Peter Eisentraut <peter.eisentraut@2ndquadrant.com>
Cc: pgsql-hackers@postgresql.org
Subject: Re: [COMMITTERS] pgsql: Use asynchronous connect API in libpqwalreceiver
Date: Fri, 17 Mar 2017 16:54:03 +0100
Message-ID: <5b6a6d6d-fb45-0afb-2e95-5600063c3dbd@2ndquadrant.com> (raw)
In-Reply-To: <10458.1489763266@sss.pgh.pa.us>
References: <E1cjo1g-0000mr-ST@gemulon.postgresql.org>
<19403.1488586564@sss.pgh.pa.us>
<34d98fbf-9195-04d2-b85a-634d6952ffdf@2ndquadrant.com>
<19815.1488600693@sss.pgh.pa.us>
<4144256b-dc4f-892c-a720-71f6e7b9ac87@2ndquadrant.com>
<dcef4616-21af-5ec0-4113-d409e5ddbf86@2ndquadrant.com>
<3ffe98f7-d2ed-65c6-51f3-4d97ffd6e312@2ndquadrant.com>
<e31d81e2-392a-dca0-a700-e28b583bd2d3@2ndQuadrant.com>
<34591606-976a-bbee-8eda-778c1e1fc52f@2ndQuadrant.com>
<10458.1489763266@sss.pgh.pa.us>
List-Unsubscribe: <mailto:majordomo@postgresql.org?body=unsub%20pgsql-hackers>
On 17/03/17 16:07, Tom Lane wrote:
> Andrew Dunstan <andrew.dunstan@2ndquadrant.com> writes:
>> I have confirmed on jacana Petr's observation that adding a timeout to
>> the WaitLatchOrSocket cures the problem.
>
> Does anyone have a theory as to why that cures the problem?
>
I now have theory and even PoC patch for it.
The long wait of WaitLatchOrSocket happens after connection state
switches from CONNECTION_STARTED to CONNECTION_MADE in both cases the
return value of PQconnectPoll is PGRES_POLLING_WRITING so we wait for
FD_WRITE.
Now the documentation for WSAEventSelect says "The FD_WRITE network
event is handled slightly differently. An FD_WRITE network event is
recorded when a socket is first connected with a call to the connect,
ConnectEx, WSAConnect, WSAConnectByList, or WSAConnectByName function or
when a socket is accepted with accept, AcceptEx, or WSAAccept function
and then after a send fails with WSAEWOULDBLOCK and buffer space becomes
available. Therefore, an application can assume that sends are possible
starting from the first FD_WRITE network event setting and lasting until
a send returns WSAEWOULDBLOCK. After such a failure the application will
find out that sends are again possible when an FD_WRITE network event is
recorded and the associated event object is set."
But while PQconnectPoll does connect() before setting connection status
to CONNECTION_STARTED and returns PGRES_POLLING_WRITING so the FD_WRITE
eventually happens, it does not do any writes in the code block that
switches to CONNECTION_MADE and PGRES_POLLING_WRITING. That means
FD_WRITE event is never recorded as per quoted documentation.
Then what remains is why it works in libpq. If you look at
pgwin32_select which is eventually called by libpq code, it actually
handles the situation by trying empty WSASend on any socket that is
supposed to wait for FD_WRITE and only calling the
WaitForMultipleObjectsEx when WSASend failed with WSAEWOULDBLOCK, when
the WSASend succeeds it immediately returns ok.
So I did something similar in attached for WaitEventSetWaitBlock() and
it indeed solves the issue my windows test machine. Now the
coding/placement probably isn't the best (and there are no comments),
but maybe somebody will find proper place for this now that we know the
cause.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackersAttachments:
[text/x-patch] fix-wait-for-writable-socket-on-windows.patch (1.1K, ../5b6a6d6d-fb45-0afb-2e95-5600063c3dbd@2ndquadrant.com/2-fix-wait-for-writable-socket-on-windows.patch)
download | inline diff:diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.cindex ea7f930..300b866 100644--- a/src/backend/storage/ipc/latch.c+++ b/src/backend/storage/ipc/latch.c@@ -1401,6 +1401,37 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
WaitEventAdjustWin32(set, cur_event);
cur_event->reset = false;
}
++ if (cur_event->events & WL_SOCKET_WRITEABLE)+ {+ char c;+ WSABUF buf;+ DWORD sent;+ int r;++ buf.buf = &c;+ buf.len = 0;++ r = WSASend(cur_event->fd, &buf, 1, &sent, 0, NULL, NULL);+ if (r == 0)+ {+ occurred_events->pos = cur_event->pos;+ occurred_events->user_data = cur_event->user_data;+ occurred_events->events = WL_SOCKET_WRITEABLE;+ occurred_events->fd = cur_event->fd;+ return 1;+ }+ else+ {+ if (WSAGetLastError() != WSAEWOULDBLOCK)+ /*+ * Not completed, and not just "would block", so an error+ * occurred+ */+ elog(ERROR, "failed writability check on socket: error code %u",+ WSAGetLastError());+ }+ }
}
/*
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-committers@postgresql.org
Cc: petr.jelinek@2ndquadrant.com, tgl@sss.pgh.pa.us, andrew.dunstan@2ndquadrant.com, peter.eisentraut@2ndquadrant.com, pgsql-hackers@postgresql.org
Subject: Re: [COMMITTERS] pgsql: Use asynchronous connect API in libpqwalreceiver
In-Reply-To: <5b6a6d6d-fb45-0afb-2e95-5600063c3dbd@2ndquadrant.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox