From 7d17e683fcc28a1b371c7dd02935728cd2cbf9bf Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Tue, 17 Nov 2015 06:46:17 -0500
Subject: [PATCH] Add support for systemd service notifications
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Insert sd_notify() calls at server start and stop for integration with
systemd.  This allows the use of systemd service units of type "notify",
which greatly simplifies the systemd configuration.

Reviewed-by: Pavel Stěhule <pavel.stehule@gmail.com>
---
 configure                           | 49 +++++++++++++++++++++++++++++
 configure.in                        | 13 ++++++++
 doc/src/sgml/installation.sgml      | 16 ++++++++++
 doc/src/sgml/runtime.sgml           | 35 +++++++++++++++++++++
 src/Makefile.global.in              |  1 +
 src/backend/Makefile                |  4 +++
 src/backend/postmaster/postmaster.c | 26 +++++++++++++++
 src/include/pg_config.h.in          |  3 ++
 8 files changed, 147 insertions(+)

diff --git a/configure b/configure
index 3dd1b152c6c..b3f3abe2e1c 100755
--- a/configure
+++ b/configure
@@ -709,6 +709,7 @@ with_libxml
 XML2_CONFIG
 UUID_EXTRA_OBJS
 with_uuid
+with_systemd
 with_selinux
 with_openssl
 krb_srvtab
@@ -830,6 +831,7 @@ with_ldap
 with_bonjour
 with_openssl
 with_selinux
+with_systemd
 with_readline
 with_libedit_preferred
 with_uuid
@@ -1518,6 +1520,7 @@ Optional Packages:
   --with-bonjour          build with Bonjour support
   --with-openssl          build with OpenSSL support
   --with-selinux          build with SELinux support
+  --with-systemd          build with systemd support
   --without-readline      do not use GNU Readline nor BSD Libedit for editing
   --with-libedit-preferred
                           prefer BSD Libedit over GNU Readline
@@ -5694,6 +5697,41 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_selinux" >&5
 $as_echo "$with_selinux" >&6; }
 
+#
+# Systemd
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build with systemd support" >&5
+$as_echo_n "checking whether to build with systemd support... " >&6; }
+
+
+
+# Check whether --with-systemd was given.
+if test "${with_systemd+set}" = set; then :
+  withval=$with_systemd;
+  case $withval in
+    yes)
+
+$as_echo "#define USE_SYSTEMD 1" >>confdefs.h
+
+      ;;
+    no)
+      :
+      ;;
+    *)
+      as_fn_error $? "no argument expected for --with-systemd option" "$LINENO" 5
+      ;;
+  esac
+
+else
+  with_systemd=no
+
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_systemd" >&5
+$as_echo "$with_systemd" >&6; }
+
 #
 # Readline
 #
@@ -10473,6 +10511,17 @@ fi
 
 done
 
+fi
+
+if test "$with_systemd" = yes ; then
+  ac_fn_c_check_header_mongrel "$LINENO" "systemd/sd-daemon.h" "ac_cv_header_systemd_sd_daemon_h" "$ac_includes_default"
+if test "x$ac_cv_header_systemd_sd_daemon_h" = xyes; then :
+
+else
+  as_fn_error $? "header file <systemd/sd-daemon.h> is required for systemd support" "$LINENO" 5
+fi
+
+
 fi
 
 if test "$with_libxml" = yes ; then
diff --git a/configure.in b/configure.in
index 93984822e47..0bd90d75019 100644
--- a/configure.in
+++ b/configure.in
@@ -699,6 +699,15 @@ PGAC_ARG_BOOL(with, selinux, no, [build with SELinux support])
 AC_SUBST(with_selinux)
 AC_MSG_RESULT([$with_selinux])
 
+#
+# Systemd
+#
+AC_MSG_CHECKING([whether to build with systemd support])
+PGAC_ARG_BOOL(with, systemd, no, [build with systemd support],
+              [AC_DEFINE([USE_SYSTEMD], 1, [Define to build with systemd support. (--with-systemd)])])
+AC_SUBST(with_systemd)
+AC_MSG_RESULT([$with_systemd])
+
 #
 # Readline
 #
@@ -1249,6 +1258,10 @@ if test "$with_pam" = yes ; then
                                      [AC_MSG_ERROR([header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.])])])
 fi
 
+if test "$with_systemd" = yes ; then
+  AC_CHECK_HEADER(systemd/sd-daemon.h, [], [AC_MSG_ERROR([header file <systemd/sd-daemon.h> is required for systemd support])])
+fi
+
 if test "$with_libxml" = yes ; then
   AC_CHECK_HEADER(libxml/parser.h, [], [AC_MSG_ERROR([header file <libxml/parser.h> is required for XML support])])
 fi
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 8dcedc0aaa4..00686a73caf 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -812,6 +812,22 @@ su - postgres
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term><option>--with-systemd</option></term>
+       <listitem>
+        <para>
+         Build with support
+         for <application>systemd</application><indexterm><primary>systemd</primary></indexterm>
+         service notifications.  This improves integration if the server binary
+         is started under <application>systemd</application> but has no impact
+         otherwise; see <xref linkend="server-start"> for more
+         information.  <application>libsystemd</application> and the
+         associated header files need to be installed to be able to use this
+         option.
+        </para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry>
        <term><option>--without-readline</option></term>
        <listitem>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index cda05f578af..209eb9e5234 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -369,6 +369,41 @@ fi
       <filename>contrib/start-scripts/linux</filename> in the
       <productname>PostgreSQL</productname> source distribution.
      </para>
