From 04e1cbe49268e22886e2b30fe412fef0cb9dcc65 Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig@2ndquadrant.com>
Date: Mon, 16 Feb 2015 18:37:19 +1300
Subject: [PATCH 4/4] Document SPI use from bgworkers in greater detail

---
 doc/src/sgml/bgworker.sgml           | 164 +++++++++++++++++++++++++++--------
 doc/src/sgml/contrib.sgml            |   1 +
 doc/src/sgml/example-worker-spi.sgml |  26 ++++++
 doc/src/sgml/filelist.sgml           |   1 +
 doc/src/sgml/spi.sgml                | 151 +++++++++++++++++++++++++++++++-
 doc/src/sgml/xfunc.sgml              |  54 ++++++++++++
 6 files changed, 357 insertions(+), 40 deletions(-)
 create mode 100644 doc/src/sgml/example-worker-spi.sgml

diff --git a/doc/src/sgml/bgworker.sgml b/doc/src/sgml/bgworker.sgml
index ef28f72..d0e7dc0 100644
--- a/doc/src/sgml/bgworker.sgml
+++ b/doc/src/sgml/bgworker.sgml
@@ -34,18 +34,21 @@
   <productname>PostgreSQL</> is started by including the module name in
   <varname>shared_preload_libraries</>.  A module wishing to run a background
   worker can register it by calling
+  <indexterm><primary>RegisterBackgroundWorker</primary></indexterm>
   <function>RegisterBackgroundWorker(<type>BackgroundWorker *worker</type>)</function>
   from its <function>_PG_init()</>.  Background workers can also be started
   after the system is up and running by calling the function
+  <indexterm><primary>RegisterDynamicBackgroundWorker</primary></indexterm>
   <function>RegisterDynamicBackgroundWorker(<type>BackgroundWorker
   *worker, BackgroundWorkerHandle **handle</type>)</function>.  Unlike
   <function>RegisterBackgroundWorker</>, which can only be called from within
   the postmaster, <function>RegisterDynamicBackgroundWorker</function> must be
-  called from a regular backend.
+  called from a regular backend (which might be another background worker).
  </para>
 
  <para>
-  The structure <structname>BackgroundWorker</structname> is defined thus:
+  The structure <indexterm><primary>BackgroundWorker</primary></indexterm>
+  <structname>BackgroundWorker</structname> is defined thus:
 <programlisting>
 typedef void (*bgworker_main_type)(Datum main_arg);
 typedef struct BackgroundWorker
@@ -64,22 +67,46 @@ typedef struct BackgroundWorker
   </para>
 
   <para>
-   <structfield>bgw_name</> is a string to be used in log messages, process
+   <indexterm><primary>bgw_name</></><structfield>bgw_name</> is a string to be used in log messages, process
    listings and similar contexts.
   </para>
 
   <para>
    <structfield>bgw_flags</> is a bitwise-or'd bit mask indicating the
-   capabilities that the module wants.  Possible values are
-   <literal>BGWORKER_SHMEM_ACCESS</literal> (requesting shared memory access)
-   and <literal>BGWORKER_BACKEND_DATABASE_CONNECTION</literal> (requesting the
-   ability to establish a database connection, through which it can later run
-   transactions and queries). A background worker using
-   <literal>BGWORKER_BACKEND_DATABASE_CONNECTION</literal> to connect to
-   a database must also attach shared memory using
-   <literal>BGWORKER_SHMEM_ACCESS</literal>, or worker start-up will fail.
+   capabilities that the module wants.  Possible values are:
+   <variablelist>
+
+    <varlistentry>
+     <term><literal>BGWORKER_SHMEM_ACCESS</literal></term>
+     <listitem>
+      <para>
+       <indexterm><primary>BGWORKER_SHMEM_ACCESS</primary></indexterm>
+       Requests shared memory access. This flag is also required to use
+       lightweight locks (LWlocks). For more information on shared memory access
+       from bgworkers and extensions see <xref linkend="xfunc-shmem-lwlocks">.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>BGWORKER_BACKEND_DATABASE_CONNECTION</literal></term>
+     <listitem>
+      <para>
+       <indexterm><primary>BGWORKER_BACKEND_DATABASE_CONNECTION</primary></indexterm>
+       Requests the ability to establish a database connection through which it
+       can later run transactions and queries.  A background worker using
+       <literal>BGWORKER_BACKEND_DATABASE_CONNECTION</literal> to connect to a
+       database must also attach shared memory using
+       <literal>BGWORKER_SHMEM_ACCESS</literal>, or worker start-up will fail.
+      </para>
+     </listitem>
+    </varlistentry>
+
+   </variablelist>
+
   </para>
 
