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]