pgpool2.git / summary / log / commit / refs
commit 7087e257ff6f0949f25eb8cdc396b26a4158ea58
Author: Tatsuo Ishii <ishii@postgresql.org>
Date: Tue Dec 20 01:28:20 2016 +0000
Fix packet kind does not match error in extended protocol per bug 231.
According to the bug231, the bug seem to bite you if all of following
conditions are met:
- Streaming replication mode
- Load balance node is not node 0
- Extended protocol is used
- SELECT is executed, the statement is closed, then a transaction
command is executed
The sequence of how the problem bites is:
1) SELECT executes on statement S1 on the load balance node 1
2) Frontend send Close statement
3) Pgool-II forward it to backend 1
4) Frontend sends Parse, Bind, Execute of COMMIT
5) Pgool-II forward it to backend 0 & 1
6) Frontend sends sync message
7) Pgool-II forward it to backend 0 & 1
8) Backend 0 replies back Parse complete ("1"), while backend 1
replies back close complete ("3") because of #3.
9) Kind mismatch occurs
The solution is, in #3, let Pgpool-II wait for response from backend
1, but do not read the response message. Later on Pgpool-II's state
machine will read the response from it before the sync message is sent
in #6. With this, backend 1 will reply back "1" in #8, and the kind
mismatch error does not occur.
Also, fix not calling pool_set_doing_extended_query_message() when
receives Close message. (I don't know why it was missed).
New regression test "067.bug231" was added.
src/context/pool_query_context.c | 5 ++-
src/protocol/pool_proto_modules.c | 5 +--
.../regression/tests/067.bug231/TestReplGap.java | 29 +++++++++++++++
src/test/regression/tests/067.bug231/test.sh | 41 ++++++++++++++++++++++
4 files changed, 77 insertions(+), 3 deletions(-)
diff --git a/src/context/pool_query_context.c b/src/context/pool_query_context.c
index fabc4d742..15a5fe337 100644
--- a/src/context/pool_query_context.c
+++ b/src/context/pool_query_context.c
@@ -920,7 +920,7 @@ POOL_STATUS pool_extended_send_and_wait(POOL_QUERY_CONTEXT *query_context,
send_extended_protocol_message(backend, i, kind, str_len, str);
- if (*kind == 'E' && STREAM)
+ if ((*kind == 'E' || *kind == 'C') && STREAM)
{
/*
* Send flush message to backend to make sure that we get any response
@@ -933,6 +933,9 @@ POOL_STATUS pool_extended_send_and_wait(POOL_QUERY_CONTEXT *query_context,
pool_write(cp, "H", 1);
len = htonl(sizeof(len));
pool_write_and_flush(cp, &len, sizeof(len));
+
+ ereport(DEBUG1,
+ (errmsg("pool_send_and_wait: send flush message to %d", i)));
}
}
diff --git a/src/protocol/pool_proto_modules.c b/src/protocol/pool_proto_modules.c
index c4115f89b..d9bbca41f 100644
--- a/src/protocol/pool_proto_modules.c
+++ b/src/protocol/pool_proto_modules.c
@@ -1510,8 +1510,8 @@ POOL_STATUS Close(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend,
POOL_PENDING_MESSAGE *pmsg;
pool_clear_sync_map();
- pool_extended_send_and_wait(query_context, "C", len, contents, 1, MASTER_NODE_ID, true);
- pool_extended_send_and_wait(query_context, "C", len, contents, -1, MASTER_NODE_ID, true);
+ pool_extended_send_and_wait(query_context, "C", len, contents, 1, MASTER_NODE_ID, false);
+ pool_extended_send_and_wait(query_context, "C", len, contents, -1, MASTER_NODE_ID, false);
pmsg = pool_pending_messages_create('C', len, contents);
pool_pending_message_add(pmsg);
@@ -2415,6 +2415,7 @@ POOL_STATUS ProcessFrontendResponse(POOL_CONNECTION *frontend,
break;
case 'C': /* Close */
+ pool_set_doing_extended_query_message();
if (!pool_is_query_in_progress() && !pool_is_ignore_till_sync())
pool_set_query_in_progress();
status = Close(frontend, backend, len, contents);
diff --git a/src/test/regression/tests/067.bug231/TestReplGap.java b/src/test/regression/tests/067.bug231/TestReplGap.java
new file mode 100644
index 000000000..2aaa17dbf
--- /dev/null
+++ b/src/test/regression/tests/067.bug231/TestReplGap.java
@@ -0,0 +1,29 @@
+import java.sql.*;
+
+public class TestReplGap {
+
+ public static void main(String[] args) throws SQLException, InterruptedException {
+
+ try (Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:11000/test?loglevel=2", "t-ishii", "")) {
+
+ conn.setAutoCommit(false);
+ // Note: It is supposed that the database postgres contains table "t1".
+ try (PreparedStatement stmt = conn.prepareStatement("select * from t1 where id = ? ")) {
+
+ for (int i = 0; i < 100; i++) {
+ stmt.setInt(1, i);
+ stmt.executeQuery().close();
+
+ System.out.println(i);
+ }
+ }
+
+ conn.commit();
+ conn.close();
+
+ System.out.println("DONE");
+ } catch (SQLException ex) {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/test/regression/tests/067.bug231/test.sh b/src/test/regression/tests/067.bug231/test.sh
new file mode 100755
index 000000000..6e2722454
--- /dev/null
+++ b/src/test/regression/tests/067.bug231/test.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+#-------------------------------------------------------------------
+# test script for for bug 231 (packet kind of backend 1 ['3'] does not
+# match with master/majority nodes packet kind ['2']).
+#
+source $TESTLIBS
+TESTDIR=testdir
+PSQL=$PGBIN/psql
+export CLASSPATH=.:$JDBC_DRIVER
+
+rm -fr $TESTDIR
+mkdir $TESTDIR
+cd $TESTDIR
+
+# create test environment
+echo -n "creating test environment..."
+$PGPOOL_SETUP -m s -n 2 || exit 1
+echo "done."
+echo "backend_weight0 = 0" >> etc/pgpool.conf
+echo "backend_weight1 = 1" >> etc/pgpool.conf
+
+source ./bashrc.ports
+./startall
+export PGPORT=$PGPOOL_PORT
+wait_for_pgpool_startup
+
+export PGPORT=11000
+psql -c "DROP TABLE IF EXISTS t1" test
+psql -c "CREATE TABLE t1 (id int);" test
+psql -c "INSERT INTO t1 VALUES(1)" test
+
+TestProg=TestReplGap
+cp ../$TestProg.java .
+javac $TestProg.java
+java $TestProg > $TestProg.log 2>&1
+if [ $? != 0 ];then
+ ./shutdownall; exit 1;
+fi
+./shutdownall
+
+exit 0
[parent: f6659fb39948]