Fix extended query hang in certain case.
authorTatsuo Ishii <ishii@postgresql.org>
Tue, 23 May 2017 00:06:29 +0000 (09:06 +0900)
committerTatsuo Ishii <ishii@postgresql.org>
Tue, 23 May 2017 00:06:29 +0000 (09:06 +0900)
While digging into "[pgpool-general: 5487] pgpool and erlang - request hangs",
http://www.pgpool.net/pipermail/pgpool-general/2017-May/005545.html
I found a certain sequence of messages which cause Pgpool-II hang.

errlang PostgreSQL API produces Parse ('P'), Describe ('D'), Flush
('H'), Bind ('B'), and Execute ('E'). Notice the 'H' message (this
does not happen in JDBC. I suspect that's the reason why this problem
is not popular before). After that, Pgpool-II dropped the extended
query mode, it failed to find which backend to read data. Thus
Pgpool-II simply tries to read all of backend which causes hang
because it may have not send a message to some of backends.

Solution is, after receiving the flush message set doing extended
query flag.

For the record, here is the pgproto data to reproduce the problem.

--------------------------------------------------------
'Q' "DROP TABLE IF EXISTS pgproto_test1"
'Y'
'Q' "CREATE TABLE pgproto_test1(i INT)"
'Y'
'Q' "INSERT INTO pgproto_test1 VALUES(1)"
'Y'

'P' "S2" "SELECT 1 FROM pgproto_test1" 0
'D' 'S' "S2"
'H'
'B' "" "S2" 0 0 0
'E' "" 0
'C' 'S' "S2"

'S'
'Y'
'X'
--------------------------------------------------------

Note that the cause of original complain seems to different from this
because it is operated in replication mode. So it needs more
investigation.

Back patched to 3.6 and 3.5 stable branches.

src/protocol/pool_proto_modules.c

index 672e507a50c8c984886d5317e6e88b7ae3751189..93f309bf53ee32fdc5ccef21cf954d25ca2b9209 100644 (file)
@@ -2477,6 +2477,10 @@ POOL_STATUS ProcessFrontendResponse(POOL_CONNECTION *frontend,
                case 'H':       /* Flush */
                        if (MAJOR(backend) == PROTO_MAJOR_V3)
                        {
+                               if (fkind == 'H')
+                               {
+                                       pool_set_doing_extended_query_message();
+                               }
                                status = SimpleForwardToBackend(fkind, frontend, backend, len, contents);
                                break;
                        }