pgpool2.git / summary / log / commit / refs

commit    dfdde7387186b6fe7180358c5e2630588f98befa
Author:   Yugo Nagata <nagata@sraoss.co.jp>
Date:     Fri Jun 09 01:47:44 2017 +0000

    Fix a posible hang with streaming replication and extended protocol
    
    This hang occured under a certain condition. The following is an example.
    
    - pgpool.conf is configured so that all read queries are sent to the standby.
    - First, issue a writing query in a transaction block
    - After commiting the transaction, issue a select query.
    - When processing the query, send Describe (statement) message just after Parse.
    
    Without using JDBC, we can reproduce the problem by pgproto with the followeing messages.
    --------------------------------------------
    
    'Q' "DROP TABLE IF EXISTS test_tbl"
    'Y'
    'Q' "CREATE TABLE test_tbl(i int)"
    'Y'
    'Q' "INSERT INTO test_tbl VALUES(1)"
    'Y'
    
    'P' "" "BEGIN" 0
    'B' "" "" 0 0 0
    'E' "" 0
    'S'
    'Y'
    
    'P' "" "INSERT INTO test_tbl VALUES(1)" 0
    'B' "" "" 0 0 0
    'E' "" 0
    'S'
    'Y'
    
    'P' "" "COMMIT" 0
    'B' "" "" 0 0 0
    'E' "" 0
    'S'
    'Y'
    
    'P' "S_1" "SELECT * FROM test_tbl" 0
    'D' 'S' "S_1"
    'B' "C_1" "S_1" 0 0 0
    'E' "C_1" 0
    'S'
    'Y'
    
    'X'
    ---------------------------------------------
    
    In practice, such Describe message can be sent by JDBC when executing PreparedStatement
    with a parameter of timestamp type more than prepare_threshold times. In addition,
    queries can be issued outside of a transaction block when autocommit is enabled.
    
    When a writing query is issued in a transaction block, writing_transaction flag
    is set, but after commiting the transaction this flag is not unset. The problem
    is that parse_before_bind() is always called when writing_transaction is set.
    
    Alhough Parse of the select and Describe following are sent to standby
    due to load balancing, another Parse and Bind, Execute are to be sent to
    primary due to parse_before_bind.
    
    In this situation, Pgpool-II waits for the responces of Describe from
    standby forever because any messages after Describe is not sent to the
    standby and any responce is not returned.
    
    To fix it, parse_before_bind() should be called only if we are in a transaction
    block so that we can send Bind and Execute to the right backend.


src/protocol/pool_proto_modules.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/protocol/pool_proto_modules.c b/src/protocol/pool_proto_modules.c index 073a3c074..e2dc3baa4 100644 --- a/src/protocol/pool_proto_modules.c +++ b/src/protocol/pool_proto_modules.c @@ -1327,7 +1327,8 @@ POOL_STATUS Bind(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, * other than primary node. In this case, we send a parse message to the * primary node. */ - if (pool_config->load_balance_mode && pool_is_writing_transaction()) + if (pool_config->load_balance_mode && pool_is_writing_transaction() && + TSTATE(backend, MASTER_SLAVE ? PRIMARY_NODE_ID : REAL_MASTER_NODE_ID) == 'T') { if (!STREAM) { [parent: c82d1f77a02a]