Fixing reset query stuck problem [pgpool-hackers: 1097]
authorMuhammad Usama <m.usama@gmail.com>
Wed, 18 Nov 2015 13:31:20 +0000 (18:31 +0500)
committerMuhammad Usama <m.usama@gmail.com>
Wed, 18 Nov 2015 13:31:20 +0000 (18:31 +0500)
The issue is already fixed in older branches by the
commit id "cb735f22441001b6afdbb5bac72808db66094ca9", and this fix adopts the
same solution used by 3.3 branch, i.e. closing the backend connection
when client idle limit is reached.

src/include/utils/elog.h
src/protocol/child.c
src/protocol/pool_process_query.c
src/utils/error/elog.c

index fd7ab1df797564141e122cd97cb2a0d70edaf545..065c7e567767bdd2e05990f05f47e0b1b664e724 100644 (file)
@@ -118,6 +118,10 @@ typedef enum
 #endif
 #define FATAL          21                      /* fatal error - abort process */
 #define PANIC          22                      /* take down the other backends with me */
+/* pgpool-II extension. This is same as ERROR but sets the
+ * do not cache connection flag before transforming to ERROR.
+ */
+#define FRONTEND_ERROR 23                      /* transformed to ERROR at errstart */
 
  /* #define DEBUG DEBUG1 */    /* Backward compatibility with pre-7.3 */
 #define POOL_EXIT_SUCCESS      0       /* failure exit and child gets restarted*/
@@ -280,6 +284,7 @@ extern int  errposition(int cursorpos);
 
 #define pg_unreachable() exit(0)
 
+extern bool getfrontendinvalid(void);
 extern int     geterrcode(void);
 extern int     geterrposition(void);
 extern int     getinternalerrposition(void);
@@ -431,6 +436,7 @@ typedef struct ErrorData
        const char *domain;                     /* message domain */
        const char *context_domain; /* message domain for context message */
        int                     sqlerrcode;             /* encoded ERRSTATE */
+       bool            frontend_invalid;/* true when frontend connection is not valid */
        char       *pgpool_errcode;     /* error code to be sent to client */
        char       *message;            /* primary error message */
        char       *detail;                     /* detail error message */
index c0cc066bbf8044912a64c028ca3948e0c7ea94fc..6f5f7f0333132d0aa67df6b253a5f464165407f0 100644 (file)
@@ -87,7 +87,7 @@ static POOL_CONNECTION *get_connection(int front_end_fd, SockAddr *saddr);
 static POOL_CONNECTION_POOL *get_backend_connection(POOL_CONNECTION *frontend);
 static StartupPacket *StartupPacketCopy(StartupPacket *sp);
 static void print_process_status(char *remote_host,char* remote_port);
-static bool backend_cleanup(POOL_CONNECTION* volatile *frontend, POOL_CONNECTION_POOL* volatile backend);
+static bool backend_cleanup(POOL_CONNECTION* volatile *frontend, POOL_CONNECTION_POOL* volatile backend, bool frontend_invalid);
 static void free_persisten_db_connection_memory(POOL_CONNECTION_POOL_SLOT *cp);
 static int choose_db_node_id(char *str);
 static void child_will_go_down(int code, Datum arg);
@@ -211,6 +211,8 @@ void do_child(int *fds)
        if (sigsetjmp(local_sigjmp_buf, 1) != 0)
        {
                POOL_PROCESS_CONTEXT *session;
+               bool frontend_invalid = getfrontendinvalid();
+
                disable_authentication_timeout();
                /* Since not using PG_TRY, must reset error stack by hand */
                error_context_stack = NULL;
@@ -233,7 +235,7 @@ void do_child(int *fds)
                if (accepted)
                        connection_count_down();
 
-               backend_cleanup(&child_frontend, backend);
+               backend_cleanup(&child_frontend, backend, frontend_invalid);
 
                session = pool_get_process_context();
 
@@ -372,7 +374,7 @@ void do_child(int *fds)
                        status = pool_process_query(child_frontend, backend, 0);
             if(status != POOL_CONTINUE)
             {
-                backend_cleanup(&child_frontend, backend);
+                backend_cleanup(&child_frontend, backend, 0);
                 break;
             }
                }
@@ -415,7 +417,7 @@ void do_child(int *fds)
  * return true if backend connection is cached
  */
 static bool