+
   <para>
    <structfield>bgw_start_time</structfield> is the server state during which
    <command>postgres</> should start the process; it can be one of
@@ -105,58 +132,113 @@ typedef struct BackgroundWorker
   </para>
 
   <para>
-   <structfield>bgw_main</structfield> is a pointer to the function to run when
-   the process is started.  This function must take a single argument of type
-   <type>Datum</> and return <type>void</>.
-   <structfield>bgw_main_arg</structfield> will be passed to it as its only
-   argument.  Note that the global variable <literal>MyBgworkerEntry</literal>
-   points to a copy of the <structname>BackgroundWorker</structname> structure
-   passed at registration time. <structfield>bgw_main</structfield> may be
-   NULL; in that case, <structfield>bgw_library_name</structfield> and
-   <structfield>bgw_function_name</structfield> will be used to determine
-   the entry point.  This is useful for background workers launched after
-   postmaster startup, where the postmaster does not have the requisite
-   library loaded.
+   <structfield>bgw_main</structfield> specifies the function to run when the
+   background worker is started. If non-NULL,
+   <structfield>bgw_main</structfield> will take precedence over
+   <structfield>bgw_library_name</structfield> and
+   <structfield>bgw_function_name</structfield>.
+   <warning>
+    <para>
+     Use of this field is deprecated. It should be set to
+     <literal>NULL</literal> then <structfield>bgw_library_name</structfield>
+     and <structfield>bgw_function_name</structfield> should be used instead.
+    </para>
+    <para>
+     Specifying the background worker entry point using a function pointer will
+     not work correctly on Windows (or with <literal>EXEC_BACKEND</literal>
+     defined). It may also malfunction when used to point to a function in a
+     dynamically loaded shared library used by a dynamic background worker.
+    </para>
+   </warning>
   </para>
 
   <para>
    <structfield>bgw_library_name</structfield> is the name of a library in
    which the initial entry point for the background worker should be sought.
-   It is ignored unless <structfield>bgw_main</structfield> is NULL.
-   But if <structfield>bgw_main</structfield> is NULL, then the named library
-   will be dynamically loaded by the worker process and
-   <structfield>bgw_function_name</structfield> will be used to identify
-   the function to be called.
+   The named library will be dynamically loaded by the worker process and
+   <structfield>bgw_function_name</structfield> will be used to identify the
+   function to be called.  <structfield>bgw_library_name</structfield> is
+   ignored if <structfield>bgw_main</structfield> is non-NULL.
   </para>
 
   <para>
    <structfield>bgw_function_name</structfield> is the name of a function in
    a dynamically loaded library which should be used as the initial entry point
-   for a new background worker.  It is ignored unless
+   for a new background worker.
+
+   This function must take a single argument of type <type>Datum</> and return
+   <type>void</>.  <structfield>bgw_main_arg</structfield> will be passed to it
+   as its only argument. It signature is:
+
+   <programlisting>
+   /* Declaration */
+   PGDLLEXPORT extern void bgw_main_func_name(Datum main_arg);
+
+   /* Definition */
+   void bgw_main_func_name(Datum main_arg)
+   {
+     /* ... */
+   }
+   </programlisting>
+
+   Note that the global variable <literal>MyBgworkerEntry</literal>
+   points to a copy of the <structname>BackgroundWorker</structname> structure
+   passed at registration time. <structfield>bgw_main</structfield> should be
+   NULL; in that case, <structfield>bgw_library_name</structfield> and
+   <structfield>bgw_function_name</structfield> will be used to determine
+   the entry point.
+
+   <structfield>bgw_function_name</structfield> is ignored unless
    <structfield>bgw_main</structfield> is NULL.
   </para>
 
   <para>
