Use a ResourceOwner to track buffer pins in all cases.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 18 Jul 2018 16:15:16 +0000 (12:15 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 18 Jul 2018 16:15:16 +0000 (12:15 -0400)
Historically, we've allowed auxiliary processes to take buffer pins without
tracking them in a ResourceOwner.  However, that creates problems for error
recovery.  In particular, we've seen multiple reports of assertion crashes
in the startup process when it gets an error while holding a buffer pin,
as for example if it gets ENOSPC during a write.  In a non-assert build,
the process would simply exit without releasing the pin at all.  We've
gotten away with that so far just because a failure exit of the startup
process translates to a database crash anyhow; but any similar behavior
in other aux processes could result in stuck pins and subsequent problems
in vacuum.

To improve this, institute a policy that we must *always* have a resowner
backing any attempt to pin a buffer, which we can enforce just by removing
the previous special-case code in resowner.c.  Add infrastructure to make
it easy to create a process-lifespan AuxProcessResourceOwner and clear
out its contents at appropriate times.  Replace existing ad-hoc resowner
management in bgwriter.c and other aux processes with that.  (Thus, while
the startup process gains a resowner where it had none at all before, some
other aux process types are replacing an ad-hoc resowner with this code.)
Also use the AuxProcessResourceOwner to manage buffer pins taken during
StartupXLOG and ShutdownXLOG, even when those are being run in a bootstrap
process or a standalone backend rather than a true auxiliary process.

In passing, remove some other ad-hoc resource owner creations that had
gotten cargo-culted into various other places.  As far as I can tell
that was all unnecessary, and if it had been necessary it was incomplete,
due to lacking any provision for clearing those resowners later.
(Also worth noting in this connection is that a process that hasn't called
InitBufferPoolBackend has no business accessing buffers; so there's more
to do than just add the resowner if we want to touch buffers in processes
not covered by this patch.)

Although this fixes a very old bug, no back-patch, because there's no
evidence of any significant problem in non-assert builds.

Patch by me, pursuant to a report from Justin Pryzby.  Thanks to
Robert Haas and Kyotaro Horiguchi for reviews.

Discussion: https://postgr.es/m/20180627233939.GA10276@telsasoft.com

16 files changed:
src/backend/access/transam/parallel.c
src/backend/access/transam/xlog.c
src/backend/bootstrap/bootstrap.c
src/backend/postmaster/autovacuum.c
src/backend/postmaster/bgwriter.c
src/backend/postmaster/checkpointer.c
src/backend/postmaster/walwriter.c
src/backend/replication/logical/logicalfuncs.c
src/backend/replication/logical/worker.c
src/backend/replication/slotfuncs.c
src/backend/replication/walreceiver.c
src/backend/replication/walsender.c
src/backend/utils/init/postinit.c
src/backend/utils/resowner/resowner.c
src/include/utils/resowner.h
src/test/modules/test_shm_mq/worker.c

index 4e32cfff50020d2efec6351bc49abb5af5b76eef..30ddf94c952dfc2ac2874fc03d3072b21e947d0e 100644 (file)
@@ -37,7 +37,6 @@
 #include "utils/guc.h"
 #include "utils/inval.h"
 #include "utils/memutils.h"
-#include "utils/resowner.h"
 #include "utils/snapmgr.h"
 #include "utils/typcache.h"
 
@@ -1220,16 +1219,19 @@ ParallelWorkerMain(Datum main_arg)
    Assert(ParallelWorkerNumber == -1);
    memcpy(&ParallelWorkerNumber, MyBgworkerEntry->bgw_extra, sizeof(int));
 
-   /* Set up a memory context and resource owner. */
-   Assert(CurrentResourceOwner == NULL);
-   CurrentResourceOwner = ResourceOwnerCreate(NULL, "parallel toplevel");
+   /* Set up a memory context to work in, just for cleanliness. */
    CurrentMemoryContext = AllocSetContextCreate(TopMemoryContext,
                                                 "Parallel worker",
                                                 ALLOCSET_DEFAULT_SIZES);
 
    /*
-    * Now that we have a resource owner, we can attach to the dynamic shared
-    * memory segment and read the table of contents.
+    * Attach to the dynamic shared memory segment for the parallel query, and
+    * find its table of contents.
+    *
+    * Note: at this point, we have not created any ResourceOwner in this
+    * process.  This will result in our DSM mapping surviving until process
+    * exit, which is fine.  If there were a ResourceOwner, it would acquire
+    * ownership of the mapping, but we have no need for that.
     */
    seg = dsm_attach(DatumGetUInt32(main_arg));
    if (seg == NULL)
@@ -1393,7 +1395,7 @@ ParallelWorkerMain(Datum main_arg)
    /* Must exit parallel mode to pop active snapshot. */
    ExitParallelMode();
 
-   /* Must pop active snapshot so resowner.c doesn't complain. */
+   /* Must pop active snapshot so snapmgr.c doesn't complain. */
    PopActiveSnapshot();
 
    /* Shut down the parallel-worker transaction. */
index bebe6405de5e956b1e2d0340e6eb981cd1efcba7..3ee6d5c46764f34aa0cb9f0e5210ac86f619f9c1 100644 (file)
@@ -6360,6 +6360,15 @@ StartupXLOG(void)
    bool        fast_promoted = false;
    struct stat st;
 
+   /*
+    * We should have an aux process resource owner to use, and we should not
+    * be in a transaction that's installed some other resowner.
+    */
+   Assert(AuxProcessResourceOwner != NULL);
+   Assert(CurrentResourceOwner == NULL ||
+          CurrentResourceOwner == AuxProcessResourceOwner);
+   CurrentResourceOwner = AuxProcessResourceOwner;
+
    /*
     * Verify XLOG status looks valid.
     */
@@ -8472,6 +8481,15 @@ GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch)
 void
 ShutdownXLOG(int code, Datum arg)
 {
+   /*
+    * We should have an aux process resource owner to use, and we should not
+    * be in a transaction that's installed some other resowner.
+    */
+   Assert(AuxProcessResourceOwner != NULL);
+   Assert(CurrentResourceOwner == NULL ||
+          CurrentResourceOwner == AuxProcessResourceOwner);
+   CurrentResourceOwner = AuxProcessResourceOwner;
+
    /* Don't be chatty in standalone mode */
    ereport(IsPostmasterEnvironment ? LOG : NOTICE,
            (errmsg("shutting down")));
index 7e34bee63e0f5e238dcb96b8bb42e1c0043db70e..cdd71a9bc339bdc5ed4f42de88efab720d8cfaae 100644 (file)
@@ -403,6 +403,13 @@ AuxiliaryProcessMain(int argc, char *argv[])
        /* finish setting up bufmgr.c */
        InitBufferPoolBackend();
 
+       /*
+        * Auxiliary processes don't run transactions, but they may need a
+        * resource owner anyway to manage buffer pins acquired outside
+        * transactions (and, perhaps, other things in future).
+        */
+       CreateAuxProcessResourceOwner();
+
        /* Initialize backend status information */
        pgstat_initialize();
        pgstat_bestart();
index 78e4c85f5d78f4e5200ad41bde81b025d9cc1aff..1d9cfc63d2211eba8ecb9c3cc746939afc05bc19 100644 (file)
@@ -522,13 +522,9 @@ AutoVacLauncherMain(int argc, char *argv[])
        pgstat_report_wait_end();
        AbortBufferIO();
        UnlockBuffers();
-       if (CurrentResourceOwner)
-       {
-           ResourceOwnerRelease(CurrentResourceOwner,
-                                RESOURCE_RELEASE_BEFORE_LOCKS,
-                                false, true);
-           /* we needn't bother with the other ResourceOwnerRelease phases */
-       }
+       /* this is probably dead code, but let's be safe: */
+       if (AuxProcessResourceOwner)
+           ReleaseAuxProcessResources(false);
        AtEOXact_Buffers(false);
        AtEOXact_SMgr();
        AtEOXact_Files(false);
index d5ce685e54f7f98c15ee7fabd5d1b24c8e061fb9..960d3de2040e73b3a66ccf5a2ae6aa63a9ea40ff 100644 (file)
@@ -141,12 +141,6 @@ BackgroundWriterMain(void)
    /* We allow SIGQUIT (quickdie) at all times */
    sigdelset(&BlockSig, SIGQUIT);
 
-   /*
-    * Create a resource owner to keep track of our resources (currently only
-    * buffer pins).
-    */
-   CurrentResourceOwner = ResourceOwnerCreate(NULL, "Background Writer");
-
    /*
     * We just started, assume there has been either a shutdown or
     * end-of-recovery snapshot.
@@ -191,11 +185,7 @@ BackgroundWriterMain(void)
        ConditionVariableCancelSleep();
        AbortBufferIO();
        UnlockBuffers();
-       /* buffer pins are released here: */
-       ResourceOwnerRelease(CurrentResourceOwner,
-                            RESOURCE_RELEASE_BEFORE_LOCKS,
-                            false, true);
-       /* we needn't bother with the other ResourceOwnerRelease phases */
+       ReleaseAuxProcessResources(false);
        AtEOXact_Buffers(false);
        AtEOXact_SMgr();
        AtEOXact_Files(false);
index 0950ada6019e20a17728c4ac7f48033603297e13..de1b22d04558fc938225eea011d6b66e63e69df7 100644 (file)
@@ -231,12 +231,6 @@ CheckpointerMain(void)
     */
    last_checkpoint_time = last_xlog_switch_time = (pg_time_t) time(NULL);
 
-   /*
-    * Create a resource owner to keep track of our resources (currently only
-    * buffer pins).
-    */
-   CurrentResourceOwner = ResourceOwnerCreate(NULL, "Checkpointer");
-
    /*
     * Create a memory context that we will do all our work in.  We do this so
     * that we can reset the context during error recovery and thereby avoid
@@ -275,11 +269,7 @@ CheckpointerMain(void)
        pgstat_report_wait_end();
        AbortBufferIO();
        UnlockBuffers();
-       /* buffer pins are released here: */
-       ResourceOwnerRelease(CurrentResourceOwner,
-                            RESOURCE_RELEASE_BEFORE_LOCKS,
-                            false, true);
-       /* we needn't bother with the other ResourceOwnerRelease phases */
+       ReleaseAuxProcessResources(false);
        AtEOXact_Buffers(false);
        AtEOXact_SMgr();
        AtEOXact_Files(false);
index 688d5b5b80bf8728c9558d54c2929aa6aeef62b0..eceed1bf8829b9329e1a710e25f5561917e7b91f 100644 (file)
@@ -129,12 +129,6 @@ WalWriterMain(void)
    /* We allow SIGQUIT (quickdie) at all times */
    sigdelset(&BlockSig, SIGQUIT);
 
-   /*
-    * Create a resource owner to keep track of our resources (not clear that
-    * we need this, but may as well have one).
-    */
-   CurrentResourceOwner = ResourceOwnerCreate(NULL, "Wal Writer");
-
    /*
     * Create a memory context that we will do all our work in.  We do this so
     * that we can reset the context during error recovery and thereby avoid
@@ -172,11 +166,7 @@ WalWriterMain(void)
        pgstat_report_wait_end();
        AbortBufferIO();
        UnlockBuffers();
-       /* buffer pins are released here: */
-       ResourceOwnerRelease(CurrentResourceOwner,
-                            RESOURCE_RELEASE_BEFORE_LOCKS,
-                            false, true);
-       /* we needn't bother with the other ResourceOwnerRelease phases */
+       ReleaseAuxProcessResources(false);
        AtEOXact_Buffers(false);
        AtEOXact_SMgr();
        AtEOXact_Files(false);
index 54c25f1f5b2cf26245c38ffd67a5108188d9fb44..45aae71a493f9a920f1819f056bf83693302404c 100644 (file)
@@ -279,8 +279,6 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
         */
        startptr = MyReplicationSlot->data.restart_lsn;
 
-       CurrentResourceOwner = ResourceOwnerCreate(CurrentResourceOwner, "logical decoding");
-
        /* invalidate non-timetravel entries */
        InvalidateSystemCaches();
 
@@ -320,6 +318,11 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
 
        tuplestore_donestoring(tupstore);
 
+       /*
+        * Logical decoding could have clobbered CurrentResourceOwner during
+        * transaction management, so restore the executor's value.  (This is
+        * a kluge, but it's not worth cleaning up right now.)
+        */
        CurrentResourceOwner = old_resowner;
 
        /*
index 0d2b795e392d1952e361688a2876e7d88dbee63d..6ca6cdcacfaf0d421ec50f06471e1c8ad08d9698 100644 (file)
@@ -1595,6 +1595,11 @@ ApplyWorkerMain(Datum main_arg)
    pqsignal(SIGTERM, die);
    BackgroundWorkerUnblockSignals();
 
+   /*
+    * We don't currently need any ResourceOwner in a walreceiver process, but
+    * if we did, we could call CreateAuxProcessResourceOwner here.
+    */
+
    /* Initialise stats to a sanish value */
    MyLogicalRepWorker->last_send_time = MyLogicalRepWorker->last_recv_time =
        MyLogicalRepWorker->reply_time = GetCurrentTimestamp();
@@ -1602,10 +1607,6 @@ ApplyWorkerMain(Datum main_arg)
    /* Load the libpq-specific functions */
    load_file("libpqwalreceiver", false);
 
-   Assert(CurrentResourceOwner == NULL);
-   CurrentResourceOwner = ResourceOwnerCreate(NULL,
-                                              "logical replication apply");
-
    /* Run as replica session replication role. */
    SetConfigOption("session_replication_role", "replica",
                    PGC_SUSET, PGC_S_OVERRIDE);
index 450f73759f972963a01c85c9b04c2aaffe0cdca9..6d7474a976c6c46a4d4379d8fd955616ddb187b9 100644 (file)
@@ -365,9 +365,6 @@ pg_logical_replication_slot_advance(XLogRecPtr moveto)
                                    logical_read_local_xlog_page,
                                    NULL, NULL, NULL);
 