-backend_cleanup(POOL_CONNECTION* volatile *frontend, POOL_CONNECTION_POOL* volatile backend)
+backend_cleanup(POOL_CONNECTION* volatile *frontend, POOL_CONNECTION_POOL* volatile backend, bool frontend_invalid)
 {
     StartupPacket *sp;
     bool cache_connection = false;
@@ -426,11 +428,11 @@ backend_cleanup(POOL_CONNECTION* volatile *frontend, POOL_CONNECTION_POOL* volat
     sp = MASTER_CONNECTION(backend)->sp;
 
     /*
-     * cach connection if connection is not for
+     * cach connection if frontend is not invalid, connection is not for
      * system db and connection cache configuration
      * parameter is enabled
      */
-    if (sp && pool_config->connection_cache != 0 && sp->system_db == false)
+    if (sp && pool_config->connection_cache != 0 && sp->system_db == false  && frontend_invalid == false )
     {
         if (*frontend)
         {
@@ -453,20 +455,22 @@ backend_cleanup(POOL_CONNECTION* volatile *frontend, POOL_CONNECTION_POOL* volat
         }
     }
 
-       /*
-        * For those special databases, and when frontend client exits abnormally,
-        * we don't cache connection to backend.
-        */
-    if ((sp &&
-               (!strcmp(sp->database, "template0") ||
-                !strcmp(sp->database, "template1") ||
-                !strcmp(sp->database, "postgres") ||
-                !strcmp(sp->database, "regression"))) ||
-                (*frontend != NULL &&
-                 ((*frontend)->socket_state == POOL_SOCKET_EOF ||
-                 (*frontend)->socket_state == POOL_SOCKET_ERROR)))
-        cache_connection = false;
-
+       if (cache_connection)
+       {
+               /*
+                * For those special databases, and when frontend client exits abnormally,
+                * we don't cache connection to backend.
+                */
+               if ((sp &&
+                       (!strcmp(sp->database, "template0") ||
+                        !strcmp(sp->database, "template1") ||
+                        !strcmp(sp->database, "postgres") ||
+                        !strcmp(sp->database, "regression"))) ||
+                        (*frontend != NULL &&
+                         ((*frontend)->socket_state == POOL_SOCKET_EOF ||
+                         (*frontend)->socket_state == POOL_SOCKET_ERROR)))
+                       cache_connection = false;
+       }
        /*
         * Close frontend connection
         */
index ff97bf1cb1104a5013615f3397ac83e9561466e8..271f19f51297fe622ee520e1d9bf2e54f3c87513 100644 (file)
@@ -4695,7 +4695,7 @@ SELECT_RETRY:
 
                        if (idle_count > pool_config->client_idle_limit)
                        {
-                ereport(ERROR,
+                ereport(FRONTEND_ERROR,
                         (pool_error_code("57000"),
                         errmsg("unable to read data"),
                          errdetail("child connection forced to terminate due to client_idle_limit:%d is reached",
@@ -4708,7 +4708,7 @@ SELECT_RETRY:
 
                        if (idle_count_in_recovery > pool_config->client_idle_limit_in_recovery)
                        {
-                ereport(ERROR,
+                ereport(FRONTEND_ERROR,
                     (pool_error_code("57000"),
                     errmsg("unable to read data"),
                          errdetail("child connection forced to terminate due to client_idle_limit_in_recovery:%d is reached",pool_config->client_idle_limit_in_recovery)));
@@ -4720,7 +4720,7 @@ SELECT_RETRY:
                         * If we are in recovery and client_idle_limit_in_recovery is -1, then
                         * exit immediately.
                         */
-            ereport(ERROR,
+            ereport(FRONTEND_ERROR,
                 (pool_error_code("57000"),
                 errmsg("connection terminated due to online recovery"),
                      errdetail("child connection forced to terminate due to client_idle_limitis:-1")));
index 18ab00694340b408788083dff42827972759bf8b..42899e836f4253751fc6226c7ba8cbc825b3da03 100644 (file)
@@ -217,11 +217,17 @@ errstart(int elevel, const char *filename, int lineno,
        bool            output_to_server;
        bool            output_to_client = false;
        int                     i;
-
+       int                     frontend_invalid = false;
        /*
         * Check some cases in which we want to promote an error into a more
         * severe error.  None of this logic applies for non-error messages.
         */
+       if (elevel == FRONTEND_ERROR)
+       {
+               frontend_invalid = true;
+               elevel = ERROR;
+       }
+
        if (elevel >= ERROR)
        {
                /*
@@ -321,6 +327,7 @@ errstart(int elevel, const char *filename, int lineno,
        edata = &errordata[errordata_stack_depth];
        MemSet(edata, 0, sizeof(ErrorData));
        edata->elevel = elevel;
+       edata->frontend_invalid = frontend_invalid;
        edata->output_to_server = output_to_server;
        edata->output_to_client = output_to_client;
        if(elevel == FATAL && PG_exception_stack == NULL) /* This is startup failure. Take down main process with it */
@@ -968,6 +975,21 @@ geterrcode(void)
        return edata->sqlerrcode;
 }
 
+/*
+ * getfrontendinvalid --- return the currently frontend_invalid value
+ *
+ * This is only intended for use in error callback subroutines, since there
+ * is no other place outside elog.c where the concept is meaningful.
+ */
+bool getfrontendinvalid(void)
+{
+       ErrorData  *edata = &errordata[errordata_stack_depth];
+
+       /* we don't bother incrementing recursion_depth */
+       CHECK_STACK_DEPTH();
+
+       return edata->frontend_invalid;
+}
 /*
  * geterrposition --- return the currently set error position (0 if none)
  *
@@ -1580,7 +1602,7 @@ write_eventlog(int level, const char *line, int len)
 
        if (evtHandle == INVALID_HANDLE_VALUE)
        {
-               evtHandle = RegisterEventSource(NULL, event_source ? event_source : "PostgreSQL");
+               evtHandle = RegisterEventSource(NULL, event_source ? event_source : "pgpool");
                if (evtHandle == NULL)
                {
                        evtHandle = INVALID_HANDLE_VALUE;