+   <structfield>bgw_main_arg</structfield> is the <type>Datum</> argument
+   to the background worker main function. It should be set and fetched with
+   the Datum accessors, e.g. for an integer you should use
+   <function>Int32GetDatum</function> to set it and
+   <function>DatumGetInt32</function> to read it.
+   <warning>
+    <para>
+     On Windows (and anywhere else where <literal>EXEC_BACKEND</literal> is
+     defined) or in dynamic background workers it is not safe to pass a
+     <type>Datum</> by reference, only by value. If an argument is required is
+     safest to pass an int32 or other small value and use that as an index into
+     an array allocated in shared memory. If a value like a <type>cstring</> or
+     <type>text</type> is passed then the pointer won't be valid from the
+     postmaster and/or the new background worker process, leading to
+     crashes or undefined behavour.</para>
+   </warning>
+  </para>
+
+  <para>
    <structfield>bgw_notify_pid</structfield> is the PID of a PostgreSQL
    backend process to which the postmaster should send <literal>SIGUSR1</>
-   when the process is started or exits.  It should be 0 for workers registered
-   at postmaster startup time, or when the backend registering the worker does
+   when the process is started or exits, causing the notified process's latch
+   to be set.  It should be 0 for workers registered
+   at postmaster startup time, when the backend registering the worker does
    not wish to wait for the worker to start up.  Otherwise, it should be
    initialized to <literal>MyProcPid</>.
   </para>
 
   <para>Once running, the process can connect to a database by calling
+   <indexterm><primary>BackgroundWorkerInitializeConnection</primary></indexterm>
    <function>BackgroundWorkerInitializeConnection(<parameter>char *dbname</parameter>, <parameter>char *username</parameter>)</function> or
+   <indexterm><primary>BackgroundWorkerInitializeConnectionByOid</primary></indexterm>
    <function>BackgroundWorkerInitializeConnectionByOid(<parameter>Oid dboid</parameter>, <parameter>Oid useroid</parameter>)</function>.
    This allows the process to run transactions and queries using the
-   <literal>SPI</literal> interface.  If <varname>dbname</> is NULL or
+   <link linkend="spi">the Server Programming Interface (<acronym>SPI</acronym>)</link>. See <xref linkend="spi-bgworker">
+   for details. If <varname>dbname</> is NULL or
    <varname>dboid</> is <literal>InvalidOid</>, the session is not connected
-   to any particular database, but shared catalogs can be accessed.
+   to any particular database, but shared catalogs (tables where
+   <varname>relisshared</varname> is <literal>true</literal> in
+   <varname>pg_class</varname>) can be accessed.
    If <varname>username</> is NULL or <varname>useroid</> is
    <literal>InvalidOid</>, the process will run as the superuser created
    during <command>initdb</>.
    A background worker can only call one of these two functions, and only
-   once.  It is not possible to switch databases.
+   once.  It is not possible to switch databases without exiting and restarting
+   the background worker.
   </para>
 
   <para>
@@ -224,12 +306,22 @@ typedef struct BackgroundWorker
   </para>
 
   <para>
-   The <filename>worker_spi</> contrib module contains a working example,
-   which demonstrates some useful techniques.
+   Use of <link linkend="spi">the <acronym>SPI</acronym></link> to perform queries and access
+   database tables in a database-connected background worker requires explicit
+   management of transactions and snapshots. See <xref linkend="spi-bgworker">.
+   The same requirements apply to low-level access via direct scans.
+  </para>
+
+  <para>
+   The <link linkend="example-worker-spi">worker-spi</link> sample extension
+   contains a working example of a background worker that uses the
+   <acronym>SPI</acronym> and shared memory as well as some other useful
+   techniques.
   </para>
 
   <para>
    The maximum number of registered background workers is limited by
    <xref linkend="guc-max-worker-processes">.
   </para>
+
 </chapter>
diff --git a/doc/src/sgml/contrib.sgml b/doc/src/sgml/contrib.sgml
index a698d0f..4564274 100644
--- a/doc/src/sgml/contrib.sgml
+++ b/doc/src/sgml/contrib.sgml
@@ -136,6 +136,7 @@ CREATE EXTENSION <replaceable>module_name</> FROM unpackaged;
  &seg;
  &sepgsql;
  &contrib-spi;