-       CurrentResourceOwner = ResourceOwnerCreate(CurrentResourceOwner,
-                                                  "logical decoding");
-
        /* invalidate non-timetravel entries */
        InvalidateSystemCaches();
 
@@ -402,6 +399,11 @@ pg_logical_replication_slot_advance(XLogRecPtr moveto)
            CHECK_FOR_INTERRUPTS();
        }
 
+       /*
+        * Logical decoding could have clobbered CurrentResourceOwner during
+        * transaction management, so restore the executor's value.  (This is
+        * a kluge, but it's not worth cleaning up right now.)
+        */
        CurrentResourceOwner = old_resowner;
 
        if (ctx->reader->EndRecPtr != InvalidXLogRecPtr)
index 987bb84683c4e8431b98b4e4af28e61a9f05ea6a..7c292d8071b9c8c45bb9bb9bafe71d1970ad2abd 100644 (file)
@@ -292,12 +292,6 @@ WalReceiverMain(void)
    if (WalReceiverFunctions == NULL)
        elog(ERROR, "libpqwalreceiver didn't initialize correctly");
 
-   /*
-    * Create a resource owner to keep track of our resources (not clear that
-    * we need this, but may as well have one).
-    */
-   CurrentResourceOwner = ResourceOwnerCreate(NULL, "Wal Receiver");
-
    /* Unblock signals (they were blocked when the postmaster forked us) */
    PG_SETMASK(&UnBlockSig);
 
