]> granicus.if.org Git - postgresql/commitdiff
Make idle backends exit if the postmaster dies.
authorRobert Haas <rhaas@postgresql.org>
Thu, 12 Nov 2015 14:00:33 +0000 (09:00 -0500)
committerRobert Haas <rhaas@postgresql.org>
Thu, 12 Nov 2015 14:00:33 +0000 (09:00 -0500)
Letting backends continue to run if the postmaster has exited prevents
PostgreSQL from being restarted, which in many environments is
catastrophic.  Worse, if some other backend crashes, we no longer have
any protection against shared memory corruption.  So, arrange for them
to exit instead.  We don't want to expend many cycles on this, but
including postmaster death in the set of things that we wait for when
a backend is idle seems cheap enough.

Rajeev Rastogi and Robert Haas

src/backend/libpq/be-secure.c

index 26d8faaf773a818b388b899b8d83d617bdf7af9b..2ddcf428f89fd12c230d6f417c2f707fbd97bf39 100644 (file)
@@ -35,6 +35,7 @@
 #include "miscadmin.h"
 #include "tcop/tcopprot.h"
 #include "utils/memutils.h"
+#include "storage/ipc.h"
 #include "storage/proc.h"
 
 
@@ -144,9 +145,31 @@ retry:
                Assert(waitfor);
 
                w = WaitLatchOrSocket(MyLatch,
-                                                         WL_LATCH_SET | waitfor,
+                                                         WL_LATCH_SET | WL_POSTMASTER_DEATH | waitfor,
                                                          port->sock, 0);
 
+               /*
+                * If the postmaster has died, it's not safe to continue running,
+                * because it is the postmaster's job to kill us if some other backend
+                * exists uncleanly.  Moreover, we won't run very well in this state;
+                * helper processes like walwriter and the bgwriter will exit, so
+                * performance may be poor.  Finally, if we don't exit, pg_ctl will
+                * be unable to restart the postmaster without manual intervention,
+                * so no new connections can be accepted.  Exiting clears the deck
+                * for a postmaster restart.
+                *
+                * (Note that we only make this check when we would otherwise sleep
+                * on our latch.  We might still continue running for a while if the
+                * postmaster is killed in mid-query, or even through multiple queries
+                * if we never have to wait for read.  We don't want to burn too many
+                * cycles checking for this very rare condition, and this should cause
+                * us to exit quickly in most cases.)
+                */
+               if (w & WL_POSTMASTER_DEATH)
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_ADMIN_SHUTDOWN),
+                                       errmsg("terminating connection due to unexpected postmaster exit")));
+
                /* Handle interrupt. */
                if (w & WL_LATCH_SET)
                {
@@ -223,9 +246,15 @@ retry:
                Assert(waitfor);
 
                w = WaitLatchOrSocket(MyLatch,
-                                                         WL_LATCH_SET | waitfor,
+                                                         WL_LATCH_SET | WL_POSTMASTER_DEATH | waitfor,
                                                          port->sock, 0);
 
+               /* See comments in secure_read. */
+               if (w & WL_POSTMASTER_DEATH)
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_ADMIN_SHUTDOWN),
+                                       errmsg("terminating connection due to unexpected postmaster exit")));
+
                /* Handle interrupt. */
                if (w & WL_LATCH_SET)
                {