+ &example-worker-spi;
  &sslinfo;
  &tablefunc;
  &tcn;
diff --git a/doc/src/sgml/example-worker-spi.sgml b/doc/src/sgml/example-worker-spi.sgml
new file mode 100644
index 0000000..63d8f3d
--- /dev/null
+++ b/doc/src/sgml/example-worker-spi.sgml
@@ -0,0 +1,26 @@
+<!-- doc/src/sgml/example-worker-spi.sgml -->
+
+<sect1 id="example-worker-spi" xreflabel="worker-spi">
+ <title>worker-spi example</title>
+
+ <indexterm zone="example-worker-spi">
+  <primary>Background worker with SPI</primary>
+  <secondary>SPI in background worker</secondary>
+ </indexterm>
+
+ <para>
+  The <application>worker-spi</> module provides a complete and working
+  example of a background worker that uses the SPI to query databases and
+  uses shared memory for communication. It is not intended for use except
+  as an example for developers.
+ </para>
+
+ <para>
+  It is located in <filename>src/test/modules/worker_spi</filename>.
+ </para>
+
+ <para>
+  Relevant documentation for this example module is in <xref linkend="bgworker"/>, <xref linkend="spi"/>, <xref linkend="xfunc"/> and <xref linkend="extend"/>.
+ </para>
+
+</sect1>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index f03b72a..7fa1896 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -142,6 +142,7 @@
 <!ENTITY postgres-fdw    SYSTEM "postgres-fdw.sgml">
 <!ENTITY seg             SYSTEM "seg.sgml">
 <!ENTITY contrib-spi     SYSTEM "contrib-spi.sgml">
+<!ENTITY example-worker-spi     SYSTEM "example-worker-spi.sgml">
 <!ENTITY sepgsql         SYSTEM "sepgsql.sgml">
 <!ENTITY sslinfo         SYSTEM "sslinfo.sgml">
 <!ENTITY tablefunc       SYSTEM "tablefunc.sgml">
diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
index cb85086..57914be 100644
--- a/doc/src/sgml/spi.sgml
+++ b/doc/src/sgml/spi.sgml
@@ -10,7 +10,8 @@
  <para>
   The <firstterm>Server Programming Interface</firstterm>
   (<acronym>SPI</acronym>) gives writers of user-defined
-  <acronym>C</acronym> functions the ability to run
+  <acronym>C</acronym> functions and <xref linkend="bgworker"/>
+  the ability to run
   <acronym>SQL</acronym> commands inside their functions.
   <acronym>SPI</acronym> is a set of
   interface functions to simplify access to the parser, planner,
@@ -363,6 +364,7 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar RETURNING *", false, 5);
    or the command counter, and it allows only plain <command>SELECT</>
    commands to appear in the command string.  The commands are executed
    using the snapshot previously established for the surrounding query.
+   Additional steps are required for <xref linkend="spi-bgworker"/>.
    This execution mode is somewhat faster than the read/write mode due
    to eliminating per-command overhead.  It also allows genuinely
    <firstterm>stable</> functions to be built: since successive executions
