Fix DROP DATABASE failure.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Tue, 16 Apr 2019 06:48:44 +0000 (15:48 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Tue, 16 Apr 2019 08:39:53 +0000 (17:39 +0900)
When DROP DATABASE gets executed, SIGUSR1 is sent to the Pgpool-II
child process being issuing the command. In its SIGUSR1 handler,
MASTER macro is called while closing all idle connections. The MACRO
checks whether we are in failover process surely we are. As a result,
the process exits and DROP DATABASE command never been issued.

Per bug 486. However the reason of segfault in the report is not
clear.  After commit:
https://git.postgresql.org/gitweb/?p=pgpool2.git;a=commit;h=66b5aacfcc045ec1485921a5884b637fcfb6fd73

Things could be different. Let the user test the latest version in the
git repo and see if the problem is solved...

src/include/pool.h
src/protocol/child.c
src/protocol/pool_proto_modules.c

index d749692762d2331a227176070504a5e7eb29e9d1..1f86164431105b1b88d3f0b3b976753cd0d82bb6 100644 (file)
@@ -497,6 +497,7 @@ extern volatile sig_atomic_t *InRecovery;
 extern char remote_ps_data[];          /* used for set_ps_display */
 extern volatile sig_atomic_t got_sighup;
 extern volatile sig_atomic_t exit_request;
+extern volatile sig_atomic_t ignore_sigusr1;
 
 #define QUERY_STRING_BUFFER_LEN 1024
 extern char query_string_buffer[];             /* last query string sent to simpleQuery() */
index cf65e02e25a9111e147dc8499b301f57755678f0..20fa81a4ef46289d098413fafb957a409fa2e4ac 100644 (file)
@@ -93,11 +93,15 @@ static int choose_db_node_id(char *str);
 static void child_will_go_down(int code, Datum arg);
 static int opt_sort(const void *a, const void *b);
 /*
- * non 0 means SIGTERM(smart shutdown) or SIGINT(fast shutdown) has arrived
+ * Non 0 means SIGTERM (smart shutdown) or SIGINT (fast shutdown) has arrived
  */
 volatile sig_atomic_t exit_request = 0;
 static volatile sig_atomic_t alarm_enabled = false;
 
+/*
+ * Ignore SIGUSR1 if requested. Used when DROP DATABASE is requested.
+ */
+volatile sig_atomic_t ignore_sigusr1 = 0;
 
 static int idle;               /* non 0 means this child is in idle state */
 static int accepted = 0;
@@ -1033,6 +1037,12 @@ static RETSIGTYPE close_idle_connection(int sig)
        ConnectionInfo *info;
        int save_errno = errno;
 
+       /*
+        * DROP DATABSE is ongoing.
+        */
+       if (ignore_sigusr1)
+               return;
+
 #ifdef NOT_USED
        ereport(DEBUG1,
                        (errmsg("close connection request received")));
index 9cec160d0d1c8513b7ce6adaec52cd85fdb88605..f8ea4bbd2f91d88f3ff95a59c10675ac8282c4b8 100644 (file)
@@ -397,17 +397,37 @@ POOL_STATUS SimpleQuery(POOL_CONNECTION *frontend,
                 */
                if (is_drop_database(node))
                {
-                       int stime = 5;  /* XXX give arbitrary time to allow closing idle connections */
+                       struct timeval stime;
 
+                       stime.tv_usec = 0;
+                       stime.tv_sec = 5;       /* XXX give arbitrary time to allow
+                                                                        * closing idle connections */
                        ereport(DEBUG1,
                                        (errmsg("Query: sending SIGUSR1 signal to parent")));
+
+                       ignore_sigusr1 = 1;     /* disable SIGUSR1 handler */
                        register_node_operation_request(CLOSE_IDLE_REQUEST, NULL, 0);
 
-                       /* we need to loop over here since we will get USR1 signal while sleeping */
-                       while (stime > 0)
+                       /*
+                        * We need to loop over here since we might get some signals while
+                        * sleeping
+                        */
+                       for (;;)
                        {
-                               stime = sleep(stime);
+                               int sts;
+
+                               errno = 0;
+                               sts = select(0, NULL, NULL, NULL, &stime);
+                               if (stime.tv_usec == 0 && stime.tv_sec == 0)
+                                       break;
+                               if (sts != 0 && errno != EINTR)
+                               {
+                                       elog(DEBUG1, "select(2) returns error: %s", strerror(errno));
+                                       break;
+                               }
                        }
+
+                       ignore_sigusr1 = 0;
                }
 
                /*