pgpool2.git / summary / log / commit / refs

commit    8bd0baeb9c0ca737eca6bd0e77b87e4c51c2fd39
Author:   Tatsuo Ishii <ishii@postgresql.org>
Date:     Thu Jul 12 01:39:53 2012 +0000

    Fix bug with treatment of BEGIN TRANSACTION in master/slave
    mode. Original complain is [pgpool-general: 714]. From 3.1, pgpool-II
    sends BEGIN.. to all DB nodes. Of course we cannot send BEGIN
    TRANSACTION READ WRITE to standby nodes. Problem is, we did not check
    BEGIN WORK ISOLATION LEVEL SERIALIZABLE; and sent to standby nodes.
    Of course this is wrong, since it's not allowed to run transactions in
    serializable mode on standby nodes. So I added check for BEGIN WORK
    ISOLATION LEVEL SERIALIZABLE case, with some refactoring because
    there's lots of redundant codes.


pool_proto_modules.c | 9 +++---- pool_query_context.c | 69 +++++++++++++++++++++++++++++++++++++++++++--------- pool_query_context.h | 2 ++ 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/pool_proto_modules.c b/pool_proto_modules.c index a6356d936..de986c908 100644 --- a/pool_proto_modules.c +++ b/pool_proto_modules.c @@ -545,14 +545,13 @@ POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend, rewrite_query = rewrite_timestamp(backend, query_context->parse_tree, false, msg); /* - * If the query is BEGIN READ WRITE in master/slave mode, - * we send BEGIN instead of it to slaves/standbys. + * If the query is BEGIN READ WRITE or + * BEGIN ... SERIALIZABLE in master/slave mode, + * we send BEGIN to slaves/standbys instead. * original_query which is BEGIN READ WRITE is sent to primary. * rewritten_query which is BEGIN is sent to standbys. */ - if (is_start_transaction_query(query_context->parse_tree) && - is_read_write((TransactionStmt *)query_context->parse_tree) && - MASTER_SLAVE) + if (pool_need_to_treat_as_if_default_transaction(query_context)) { rewrite_query = pstrdup("BEGIN"); } diff --git a/pool_query_context.c b/pool_query_context.c index a2c3c277c..45f6c968c 100644 --- a/pool_query_context.c +++ b/pool_query_context.c @@ -574,12 +574,13 @@ POOL_STATUS pool_send_and_wait(POOL_QUERY_CONTEXT *query_context, string = NULL; /* - * If the query is BEGIN READ WRITE in master/slave mode, - * we send BEGIN instead of it to slaves/standbys. + * If the query is BEGIN READ WRITE or + * BEGIN ... SERIALIZABLE in master/slave mode, + * we send BEGIN to slaves/standbys instead. + * original_query which is BEGIN READ WRITE is sent to primary. + * rewritten_query which is BEGIN is sent to standbys. */ - if (is_start_transaction_query(query_context->parse_tree) && - is_read_write((TransactionStmt *)query_context->parse_tree) && - MASTER_SLAVE) + if (pool_need_to_treat_as_if_default_transaction(query_context)) { is_begin_read_write = true; } @@ -738,12 +739,13 @@ POOL_STATUS pool_extended_send_and_wait(POOL_QUERY_CONTEXT *query_context, rewritten_begin = NULL; /* - * If the query is BEGIN READ WRITE in master/slave mode, - * we send BEGIN instead of it to slaves/standbys. + * If the query is BEGIN READ WRITE or + * BEGIN ... SERIALIZABLE in master/slave mode, + * we send BEGIN to slaves/standbys instead. + * original_query which is BEGIN READ WRITE is sent to primary. + * rewritten_query which is BEGIN is sent to standbys. */ - if (is_start_transaction_query(query_context->parse_tree) && - is_read_write((TransactionStmt *)query_context->parse_tree) && - MASTER_SLAVE) + if (pool_need_to_treat_as_if_default_transaction(query_context)) { is_begin_read_write = true; @@ -1372,14 +1374,59 @@ bool is_read_write(TransactionStmt *node) bool read_only; read_only = ((A_Const *)opt->arg)->val.val.ival; - if (!read_only) + if (read_only) + return false; /* TRANSACTION READ ONLY */ + else + /* + * TRANSACTION READ WRITE specified. This sounds a little bit strange, + * but actually the parse code works in the way. + */ return true; } } + /* + * No TRANSACTION READ ONLY/READ WRITE clause specified. + */ return false; } +/* + * Return true if start transaction query with "SERIALIZABLE" option. + */ +bool is_serializable(TransactionStmt *node) +{ + ListCell *list_item; + + List *options = node->options; + foreach(list_item, options) + { + DefElem *opt = (DefElem *) lfirst(list_item); + + if (!strcmp("transaction_isolation", opt->defname) && + IsA(opt->arg, A_Const) && + ((A_Const *)opt->arg)->val.type == T_String && + !strcmp("serializable", ((A_Const *)opt->arg)->val.val.str)) + return true; + } + return false; +} + +/* + * If the query is BEGIN READ WRITE or + * BEGIN ... SERIALIZABLE in master/slave mode, + * we send BEGIN to slaves/standbys instead. + * original_query which is BEGIN READ WRITE is sent to primary. + * rewritten_query which is BEGIN is sent to standbys. + */ +bool pool_need_to_treat_as_if_default_transaction(POOL_QUERY_CONTEXT *query_context) +{ + return (MASTER_SLAVE && + is_start_transaction_query(query_context->parse_tree) && + (is_read_write((TransactionStmt *)query_context->parse_tree) || + is_serializable((TransactionStmt *)query_context->parse_tree))); +} + /* * Return true if the query is SAVEPOINT related query. */ diff --git a/pool_query_context.h b/pool_query_context.h index c48db973a..eab1f673c 100644 --- a/pool_query_context.h +++ b/pool_query_context.h @@ -89,6 +89,8 @@ extern char *pool_get_query_string(void); extern bool is_set_transaction_serializable(Node *node, char *query); extern bool is_start_transaction_query(Node *node); extern bool is_read_write(TransactionStmt *node); +extern bool is_serializable(TransactionStmt *node); +extern bool pool_need_to_treat_as_if_default_transaction(POOL_QUERY_CONTEXT *query_context); extern bool is_savepoint_query(Node *node); extern bool is_2pc_transaction_query(Node *node); extern void pool_set_query_state(POOL_QUERY_CONTEXT *query_context, POOL_QUERY_STATE state); [parent: a36819d8a23b]