@@ -822,7 +824,9 @@ int SPI_execute_with_args(const char *<parameter>command</parameter>,
    <varlistentry>
     <term><literal>bool <parameter>read_only</parameter></literal></term>
     <listitem>
-     <para><literal>true</> for read-only execution</para>
+     <para><literal>true</> for read-only execution with no snapshot
+     or command counter management. See <function>SPI_execute</function>
+     for details.</para>
     </listitem>
    </varlistentry>
 
@@ -3361,7 +3365,8 @@ char * SPI_getnspname(Relation <parameter>rel</parameter>)
    <quote>upper executor context</quote>, that is, the memory context
    that was current when <function>SPI_connect</function> was called,
    which is precisely the right context for a value returned from your
-   procedure.
+   procedure. For direct control over the context used for allocation,
+   <function>MemoryContextAlloc</function> may be used.
   </para>
 
   <para>
@@ -4092,6 +4097,143 @@ INSERT INTO a SELECT * FROM a;
   </para>
  </sect1>
 
+ <sect1 id="spi-bgworker" xreflabel="SPI in background workers">
+  <title>Using the SPI from background workers</title>
+
+  <para>
+   Using the SPI from <link linkend="bgworker">background workers</>
+   requires some additional steps that are not required from SPI-using
+   procedures invoked via SQL from normal user backends. When using the SPI
+   from an SQL-callable function it is safe to assume that a transaction is
+   already open, there is already a snapshot, and that PostgreSQL's statistics
+   have been updated. None of these things may be assumed for use of the SPI
+   from a bgworker.
+  </para>
+
+  <para>
+   To safely use the SPI from a bgworker you must ensure that:
+  <itemizedlist>
+   <listitem><para>A transaction is open (in progress)</para></listitem>
+   <listitem><para>The SPI is connected</para></listitem>
+   <listitem><para>There is an active snapshot or <parameter>read_only</parameter> is set to <literal>false</literal> in SPI calls</para></listitem>
+  </itemizedlist>
+   You should also update the statement start and end timestamps for use in
+   <literal>pg_stat_activity</> using <function>pgstat_report_activity</>.
+  </para>
+
+  <para>
+   Attempting to use the SPI without an open transaction or using the SPI
+   in <parameter>read_only</parameter> mode without setting a snapshot will
+   generally <emphasis>not</emphasis> cause obvious failures or, in a
+   <literal>--enable-cassert</literal> build, assertions. Instead it will
+   usually appear to work for simple cases but may produce incorrect
+   results or be unstable. Users of background workers should generally
+   prefix SPI use with
+<programlisting>
+Assert(IsTransactionState());
+</programlisting>
+   if the function does not its self establish a transaction.
+  </para>
+
+  <para>
+   Typical SPI use from a background worker involves setting up a transaction,
+   setting the statement start timestamp, connecting to the SPI, updating
+   pg_stat_activity, establishing a snapshot, running the query/queries,
+   then performing matching cleanup actions. For example:
+  </para>
+
+<programlisting>
+const char * some_sql = "SELECT 1;";
+
+/* setup */
+StartTransactionCommand();
+SetCurrentStatementStartTimestamp();
+SPI_connect();
+PushActiveSnapshot(GetTransactionSnapshot());
+
+pgstat_report_activity(STATE_RUNNING, some_sql);
+
+/* Run queries with SPI, read_only = false ... */
+spi_ret = SPI_execute(some_sql, false);
+if (spi_ret != SPI_OK_TUPLES)
+    elog(ERROR, "SPI error: %d", spi_ret);
+
+/* ... process results, run more queries, etc ... */
+
+/* cleanup */
+SPI_finish();
+PopActiveSnapshot();
+CommitTransactionCommand();
+pgstat_report_activity(STATE_IDLE, NULL);
+</programlisting>
+
+  <para>
+   In more complex cases the function may need to check if a transaction is
+   already open with <function>IsTransactionState()</function> and only perform
+   transaction management if there is no current transaction. If the SPI may
+   already connected by the caller the function should use
+   <function>SPI_push_conditional</function> before <function>SPI_connect</function> and
+   <function>SPI_pop_conditional</function> after <function>SPI_finish</function>. Snapshot
+   state may also be conditionally handled. The resulting procedure will
+   look more like:
+  </para>
+
+<programlisting>
+const char * some_sql = "SELECT 1;";
+bool tx_started = false,
+     snapshot_pushed = false,
+     spi_pushed;
+
+/* setup */
+if (!IsTransactionCommand())
+{
+  StartTransactionCommand();
+  tx_started = true;
+}
+SetCurrentStatementStartTimestamp();
+if (!ActiveSnapshotSet())
+{
+  PushActiveSnapshot(GetTransactionSnapshot());
+  snapshot_pushed = true;
+}
+spi_pushed = SPI_push_conditional();
+SPI_connect();
+
+pgstat_report_activity(STATE_RUNNING, some_sql);
+
+/* Run queries with SPI, read_only = false... */
+spi_ret = SPI_execute(some_sql, false);
+if (spi_ret != SPI_OK_TUPLES)
+    elog(ERROR, "SPI error: %d", spi_ret);
+
+/* ... process results, run more queries, etc ... */
+
+/* cleanup */
+SPI_finish();
+if (snapshot_pushed)
+  PopActiveSnapshot();
+SPI_pop_conditional(spi_pushed);
+if (tx_started)
+  CommitTransactionCommand();
+pgstat_report_activity(STATE_IDLE, NULL);
+</programlisting>
+
+  <para>
+   If <parameter>read_only</parameter> is <literal>true</literal> for the SPI
+   execution functions then the caller should also manage the snapshot using
+   <function>PushActiveSnapshot</function> and
+   <function>PopActiveSnapshot</function>. If only <literal>read_only =
+   false</literal> SPI procedures are used then there is generally no need for
+   SPI users to explicitly manage snapshots.
+  </para>
+
+  <para>
+   See the <xref linkend="example-worker-spi"> module for a more detailed example of
+   SPI use in background workers.
+  </para>
+
+</sect1>
+
  <sect1 id="spi-examples">
   <title>Examples</title>
 
@@ -4103,7 +4245,8 @@ INSERT INTO a SELECT * FROM a;
    that were processed by the command.  You can find more complex
    examples for SPI in the source tree in
    <filename>src/test/regress/regress.c</filename> and in the
-   <xref linkend="contrib-spi"> module.
+   <xref linkend="contrib-spi"> module. For background-worker
+   specific SPI examples see <xref linkend="spi-bgworker"/>.
   </para>
 
 <programlisting>
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 6437ab1..39e6a15 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3357,6 +3357,60 @@ if (!ptr)
 }
 </programlisting>
     </para>
