Arrange for SIGINT in autovacuum workers to cancel the current table and
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 29 Jun 2007 17:07:39 +0000 (17:07 +0000)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Fri, 29 Jun 2007 17:07:39 +0000 (17:07 +0000)
continue with the schedule.  Change current uses of SIGINT to abort a worker
into SIGTERM, which keeps the old behaviour of terminating the process.

Patch from ITAGAKI Takahiro, with some editorializing of my own.

src/backend/postmaster/autovacuum.c
src/backend/postmaster/postmaster.c
src/backend/storage/ipc/procarray.c
src/backend/tcop/postgres.c

index 6e254b55d3272de3f4795179e98dcdc322abe9c2..c6744374778578ead5c970df6cb7172b9c934ca3 100644 (file)
@@ -75,6 +75,7 @@
 #include "catalog/namespace.h"
 #include "catalog/pg_autovacuum.h"
 #include "catalog/pg_database.h"
+#include "commands/dbcommands.h"
 #include "commands/vacuum.h"
 #include "libpq/hba.h"
 #include "libpq/pqsignal.h"
@@ -2025,12 +2026,53 @@ next_worker:
                autovac_balance_cost();
                LWLockRelease(AutovacuumLock);
 
-               /* have at it */
-               autovacuum_do_vac_analyze(tab->at_relid,
-                                                                 tab->at_dovacuum,
-                                                                 tab->at_doanalyze,
-                                                                 tab->at_freeze_min_age,
-                                                                 bstrategy);
+               /*
+                * We will abort vacuuming the current table if we are interrupted, and
+                * continue with the next one in schedule; but if anything else
+                * happens, we will do our usual error handling which is to cause the
+                * worker process to exit.
+                */
+               PG_TRY();
+               {
+                       /* have at it */
+                       autovacuum_do_vac_analyze(tab->at_relid,
+                                                                         tab->at_dovacuum,
+                                                                         tab->at_doanalyze,
+                                                                         tab->at_freeze_min_age,
+                                                                         bstrategy);
+               }
+               PG_CATCH();
+               {
+                       ErrorData          *errdata;
+
+                       MemoryContextSwitchTo(TopTransactionContext);
+                       errdata = CopyErrorData();
+
+                       /*
+                        * If we errored out due to a cancel request, abort and restart the
+                        * transaction and go to the next table.  Otherwise rethrow the
+                        * error so that the outermost handler deals with it.
+                        */
+                       if (errdata->sqlerrcode == ERRCODE_QUERY_CANCELED)
+                       {
+                               HOLD_INTERRUPTS();
+                               elog(LOG, "cancelling autovacuum of table \"%s.%s.%s\"",
+                                        get_database_name(MyDatabaseId),
+                                        get_namespace_name(get_rel_namespace(tab->at_relid)),
+                                        get_rel_name(tab->at_relid));
+
+                               AbortOutOfAnyTransaction();
+                               FlushErrorState();
+
+                               /* restart our transaction for the following operations */
+                               StartTransactionCommand();
+                               RESUME_INTERRUPTS();
+                       }
+                       else
+                               PG_RE_THROW();
+               }
+               PG_END_TRY();
+
                /* be tidy */
                pfree(tab);
        }
index 9337e3ccb44901676daf7d1323cecbe5e94a45cd..193980e484233764c31c81b8066ff182e180f385 100644 (file)
@@ -1875,7 +1875,7 @@ pmdie(SIGNAL_ARGS)
 
                        /* autovacuum workers are shut down immediately */
                        if (DLGetHead(BackendList))
-                               SignalSomeChildren(SIGINT, true);
+                               SignalSomeChildren(SIGTERM, true);
 
                        if (DLGetHead(BackendList))
                                break;                  /* let reaper() handle this */
index 5361c88205cce35cce8808023fb30c735d26bf28..65ea1bcdeac63b37e1c44d6041434b5e04db9337 100644 (file)
@@ -1008,7 +1008,7 @@ CheckOtherDBBackends(Oid databaseId)
                                 */
                                LWLockRelease(ProcArrayLock);
 
-                               (void) kill(autopid, SIGINT);           /* ignore any error */
+                               (void) kill(autopid, SIGTERM);          /* ignore any error */
 
                                break;
                        }
index d98c7bea0477d42cf87287eaa9f1972b0a73c1fa..9ee4a7e960f73c83a8872b2f3fa5a907ce2ef8bc 100644 (file)
@@ -51,6 +51,7 @@
 #include "optimizer/planner.h"
 #include "parser/analyze.h"
 #include "parser/parser.h"
+#include "postmaster/autovacuum.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/freespace.h"
 #include "storage/ipc.h"
@@ -2540,9 +2541,14 @@ ProcessInterrupts(void)
                ImmediateInterruptOK = false;   /* not idle anymore */
                DisableNotifyInterrupt();
                DisableCatchupInterrupt();
-               ereport(FATAL,
-                               (errcode(ERRCODE_ADMIN_SHUTDOWN),
-                        errmsg("terminating connection due to administrator command")));
+               if (IsAutoVacuumWorkerProcess())
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_ADMIN_SHUTDOWN),
+                                        errmsg("terminating autovacuum process due to administrator command")));
+               else
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_ADMIN_SHUTDOWN),
+                                        errmsg("terminating connection due to administrator command")));
        }
        if (QueryCancelPending)
        {