+
+     <para>
+      When using <application>systemd</application>, you can use the following
+      service unit file (e.g.,
+      at <filename>/etc/systemd/system/postgresql.service</filename>):<indexterm><primary>systemd</primary></indexterm>
+<programlisting>
+[Unit]
+Description=PostgreSQL database server
+Documentation=man:postgres(1)
+
+[Service]
+Type=notify
+User=postgres
+ExecStart=/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data
+ExecReload=/bin/kill -HUP $MAINPID
+KillMode=mixed
+KillSignal=SIGINT
+TimeoutSec=0
+
+[Install]
+WantedBy=multi-user.target
+</programlisting>
+      Using <literal>Type=notify</literal> requires that the server binary was
+      built with <literal>configure --with-systemd</literal>.
+     </para>
+
+     <para>
+      Consider carefully the timeout
+      setting.  <application>systemd</application> has a default timeout of 90
+      seconds as of this writing and will kill a process that does not notify
+      readiness within that time.  But a <productname>PostgreSQL</productname>
+      server that might have to perform crash recovery at startup could take
+      much longer to become ready.  The suggested value of 0 disables the
+      timeout logic.
+     </para>
     </listitem>
 
     <listitem>
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 51f479713c3..e94d6a58a0c 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -184,6 +184,7 @@ with_python	= @with_python@
 with_tcl	= @with_tcl@
 with_openssl	= @with_openssl@
 with_selinux	= @with_selinux@
+with_systemd	= @with_systemd@
 with_libxml	= @with_libxml@
 with_libxslt	= @with_libxslt@
 with_system_tzdata = @with_system_tzdata@
diff --git a/src/backend/Makefile b/src/backend/Makefile
index d4db8ff57a2..b3d5e2e1bd9 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -45,6 +45,10 @@ LIBS := $(filter-out -lpgport -lpgcommon, $(LIBS)) $(LDAP_LIBS_BE)
 # The backend doesn't need everything that's in LIBS, however
 LIBS := $(filter-out -lz -lreadline -ledit -ltermcap -lncurses -lcurses, $(LIBS))
 
+ifeq ($(with_systemd),yes)
+LIBS += -lsystemd
+endif
+
 ##########################################################################
 
 all: submake-libpgport submake-schemapg postgres $(POSTGRES_IMP)
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 9aaed5b9848..d983a50ee1d 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -87,6 +87,10 @@
 #include <dns_sd.h>
 #endif
 
+#ifdef USE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
 #ifdef HAVE_PTHREAD_IS_THREADED_NP
 #include <pthread.h>
 #endif
@@ -2533,6 +2537,9 @@ pmdie(SIGNAL_ARGS)
 			Shutdown = SmartShutdown;
 			ereport(LOG,
 					(errmsg("received smart shutdown request")));
+#ifdef USE_SYSTEMD
+			sd_notify(0, "STOPPING=1");
+#endif
 
 			if (pmState == PM_RUN || pmState == PM_RECOVERY ||
 				pmState == PM_HOT_STANDBY || pmState == PM_STARTUP)
@@ -2585,6 +2592,9 @@ pmdie(SIGNAL_ARGS)
 			Shutdown = FastShutdown;
 			ereport(LOG,
 					(errmsg("received fast shutdown request")));
+#ifdef USE_SYSTEMD
+			sd_notify(0, "STOPPING=1");
+#endif
 
 			if (StartupPID != 0)
 				signal_child(StartupPID, SIGTERM);
@@ -2645,6 +2655,9 @@ pmdie(SIGNAL_ARGS)
 			Shutdown = ImmediateShutdown;
 			ereport(LOG,
 					(errmsg("received immediate shutdown request")));
+#ifdef USE_SYSTEMD
+			sd_notify(0, "STOPPING=1");
+#endif
 
 			TerminateChildren(SIGQUIT);
 			pmState = PM_WAIT_BACKENDS;
@@ -2787,6 +2800,10 @@ reaper(SIGNAL_ARGS)
 			ereport(LOG,
 				 (errmsg("database system is ready to accept connections")));
 
+#ifdef USE_SYSTEMD
+			sd_notify(0, "READY=1");
+#endif
+
 			continue;
 		}
 
@@ -4916,6 +4933,11 @@ sigusr1_handler(SIGNAL_ARGS)
 		if (XLogArchivingAlways())
 			PgArchPID = pgarch_start();
 
+#ifdef USE_SYSTEMD
+		if (!EnableHotStandby)
+			sd_notify(0, "READY=1");
+#endif
+
 		pmState = PM_RECOVERY;
 	}
 	if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
@@ -4930,6 +4952,10 @@ sigusr1_handler(SIGNAL_ARGS)
 		ereport(LOG,
 		(errmsg("database system is ready to accept read only connections")));
 
+#ifdef USE_SYSTEMD
+		sd_notify(0, "READY=1");
+#endif
+
 		pmState = PM_HOT_STANDBY;
 		/* Some workers may be scheduled to start now */
 		StartWorkerNeeded = true;
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 16a272efdee..b3ceea5edc9 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -833,6 +833,9 @@
 /* Define to 1 to use Intel SSSE 4.2 CRC instructions with a runtime check. */
 #undef USE_SSE42_CRC32C_WITH_RUNTIME_CHECK
 
+/* Define to build with systemd support. (--with-systemd) */
+#undef USE_SYSTEMD
+
 /* Define to select SysV-style semaphores. */
 #undef USE_SYSV_SEMAPHORES
 
-- 
GitLab