+
+    <para>
+     Extensions registered to run at startup
+     using <xref linkend="guc-shared-preload-libraries"> should instead install a
+     <literal>shmem_startup_hook</> from <function>_PG_init</>.  This will be
+     invoked once shared memory is ready but before user backends or background
+     workers get launched. The hook function invoked should use a pattern like
+     that shown for shared memory initialization above then call the next hook
+     function, e.g. declare:
+<programlisting>
+static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
+</programlisting>
+     then from <function>_PG_init</>, after any
+     <function>RequestAddinShmemSpace</> and <function>RequestAddinLWLocks</>
+     install the hook:
+<programlisting>
+     prev_shmem_startup_hook = shmem_startup_hook;
+     shmem_startup_hook = my_worker_shmem_startup;
+</programlisting>
+     where <function>my_worker_shmem_startup</function> is a <type>void</> function
+     with <type>void</> arguments that calls the next hook (if any):
+<programlisting>
+     if (prev_shmem_startup_hook != NULL)
+         prev_shmem_startup_hook();
+</programlisting>
+     then calls <function>ShmemInitStruct</> per the example shown above. An
+     example of this usage can be found in the initialisation of the <xref
+     linkend="pgstatstatements"> extension.
+    </para>
+
+     <caution>
+      <title>Shared memory is zeroed on postmaster restart</title>
+      <para>
+       If the postmaster restarts - usually due to the crash of a backend
+       process like a user backend or a background worker - then it zeroes
+       shared memory on restart then re-invokes any shared memory setup hooks
+       that have been installed by extensions. Extensions using shared memory
+       must be prepared for this.
+      </para>
+      <para>
+       Background workers are not unregistered if the postmaster restarts
+       due to the crash of a background worker or user backend. This can lead
+       to background workers accessing shared memory that has been reinitialized.
+       Care must be taken to ensure that initialisation of shared memory produces
+       stable results when re-run or workers must detect the postmaster restart
+       using a generation counter and exit. In particular if parameters are being
+       passed to a bgworker via shared memory the background worker
+       <structfield>bgw_main_arg</structfield> should always be an index into an
+       array allocated in shared memory, rather than a pointer, and repeated
+       initialisations of the shared memory segment must produce the same range
+       of valid indexes in the same order.
+      </para>
+     </caution>
+
    </sect2>
 
    <sect2 id="extend-Cpp" xreflabel="using C++ for extensibility">
-- 
2.1.0