index 76954831cee09ef2078db40cddc0d68d86eabbca..e8f4f37e5ce696bfa00af5c04528663ef830980d 100644 (file)
@@ -90,7 +90,6 @@
 #include "utils/pg_lsn.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
-#include "utils/resowner.h"
 #include "utils/timeout.h"
 #include "utils/timestamp.h"
 
@@ -264,8 +263,10 @@ InitWalSender(void)
    /* Create a per-walsender data structure in shared memory */
    InitWalSenderSlot();
 
-   /* Set up resource owner */
-   CurrentResourceOwner = ResourceOwnerCreate(NULL, "walsender top-level resource owner");
+   /*
+    * We don't currently need any ResourceOwner in a walsender process, but
+    * if we did, we could call CreateAuxProcessResourceOwner here.
+    */
 
    /*
     * Let postmaster know that we're a WAL sender. Once we've declared us as
index 09e0df290dd46c4bc4e213b9eca76eb8429edfec..5ef6315d20614ca7382450768877ba2cebeb9f25 100644 (file)
@@ -632,8 +632,19 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
         * We are either a bootstrap process or a standalone backend. Either
         * way, start up the XLOG machinery, and register to have it closed
         * down at exit.
+        *
+        * We don't yet have an aux-process resource owner, but StartupXLOG
+        * and ShutdownXLOG will need one.  Hence, create said resource owner
+        * (and register a callback to clean it up after ShutdownXLOG runs).
         */
