On Sat, Oct 17, 2020 at 08:39:35AM -0700, Peter Geoghegan wrote:
> On Tue, Oct 13, 2020 at 7:26 PM Noah Misch <n...@leadboat.com> wrote:
> > 1. Disable parallelism for the index build under ExecuteTruncateGuts().
> >    Nobody will mourn a performance loss from declining parallelism for an
> >    empty index, but I feel like this is fixing in the wrong place.
> > 2. Make _bt_begin_parallel() and begin_parallel_vacuum() recognize the
> >    debug_query_string==NULL case and reproduce it on the worker.
> > 3. Require bgworkers to set debug_query_string before entering code of 
> > vacuum,
> >    truncate, etc.  Logical replication might synthesize a DDL statement, or 
> > it
> >    might just use a constant string.
> >
> > I tend to prefer (2), but (3) isn't bad.  Opinions?
> 
> I also prefer 2.

Thanks.  Here is the pair of patches I plan to use.  The second is equivalent
to v0; I just added a log message.
Author:     Noah Misch <n...@leadboat.com>
Commit:     Noah Misch <n...@leadboat.com>

    Reproduce debug_query_string==NULL on parallel workers.
    
    Certain background workers initiate parallel queries while
    debug_query_string==NULL, at which point they attempted strlen(NULL) and
    died to SIGSEGV.  Older debug_query_string observers allow NULL, so do
    likewise in these newer ones.  Back-patch to v11, where commit
    7de4a1bcc56f494acbd0d6e70781df877dc8ecb5 introduced the first of these.
    
    Reviewed by FIXME.
    
    Discussion: https://postgr.es/m/20201014022636.ga1962...@rfd.leadboat.com

diff --git a/src/backend/access/heap/vacuumlazy.c 
b/src/backend/access/heap/vacuumlazy.c
index 4f2f381..34ae8aa 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -3238,7 +3238,6 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, 
LVRelStats *vacrelstats,
        WalUsage   *wal_usage;
        bool       *can_parallel_vacuum;
        long            maxtuples;
-       char       *sharedquery;
        Size            est_shared;
        Size            est_deadtuples;
        int                     nindexes_mwm = 0;
@@ -3335,9 +3334,14 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, 
LVRelStats *vacrelstats,
        shm_toc_estimate_keys(&pcxt->estimator, 1);
 
        /* Finally, estimate PARALLEL_VACUUM_KEY_QUERY_TEXT space */
-       querylen = strlen(debug_query_string);
-       shm_toc_estimate_chunk(&pcxt->estimator, querylen + 1);
-       shm_toc_estimate_keys(&pcxt->estimator, 1);
+       if (debug_query_string)
+       {
+               querylen = strlen(debug_query_string);
+               shm_toc_estimate_chunk(&pcxt->estimator, querylen + 1);
+               shm_toc_estimate_keys(&pcxt->estimator, 1);
+       }
+       else
+               querylen = 0;                   /* keep compiler quiet */
 
        InitializeParallelDSM(pcxt);
 
@@ -3382,10 +3386,16 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, 
LVRelStats *vacrelstats,
        lps->wal_usage = wal_usage;
 
        /* Store query string for workers */
-       sharedquery = (char *) shm_toc_allocate(pcxt->toc, querylen + 1);
-       memcpy(sharedquery, debug_query_string, querylen + 1);
-       sharedquery[querylen] = '\0';
-       shm_toc_insert(pcxt->toc, PARALLEL_VACUUM_KEY_QUERY_TEXT, sharedquery);
+       if (debug_query_string)
+       {
+               char       *sharedquery;
+
+               sharedquery = (char *) shm_toc_allocate(pcxt->toc, querylen + 
1);
+               memcpy(sharedquery, debug_query_string, querylen + 1);
+               sharedquery[querylen] = '\0';
+               shm_toc_insert(pcxt->toc,
+                                          PARALLEL_VACUUM_KEY_QUERY_TEXT, 
sharedquery);
+       }
 
        pfree(can_parallel_vacuum);
        return lps;
@@ -3528,7 +3538,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
                elog(DEBUG1, "starting parallel vacuum worker for bulk delete");
 
        /* Set debug_query_string for individual workers */
-       sharedquery = shm_toc_lookup(toc, PARALLEL_VACUUM_KEY_QUERY_TEXT, 
false);
+       sharedquery = shm_toc_lookup(toc, PARALLEL_VACUUM_KEY_QUERY_TEXT, true);
        debug_query_string = sharedquery;
        pgstat_report_activity(STATE_RUNNING, debug_query_string);
 
diff --git a/src/backend/access/nbtree/nbtsort.c 
b/src/backend/access/nbtree/nbtsort.c
index efee867..8730de2 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -1466,7 +1466,6 @@ _bt_begin_parallel(BTBuildState *buildstate, bool 
isconcurrent, int request)
        WalUsage   *walusage;
        BufferUsage *bufferusage;
        bool            leaderparticipates = true;
-       char       *sharedquery;
        int                     querylen;
 
 #ifdef DISABLE_LEADER_PARTICIPATION
@@ -1533,9 +1532,14 @@ _bt_begin_parallel(BTBuildState *buildstate, bool 
isconcurrent, int request)
        shm_toc_estimate_keys(&pcxt->estimator, 1);
 
        /* Finally, estimate PARALLEL_KEY_QUERY_TEXT space */
