summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Deolasee2016-03-09 12:18:23 +0000
committerPavan Deolasee2016-10-18 10:00:19 +0000
commitfc88a9adc7a027c22e300bfc6bfc0f97128f97e1 (patch)
tree9056b9a70168233aab5e78c9969c13011e3e2766
parent7aecc3a15b64df4da5dfa3d458f9dd0f959030bd (diff)
Send down SYNC message to a failed remote session that was running extended
query protocol. While running extended query protocol, a backend that has thrown an error will keep ignoring all messages until it sees a SYNC message. We now carefully track the messages that we are sending to the remote node and remember if we must send a SYNC message even before sending a ROLLBACK command. While the regression was running fine even without this patch, this issue was noticed as part of some other work and hence fixed
-rw-r--r--src/backend/pgxc/pool/execRemote.c28
-rw-r--r--src/backend/pgxc/pool/pgxcnode.c12
-rw-r--r--src/include/pgxc/pgxcnode.h3
3 files changed, 43 insertions, 0 deletions
diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c
index eb3807c70e..ab0a96986c 100644
--- a/src/backend/pgxc/pool/execRemote.c
+++ b/src/backend/pgxc/pool/execRemote.c
@@ -1718,6 +1718,15 @@ handle_response(PGXCNodeHandle *conn, ResponseCombiner *combiner)
case 'E': /* ErrorResponse */
HandleError(combiner, msg, msg_len, conn);
add_error_message(conn, combiner->errorMessage);
+ /*
+ * In case the remote node was running an extended query
+ * protocol and reported an error, it will keep ignoring all
+ * subsequent commands until it sees a SYNC message. So make
+ * sure that we send down SYNC even before sending a ROLLBACK
+ * command
+ */
+ if (conn->in_extended_query)
+ conn->needSync = true;
return RESPONSE_ERROR;
case 'A': /* NotificationResponse */
case 'N': /* NoticeResponse */
@@ -2638,6 +2647,16 @@ pgxc_node_remote_abort(void)
BufferConnection(conn);
/*
+ * If the remote session was running extended query protocol when
+ * it failed, it will expect a SYNC message before it accepts any
+ * other command
+ */
+ if (conn->needSync)
+ {
+ pgxc_node_send_sync(conn);
+ pgxc_node_receive(1, &conn, NULL);
+ }
+ /*
* Do not matter, is there committed or failed transaction,
* just send down rollback to finish it.
*/
@@ -2664,6 +2683,12 @@ pgxc_node_remote_abort(void)
if (conn->transaction_status != 'I')
{
+ /* Send SYNC if the remote session is expecting one */
+ if (conn->needSync)
+ {
+ pgxc_node_send_sync(conn);
+ pgxc_node_receive(1, &conn, NULL);
+ }
/*
* Do not matter, is there committed or failed transaction,
* just send down rollback to finish it.
@@ -2902,6 +2927,8 @@ DataNodeCopyIn(char *data_row, int len, int conn_count, PGXCNodeHandle** copy_co
memcpy(handle->outBuffer + handle->outEnd, data_row, len);
handle->outEnd += len;
handle->outBuffer[handle->outEnd++] = '\n';
+
+ handle->in_extended_query = false;
}
else
{
@@ -3045,6 +3072,7 @@ DataNodeCopyEnd(PGXCNodeHandle *handle, bool is_error)
memcpy(handle->outBuffer + handle->outEnd, &nLen, 4);
handle->outEnd += 4;
+ handle->in_extended_query = false;
/* We need response right away, so send immediately */
if (pgxc_node_flush(handle) < 0)
return true;
diff --git a/src/backend/pgxc/pool/pgxcnode.c b/src/backend/pgxc/pool/pgxcnode.c
index 87a2f6167f..579cb4b30a 100644
--- a/src/backend/pgxc/pool/pgxcnode.c
+++ b/src/backend/pgxc/pool/pgxcnode.c
@@ -143,6 +143,7 @@ init_pgxc_handle(PGXCNodeHandle *pgxc_handle)
pgxc_handle->inEnd = 0;
pgxc_handle->inCursor = 0;
pgxc_handle->outEnd = 0;
+ pgxc_handle->needSync = false;
if (pgxc_handle->outBuffer == NULL || pgxc_handle->inBuffer == NULL)
{
@@ -415,6 +416,7 @@ pgxc_node_init(PGXCNodeHandle *handle, int sock, bool global_session, int pid)
handle->inStart = 0;
handle->inEnd = 0;
handle->inCursor = 0;
+ handle->needSync = false;
/*
* We got a new connection, set on the remote node the session parameters
* if defined. The transaction parameter should be sent after BEGIN
@@ -1325,6 +1327,7 @@ pgxc_node_send_plan(PGXCNodeHandle * handle, const char *statement,
}
pfree(paramTypes);
+ handle->in_extended_query = true;
return 0;
}
@@ -1405,6 +1408,7 @@ pgxc_node_send_bind(PGXCNodeHandle * handle, const char *portal,
handle->outBuffer[handle->outEnd++] = 0;
handle->outBuffer[handle->outEnd++] = 0;
+ handle->in_extended_query = true;
return 0;
}
@@ -1452,6 +1456,7 @@ pgxc_node_send_describe(PGXCNodeHandle * handle, bool is_statement,
else
handle->outBuffer[handle->outEnd++] = '\0';
+ handle->in_extended_query = true;
return 0;
}
@@ -1492,6 +1497,7 @@ pgxc_node_send_close(PGXCNodeHandle * handle, bool is_statement,
else
handle->outBuffer[handle->outEnd++] = '\0';
+ handle->in_extended_query = true;
return 0;
}
@@ -1535,6 +1541,7 @@ pgxc_node_send_execute(PGXCNodeHandle * handle, const char *portal, int fetch)
PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_QUERY);
+ handle->in_extended_query = true;
return 0;
}
@@ -1561,6 +1568,7 @@ pgxc_node_send_flush(PGXCNodeHandle * handle)
memcpy(handle->outBuffer + handle->outEnd, &msgLen, 4);
handle->outEnd += 4;
+ handle->in_extended_query = true;
return pgxc_node_flush(handle);
}
@@ -1587,6 +1595,9 @@ pgxc_node_send_sync(PGXCNodeHandle * handle)
memcpy(handle->outBuffer + handle->outEnd, &msgLen, 4);
handle->outEnd += 4;
+ handle->in_extended_query = false;
+ handle->needSync = false;
+
return pgxc_node_flush(handle);
}
@@ -1721,6 +1732,7 @@ pgxc_node_send_query_internal(PGXCNodeHandle * handle, const char *query,
PGXCNodeSetConnectionState(handle, DN_CONNECTION_STATE_QUERY);
+ handle->in_extended_query = false;
return pgxc_node_flush(handle);
}
diff --git a/src/include/pgxc/pgxcnode.h b/src/include/pgxc/pgxcnode.h
index 64cf432ee8..93cc925c70 100644
--- a/src/include/pgxc/pgxcnode.h
+++ b/src/include/pgxc/pgxcnode.h
@@ -92,6 +92,9 @@ struct pgxc_node_handle
* For details see comments of RESP_ROLLBACK
*/
bool ck_resp_rollback;
+
+ bool in_extended_query;
+ bool needSync;
};
typedef struct pgxc_node_handle PGXCNodeHandle;