+       CreateAuxProcessResourceOwner();
+
        StartupXLOG();
+       /* Release (and warn about) any buffer pins leaked in StartupXLOG */
+       ReleaseAuxProcessResources(true);
+       /* Reset CurrentResourceOwner to nothing for the moment */
+       CurrentResourceOwner = NULL;
+
        on_shmem_exit(ShutdownXLOG, 0);
    }
 
index bce021e1001dff306570232af10e1f03e5302b23..211833da02c80b7b06fe943cd303fd88e10e24df 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "access/hash.h"
 #include "jit/jit.h"
+#include "storage/ipc.h"
 #include "storage/predicate.h"
 #include "storage/proc.h"
 #include "utils/memutils.h"
@@ -140,6 +141,7 @@ typedef struct ResourceOwnerData
 ResourceOwner CurrentResourceOwner = NULL;
 ResourceOwner CurTransactionResourceOwner = NULL;
 ResourceOwner TopTransactionResourceOwner = NULL;
+ResourceOwner AuxProcessResourceOwner = NULL;
 
 /*
  * List of add-on callbacks for resource releasing
@@ -165,6 +167,7 @@ static void ResourceOwnerReleaseInternal(ResourceOwner owner,
                             ResourceReleasePhase phase,
                             bool isCommit,
                             bool isTopLevel);
+static void ReleaseAuxProcessResourcesCallback(int code, Datum arg);
 static void PrintRelCacheLeakWarning(Relation rel);
 static void PrintPlanCacheLeakWarning(CachedPlan *plan);
 static void PrintTupleDescLeakWarning(TupleDesc tupdesc);
@@ -823,6 +826,60 @@ UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
    }
 }
 
+/*
+ * Establish an AuxProcessResourceOwner for the current process.
+ */
+void
+CreateAuxProcessResourceOwner(void)
+{
+   Assert(AuxProcessResourceOwner == NULL);
+   Assert(CurrentResourceOwner == NULL);
+   AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
+   CurrentResourceOwner = AuxProcessResourceOwner;
+
+   /*
+    * Register a shmem-exit callback for cleanup of aux-process resource
+    * owner.  (This needs to run after, e.g., ShutdownXLOG.)
+    */
+   on_shmem_exit(ReleaseAuxProcessResourcesCallback, 0);
+
+}
+
+/*
+ * Convenience routine to release all resources tracked in
+ * AuxProcessResourceOwner (but that resowner is not destroyed here).
+ * Warn about leaked resources if isCommit is true.
+ */
+void
+ReleaseAuxProcessResources(bool isCommit)
+{
+   /*
+    * At this writing, the only thing that could actually get released is
+    * buffer pins; but we may as well do the full release protocol.
+    */
+   ResourceOwnerRelease(AuxProcessResourceOwner,
+                        RESOURCE_RELEASE_BEFORE_LOCKS,
+                        isCommit, true);
+   ResourceOwnerRelease(AuxProcessResourceOwner,
+                        RESOURCE_RELEASE_LOCKS,
+                        isCommit, true);
+   ResourceOwnerRelease(AuxProcessResourceOwner,
+                        RESOURCE_RELEASE_AFTER_LOCKS,
+                        isCommit, true);
+}
+
+/*
+ * Shmem-exit callback for the same.
+ * Warn about leaked resources if process exit code is zero (ie normal).
+ */
+static void
+ReleaseAuxProcessResourcesCallback(int code, Datum arg)
+{
+   bool        isCommit = (code == 0);
+
+   ReleaseAuxProcessResources(isCommit);
+}
+
 
 /*
  * Make sure there is room for at least one more entry in a ResourceOwner's
@@ -830,15 +887,12 @@ UnregisterResourceReleaseCallback(ResourceReleaseCallback callback, void *arg)
  *
  * This is separate from actually inserting an entry because if we run out
  * of memory, it's critical to do so *before* acquiring the resource.
- *
- * We allow the case owner == NULL because the bufmgr is sometimes invoked
- * outside any transaction (for example, during WAL recovery).
  */
 void
 ResourceOwnerEnlargeBuffers(ResourceOwner owner)
 {
-   if (owner == NULL)
-       return;
+   /* We used to allow pinning buffers without a resowner, but no more */
+   Assert(owner != NULL);
    ResourceArrayEnlarge(&(owner->bufferarr));
 }
 