-       querylen = strlen(debug_query_string);
-       shm_toc_estimate_chunk(&pcxt->estimator, querylen + 1);
-       shm_toc_estimate_keys(&pcxt->estimator, 1);
+       if (debug_query_string)
+       {
+               querylen = strlen(debug_query_string);
+               shm_toc_estimate_chunk(&pcxt->estimator, querylen + 1);
+               shm_toc_estimate_keys(&pcxt->estimator, 1);
+       }
+       else
+               querylen = 0;                   /* keep compiler quiet */
 
        /* Everyone's had a chance to ask for space, so now create the DSM */
        InitializeParallelDSM(pcxt);
@@ -1599,9 +1603,14 @@ _bt_begin_parallel(BTBuildState *buildstate, bool 
isconcurrent, int request)
        }
 
        /* Store query string for workers */
-       sharedquery = (char *) shm_toc_allocate(pcxt->toc, querylen + 1);
-       memcpy(sharedquery, debug_query_string, querylen + 1);
-       shm_toc_insert(pcxt->toc, PARALLEL_KEY_QUERY_TEXT, sharedquery);
+       if (debug_query_string)
+       {
+               char       *sharedquery;
+
+               sharedquery = (char *) shm_toc_allocate(pcxt->toc, querylen + 
1);
+               memcpy(sharedquery, debug_query_string, querylen + 1);
+               shm_toc_insert(pcxt->toc, PARALLEL_KEY_QUERY_TEXT, sharedquery);
+       }
 
        /*
         * Allocate space for each worker's WalUsage and BufferUsage; no need to
@@ -1806,7 +1815,7 @@ _bt_parallel_build_main(dsm_segment *seg, shm_toc *toc)
 #endif                                                 /* BTREE_BUILD_STATS */
 
        /* Set debug_query_string for individual workers first */
-       sharedquery = shm_toc_lookup(toc, PARALLEL_KEY_QUERY_TEXT, false);
+       sharedquery = shm_toc_lookup(toc, PARALLEL_KEY_QUERY_TEXT, true);
        debug_query_string = sharedquery;
 
        /* Report the query string from leader */
Author:     Noah Misch <n...@leadboat.com>
Commit:     Noah Misch <n...@leadboat.com>

    Set debug_query_string in worker_spi.
    
    This makes elog.c emit the string, which is good practice for a
    background worker that executes SQL strings.
    
    Reviewed by FIXME.
    
    Discussion: https://postgr.es/m/20201014022636.ga1962...@rfd.leadboat.com

diff --git a/src/test/modules/worker_spi/worker_spi.c 
b/src/test/modules/worker_spi/worker_spi.c
index 1c7b17c..daf6c1d 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -113,16 +113,17 @@ initialize_worker_spi(worktable *table)
        SPI_connect();
        PushActiveSnapshot(GetTransactionSnapshot());
        pgstat_report_activity(STATE_RUNNING, "initializing worker_spi schema");
 
        /* XXX could we use CREATE SCHEMA IF NOT EXISTS? */
        initStringInfo(&buf);
        appendStringInfo(&buf, "select count(*) from pg_namespace where nspname 
= '%s'",
                                         table->schema);
+       debug_query_string = buf.data;
 
        ret = SPI_execute(buf.data, true, 0);
        if (ret != SPI_OK_SELECT)
                elog(FATAL, "SPI_execute failed: error code %d", ret);
 
        if (SPI_processed != 1)
                elog(FATAL, "not a singleton result");
 
@@ -138,30 +139,32 @@ initialize_worker_spi(worktable *table)
                appendStringInfo(&buf,
                                                 "CREATE SCHEMA \"%s\" "
                                                 "CREATE TABLE \"%s\" ("
                                                 "              type text CHECK 
(type IN ('total', 'delta')), "
                                                 "              value   
integer)"
                                                 "CREATE UNIQUE INDEX 
\"%s_unique_total\" ON \"%s\" (type) "
                                                 "WHERE type = 'total'",
                                                 table->schema, table->name, 
table->name, table->name);
+               debug_query_string = buf.data;
 
                /* set statement start time */
                SetCurrentStatementStartTimestamp();
 
                ret = SPI_execute(buf.data, false, 0);
 
                if (ret != SPI_OK_UTILITY)
                        elog(FATAL, "failed to create my schema");
        }
 
        SPI_finish();
        PopActiveSnapshot();
        CommitTransactionCommand();
        pgstat_report_activity(STATE_IDLE, NULL);
+       debug_query_string = NULL;
 }
 
 void
 worker_spi_main(Datum main_arg)
 {
        int                     index = DatumGetInt32(main_arg);
        worktable  *table;
        StringInfoData buf;
@@ -206,16 +209,17 @@ worker_spi_main(Datum main_arg)
                                         "UPDATE %s.%s "
                                         "SET value = %s.value + total.sum "
                                         "FROM total WHERE type = 'total' "
                                         "RETURNING %s.value",
                                         table->schema, table->name,
                                         table->schema, table->name,
                                         table->name,
                                         table->name);
+       debug_query_string = buf.data;
 
        /*
         * Main loop: do this until the SIGTERM handler tells us to terminate
         */
        while (!got_sigterm)
        {
                int                     ret;
 

Reply via email to