Fix hang up in Execute. master
authorYoshiyuki Asaba <y-asaba at pgfoundry.org>
Thu, 8 May 2008 04:59:26 +0000 (04:59 +0000)
committerYoshiyuki Asaba <y-asaba at pgfoundry.org>
Thu, 8 May 2008 04:59:26 +0000 (04:59 +0000)
We sended a syntax error query to abort a transaction if
replicate_select was true. However, the query was sended over Query
message.

Patch contributed by Kenichi Sawada.

pool_process_query.c

index d61cc3f190205300f3caabaabdb432f300b26b58..9aac9ae7fbb3fea4abec38eab10b4c75821e8d79 100644 (file)
@@ -160,6 +160,7 @@ static int master_slave_was_enabled;        /* master/slave mode was enabled */
 static int internal_transaction_started;               /* to issue table lock command a transaction
                                                                                                   has been started internally */
 static int select_in_transaction = 0; /* non 0 if select query is in transaction */
+static int extended_select = 0; /* non 0 if extended mode */
 static int in_progress = 0;
 
 static void (*pending_function)(PreparedStatementList *p, PreparedStatement *statement) = NULL;
@@ -737,6 +738,7 @@ static POOL_STATUS Query(POOL_CONNECTION *frontend,
                REPLICATION = 0;
                in_load_balance = 1;
                select_in_transaction = 1;
+               extended_select = 0;
        }
 
        /*
@@ -891,6 +893,7 @@ static POOL_STATUS Execute(POOL_CONNECTION *frontend,
                        REPLICATION = 0;
                        in_load_balance = 1;
                        select_in_transaction = 1;
+                       extended_select = 1;
                }
        }
 
@@ -2815,8 +2818,10 @@ POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_C
                pending_function(&prepared_list, pending_prepared_stmt);
        }
        else if (kind == 'C' && select_in_transaction)
+       {
                select_in_transaction = 0;
-
+               extended_select = 0;
+       }
        /* 
         * Remove a pending function if a received message is not
         * NoticeResponse.
@@ -2882,6 +2887,7 @@ POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_C
        {
                int i, k;
                int res1, res2;
+               int sync_secondary = 1;
                char *p1;
 
                /*
@@ -2919,6 +2925,11 @@ POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_C
                                do_error_command(SECONDARY(backend), PROTO_MAJOR_V3);
                        }
                        select_in_transaction = 0;
+                       if (extended_select)
+                       {
+                               sync_secondary = 0;
+                               extended_select = 0;
+                       }
                }
 
                for (i = 0;i < backend->num;i++)
@@ -2931,6 +2942,20 @@ POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_C
                         * it by itself. Moreover we do not need it in non-extend mode.
                         * At this point we regard it is not harmfull since error resonse
                         * will not be sent too frequently.
+                         
+                        * We observed a process stall at the synchronous 
+                        * point (Line 370 of this code) in this situation:
+                        * 1. replicate_select = false
+                        * 2. do extended select for MASTER, and get some error
+                        * 3. do_error_command for SECONDARY,
+                        * 4. send Sync to both MASTER and SECONDARY
+                        * 5. SECONDARY returns something but MASTER doesn't.
+                        * 6. then pgpool stalls at pool_read on #370 to wait
+                        *    for a response from MASTER.
+                        *
+                        * To avoid this situation, we introduced a variable
+                        * 'extended_select' so that pgpool sends Sync only to 
+                        * MASTER when the query is in extended mode.
                         */
                        pool_write(cp, "S", 1);
                        res1 = htonl(4);
@@ -2939,7 +2964,7 @@ POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_C
                                return POOL_END;
                        }
 
-                       if (!DUAL_MODE)
+                       if (!DUAL_MODE || sync_secondary == 0)
                                break;
                }