@@ -846,29 +900,19 @@ ResourceOwnerEnlargeBuffers(ResourceOwner owner)
  * Remember that a buffer pin is owned by a ResourceOwner
  *
  * Caller must have previously done ResourceOwnerEnlargeBuffers()
- *
- * We allow the case owner == NULL because the bufmgr is sometimes invoked
- * outside any transaction (for example, during WAL recovery).
  */
 void
 ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
 {
-   if (owner == NULL)
-       return;
    ResourceArrayAdd(&(owner->bufferarr), BufferGetDatum(buffer));
 }
 
 /*
  * Forget that a buffer pin is owned by a ResourceOwner
- *
- * We allow the case owner == NULL because the bufmgr is sometimes invoked
- * outside any transaction (for example, during WAL recovery).
  */
 void
 ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
 {
-   if (owner == NULL)
-       return;
    if (!ResourceArrayRemove(&(owner->bufferarr), BufferGetDatum(buffer)))
        elog(ERROR, "buffer %d is not owned by resource owner %s",
             buffer, owner->name);
index fe7f49119bab39247e9abe5c12b9085a1ec648ef..fa03942b6c56894e6c5a4adce60156cdd859f925 100644 (file)
@@ -33,6 +33,7 @@ typedef struct ResourceOwnerData *ResourceOwner;
 extern PGDLLIMPORT ResourceOwner CurrentResourceOwner;
 extern PGDLLIMPORT ResourceOwner CurTransactionResourceOwner;
 extern PGDLLIMPORT ResourceOwner TopTransactionResourceOwner;
+extern PGDLLIMPORT ResourceOwner AuxProcessResourceOwner;
 
 /*
  * Resource releasing is done in three phases: pre-locks, locks, and
@@ -78,5 +79,7 @@ extern void RegisterResourceReleaseCallback(ResourceReleaseCallback callback,
                                void *arg);
 extern void UnregisterResourceReleaseCallback(ResourceReleaseCallback callback,
                                  void *arg);
+extern void CreateAuxProcessResourceOwner(void);
+extern void ReleaseAuxProcessResources(bool isCommit);
 
 #endif                         /* RESOWNER_H */
index bcb992e1e43b7a21834ba3d91173d232f6df499f..4e23419c52e4052ed52659382be772111bc61ea6 100644 (file)
@@ -24,7 +24,6 @@
 #include "storage/procarray.h"
 #include "storage/shm_mq.h"
 #include "storage/shm_toc.h"
-#include "utils/resowner.h"
 
 #include "test_shm_mq.h"
 
@@ -69,13 +68,16 @@ test_shm_mq_main(Datum main_arg)
     * Connect to the dynamic shared memory segment.
     *
     * The backend that registered this worker passed us the ID of a shared
-    * memory segment to which we must attach for further instructions.  In
-    * order to attach to dynamic shared memory, we need a resource owner.
-    * Once we've mapped the segment in our address space, attach to the table
-    * of contents so we can locate the various data structures we'll need to
+    * memory segment to which we must attach for further instructions.  Once
+    * we've mapped the segment in our address space, attach to the table of
+    * contents so we can locate the various data structures we'll need to
     * find within the segment.
+    *
+    * Note: at this point, we have not created any ResourceOwner in this
+    * process.  This will result in our DSM mapping surviving until process
+    * exit, which is fine.  If there were a ResourceOwner, it would acquire
+    * ownership of the mapping, but we have no need for that.
     */
-   CurrentResourceOwner = ResourceOwnerCreate(NULL, "test_shm_mq worker");
    seg = dsm_attach(DatumGetInt32(main_arg));
    if (seg == NULL)
        ereport(ERROR,
@@ -133,10 +135,8 @@ test_shm_mq_main(Datum main_arg)
    copy_messages(inqh, outqh);
 
    /*
-    * We're done.  Explicitly detach the shared memory segment so that we
-    * don't get a resource leak warning at commit time.  This will fire any
-    * on_dsm_detach callbacks we've registered, as well.  Once that's done,
-    * we can go ahead and exit.
+    * We're done.  For cleanliness, explicitly detach from the shared memory
+    * segment (that would happen anyway during process exit, though).
     */
    dsm_detach(seg);
    proc_exit(1);