pgpool2.git / summary / log / commit / refs
commit 75fce2c5076ce278d6dd13b7f1fead2a6e680f5f
Author: Toshihiro Kitagawa <kitagawa at sraoss.co.jp>
Date: Fri Aug 06 13:17:24 2010 +0000
Add raise_intentional_error_if_need function and failed_transaction
valiable, to resolve following transaction issue in load_balance_mode.
Now, SELECT is sent to master node when error occurred
in master_slave_mode and load_balance_mode.
example of atomicity issue:
testdb=> BEGIN;
BEGIN
testdb=> SELECT * FROM t1;
ERROR: relation "t1" does not exist
LINE 1: SELECT * FROM t1;
^
testdb=> SELECT * FROM t2;
id
----
(0 rows)
testdb=> COMMIT;
ROLLBACK
pool_proto2.c | 5 ++++-
pool_proto_modules.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++-
pool_proto_modules.h | 1 +
pool_query_context.c | 1 +
pool_session_context.c | 44 ++++++++++++++++++++++++++++++++++++-
pool_session_context.h | 8 ++++++-
6 files changed, 114 insertions(+), 4 deletions(-)
diff --git a/pool_proto2.c b/pool_proto2.c
index 1e73cfde1..f2b3b114e 100644
--- a/pool_proto2.c
+++ b/pool_proto2.c
@@ -367,6 +367,7 @@ POOL_STATUS ErrorResponse(POOL_CONNECTION *frontend,
char *string = NULL;
int len;
int i;
+ POOL_STATUS ret;
for (i=0;i<NUM_BACKENDS;i++)
{
@@ -398,7 +399,9 @@ POOL_STATUS ErrorResponse(POOL_CONNECTION *frontend,
}
}
- return POOL_CONTINUE;
+ ret = raise_intentional_error_if_need(backend);
+
+ return ret;
}
POOL_STATUS FunctionResultResponse(POOL_CONNECTION *frontend,
diff --git a/pool_proto_modules.c b/pool_proto_modules.c
index bea623136..ec70825c6 100644
--- a/pool_proto_modules.c
+++ b/pool_proto_modules.c
@@ -1232,6 +1232,7 @@ POOL_STATUS ReadyForQuery(POOL_CONNECTION *frontend,
if (is_start_transaction_query(node))
{
pool_unset_writing_transaction();
+ pool_unset_failed_transaction();
pool_unset_transaction_isolation();
}
@@ -1451,6 +1452,9 @@ POOL_STATUS CommandComplete(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *bac
TSTATE(backend, i) = 'T';
}
+ pool_unset_writing_transaction();
+ pool_unset_failed_transaction();
+ pool_unset_transaction_isolation();
}
}
}
@@ -1461,7 +1465,7 @@ POOL_STATUS CommandComplete(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *bac
POOL_STATUS ErrorResponse3(POOL_CONNECTION *frontend,
POOL_CONNECTION_POOL *backend)
{
- int ret;
+ POOL_STATUS ret;
/* An error occurred with PREPARE or DEALLOCATE command.
* Free pending portal object.
@@ -1472,6 +1476,10 @@ POOL_STATUS ErrorResponse3(POOL_CONNECTION *frontend,
if (ret != POOL_CONTINUE)
return ret;
+ ret = raise_intentional_error_if_need(backend);
+ if (ret != POOL_CONTINUE)
+ return ret;
+
if (select_in_transaction)
{
int i;
@@ -1888,6 +1896,8 @@ POOL_STATUS ProcessBackendResponse(POOL_CONNECTION *frontend,
case 'E': /* ErrorResponse */
status = ErrorResponse3(frontend, backend);
+ if (TSTATE(backend, REAL_MASTER_NODE_ID) != 'I')
+ pool_set_failed_transaction();
if (pool_is_doing_extended_query_message())
{
pool_set_ignore_till_sync();
@@ -1955,6 +1965,8 @@ POOL_STATUS ProcessBackendResponse(POOL_CONNECTION *frontend,
case 'E': /* ErrorResponse */
status = ErrorResponse(frontend, backend);
+ if (TSTATE(backend, REAL_MASTER_NODE_ID) != 'I')
+ pool_set_failed_transaction();
break;
case 'G': /* CopyInResponse */
@@ -2264,6 +2276,51 @@ POOL_STATUS CopyDataRows(POOL_CONNECTION *frontend,
return POOL_CONTINUE;
}
+/*
+ * This function raises intentional error to make backends the same
+ * transaction state.
+ */
+POOL_STATUS raise_intentional_error_if_need(POOL_CONNECTION_POOL *backend)
+{
+ POOL_STATUS ret;
+ POOL_SESSION_CONTEXT *session_context;
+ POOL_QUERY_CONTEXT *query_context;
+
+ /* Get session context */
+ session_context = pool_get_session_context();
+ if (!session_context)
+ {
+ pool_error("ErrorResponse3: cannot get session context");
+ return POOL_END;
+ }
+
+ query_context = session_context->query_context;
+
+ if (MASTER_SLAVE &&
+ TSTATE(backend, REAL_MASTER_NODE_ID) == 'T' &&
+ REAL_MASTER_NODE_ID != MASTER_NODE_ID &&
+ query_context &&
+ is_select_query(query_context->parse_tree, query_context->original_query))
+ {
+ pool_set_node_to_be_sent(query_context, REAL_MASTER_NODE_ID);
+ if (pool_is_doing_extended_query_message())
+ {
+ ret = do_error_execute_command(backend, REAL_MASTER_NODE_ID, PROTO_MAJOR_V3);
+ if (ret != POOL_CONTINUE)
+ return ret;
+ }
+ else
+ {
+ ret = do_error_command(CONNECTION(backend, REAL_MASTER_NODE_ID), PROTO_MAJOR_V3);
+ if (ret != POOL_CONTINUE)
+ return ret;
+ }
+ pool_debug("raise_intentional_error: intentional error occurred");
+ }
+
+ return POOL_CONTINUE;
+}
+
/*
* Check various errors from backend. return values: 0: no error 1:
* deadlock detected 2: serialization error detected 3: query cancel
diff --git a/pool_proto_modules.h b/pool_proto_modules.h
index 200fef5fe..a00800434 100644
--- a/pool_proto_modules.h
+++ b/pool_proto_modules.h
@@ -185,5 +185,6 @@ extern int synchronize(POOL_CONNECTION *cp);
extern POOL_STATUS read_kind_from_backend(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, char *decided_kind);
extern POOL_STATUS read_kind_from_one_backend(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, char *kind, int node);
extern POOL_STATUS do_error_command(POOL_CONNECTION *backend, int major);
+extern POOL_STATUS raise_intentional_error_if_need(POOL_CONNECTION_POOL *backend);
#endif
diff --git a/pool_query_context.c b/pool_query_context.c
index f397c6379..ac012a394 100644
--- a/pool_query_context.c
+++ b/pool_query_context.c
@@ -351,6 +351,7 @@ void pool_where_to_send(POOL_QUERY_CONTEXT *query_context, char *query, Node *no
*/
if (TSTATE(backend, MASTER_NODE_ID) == 'I' ||
(!pool_is_writing_transaction() &&
+ !pool_is_failed_transaction() &&
pool_get_transaction_isolation() != POOL_SERIALIZABLE))
{
BackendInfo *bkinfo = pool_get_node_info(session_context->load_balance_node_id);
diff --git a/pool_session_context.c b/pool_session_context.c
index 5d8dbc4c0..142a5b4c2 100644
--- a/pool_session_context.c
+++ b/pool_session_context.c
@@ -91,9 +91,12 @@ void pool_init_session_context(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *
/* The command in progress has not succeeded yet */
pool_unset_command_success();
- /* We don't have a write query in this transaction yet. */
+ /* We don't have a write query in this transaction yet */
pool_unset_writing_transaction();
+ /* Error doesn't occur in this transaction yet */
+ pool_unset_failed_transaction();
+
/* Forget transaction isolation mode */
pool_unset_transaction_isolation();
@@ -847,6 +850,45 @@ bool pool_is_writing_transaction(void)
return session_context->writing_transaction;
}
+/*
+ * Error doesn't occur in this transaction yet.
+ */
+void pool_unset_failed_transaction(void)
+{
+ if (!session_context)
+ {
+ pool_error("pool_unset_failed_query: session context is not initialized");
+ return;
+ }
+ session_context->failed_transaction = false;
+}
+
+/*
+ * Error occurred in this transaction.
+ */
+void pool_set_failed_transaction(void)
+{
+ if (!session_context)
+ {
+ pool_error("pool_set_failed_query: session context is not initialized");
+ return;
+ }
+ session_context->failed_transaction = true;
+}
+
+/*
+ * Did error occur in this transaction?
+ */
+bool pool_is_failed_transaction(void)
+{
+ if (!session_context)
+ {
+ pool_error("pool_is_failed_query: session context is not initialized");
+ return false;
+ }
+ return session_context->failed_transaction;
+}
+
/*
* Forget transaction isolation mode
*/
diff --git a/pool_session_context.h b/pool_session_context.h
index c73ab3b43..57252317a 100644
--- a/pool_session_context.h
+++ b/pool_session_context.h
@@ -113,9 +113,12 @@ typedef struct {
/* If true, the command in progress has finished sucessfully. */
bool command_success;
- /* If true write query has been appeared in this transaction */
+ /* If true, write query has been appeared in this transaction */
bool writing_transaction;
+ /* If true, error occurred in this transaction */
+ bool failed_transaction;
+
/* If true, "SHOW pool_status" is in progress */
bool pool_status_stmt;
@@ -247,6 +250,9 @@ extern Portal *pool_get_portal_by_portal_name(const char *name);
extern void pool_unset_writing_transaction(void);
extern void pool_set_writing_transaction(void);
extern bool pool_is_writing_transaction(void);
+extern void pool_unset_failed_transaction(void);
+extern void pool_set_failed_transaction(void);
+extern bool pool_is_failed_transaction(void);
extern void pool_unset_transaction_isolation(void);
extern void pool_set_transaction_isolation(POOL_TRANSACTION_ISOLATION isolation_level);
extern POOL_TRANSACTION_ISOLATION pool_get_transaction_isolation(void);
[parent: 7249892dd173]