bdr: Remove get_worker_option in favour of direct GUC access
authorCraig Ringer <[email protected]>
Wed, 30 Apr 2014 06:21:08 +0000 (14:21 +0800)
committerAndres Freund <[email protected]>
Thu, 3 Jul 2014 15:55:29 +0000 (17:55 +0200)
Store GUCs for each bdr.[connname] as members of a postmaster palloc'd struct
accessed via a global array. Pass BDR workers indexes into this array in shmem
so they know how to access their GUC values.

Fixes Andres's concerns with get_worker_option. This also makes it easier to
support EXEC_BACKEND later.

contrib/bdr/bdr.c
contrib/bdr/bdr.h
contrib/bdr/bdr_apply.c
contrib/bdr/bdr_init_replica.c

index e7206a192bb10689d816f40e0704501eb112950a..9668c7b7559ad08e45fb21aefde12e6906054a91 100644 (file)
@@ -62,6 +62,7 @@ static int   n_configured_bdr_nodes = 0;
 ResourceOwner bdr_saved_resowner;
 static bool bdr_is_restart = false;
 Oid   BdrNodesRelid;
+BdrConnectionConfig  **bdr_connection_configs;
 
 /* GUC storage */
 static char *connections = NULL;
@@ -70,8 +71,14 @@ int bdr_default_apply_delay;
 int bdr_max_workers;
 static bool bdr_skip_ddl_replication;
 
-/* TODO: Remove when bdr_apply_main moved into bdr_apply.c */
+/*
+ * These globals are valid only for apply bgworkers, not for
+ * bdr running in the postmaster or for per-db workers.
+ *
+ * TODO: move into bdr_apply.c when bdr_apply_main moved.
+ */
 extern BdrApplyWorker *bdr_apply_worker;
+extern BdrConnectionConfig *bdr_apply_config;
 
 /* shmem init hook to chain to on startup, if any */
 static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
@@ -79,35 +86,6 @@ static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
 /* shortcut for finding the the worker shmem block */
 BdrWorkerControl *BdrWorkerCtl = NULL;
 
-/*
- * Used only in postmaster to pass data from _PG_init during
- * shared_preload_libraries into the shared memory startup hook.
- */
-typedef struct BdrStartupContext
-{
-   /* List of palloc'd BdrApplyWorker instances to copy into shmem */
-   List    *workers;
-} BdrStartupContext;
-
-static BdrStartupContext *bdr_startup_context;
-
-/*
- * We need somewhere to store config options for each bdr apply worker when
- * we're creating the GUCs for each worker in the postmaster during startup.
- *
- * This isn't directly accessible to workers as we don't keep a pointer to it
- * anywhere, and in EXEC_BACKEND cases it'd be useless because it wouldn't be
- * preserved across fork() anyway. Workers have to use GetConfigOption to
- * access these values.
- */
-typedef struct BdrApplyWorkerConfigOptions
-{
-   char *dsn;
-   int   apply_delay;
-   bool  bdr_init_replica;
-   char *replica_local_dsn;
-} BdrApplyWorkerConfigOptions;
-
 PG_MODULE_MAGIC;
 
 void       _PG_init(void);
@@ -465,35 +443,6 @@ bdr_worker_init(char *dbname)
                        PGC_BACKEND, PGC_S_OVERRIDE);   /* other context? */
 }
 
-/*
- * GetConfigOption wrapper that gets an option name qualified by the worker's
- * name.
- *
- * The returned string is *not* modifiable and will only be valid until the
- * next GUC-related call.
- */
-const char *
-bdr_get_worker_option(const char * worker_name, const char * option_name,
-                     bool missing_ok)
-{
-   char       *gucname;
-   size_t      namelen;
-   const char *optval;
-
-   /* Option names should omit leading underscore */
-   Assert(option_name[0] != '_');
-
-   namelen = sizeof("bdr.") + strlen(worker_name) + strlen(option_name) + 3;
-   gucname = palloc(namelen);
-   snprintf(gucname, namelen, "bdr.%s_%s", worker_name, option_name);
-
-   optval = GetConfigOption(gucname, missing_ok, false);
-
-   pfree(gucname);
-
-   return optval;
-}
-
 /*
  *----------------------
  * Connect to the BDR remote end, IDENTIFY_SYSTEM, and CREATE_SLOT if necessary.
@@ -516,19 +465,17 @@ bdr_get_worker_option(const char * worker_name, const char * option_name,
  *----------------------
  */
 PGconn*
-bdr_establish_connection_and_slot(Name connection_name, Name out_slot_name,
+bdr_establish_connection_and_slot(BdrConnectionConfig *cfg, Name out_slot_name,
    uint64 *out_sysid, TimeLineID* out_timeline, RepNodeId
    *out_replication_identifier, char **out_snapshot)
 {
    char        conninfo_repl[MAXCONNINFO + 75];
-   const char *dsn;
    char        remote_ident[256];
    PGconn     *streamConn;
 
-   dsn = bdr_get_worker_option(NameStr(*connection_name), "dsn", false);
    snprintf(conninfo_repl, sizeof(conninfo_repl),
             "%s replication=database fallback_application_name=bdr",
-            dsn);
+            cfg->dsn);
 
    /* Establish BDR conn and IDENTIFY_SYSTEM */
    streamConn = bdr_connect(
@@ -597,16 +544,19 @@ bdr_apply_main(Datum main_arg)
    Assert(bdr_worker_slot->worker_type == BDR_WORKER_APPLY);
    bdr_apply_worker = &bdr_worker_slot->worker_data.apply_worker;
 
-   bdr_worker_init(NameStr(bdr_apply_worker->dbname));
+   bdr_apply_config = bdr_connection_configs[bdr_apply_worker->connection_config_idx];
+   Assert(bdr_apply_config != NULL);
+
+   bdr_worker_init(NameStr(bdr_apply_config->dbname));
 
    CurrentResourceOwner = ResourceOwnerCreate(NULL, "bdr apply top-level resource owner");
    bdr_saved_resowner = CurrentResourceOwner;
 
    elog(LOG, "%s initialized on %s",
-        MyBgworkerEntry->bgw_name, NameStr(bdr_apply_worker->dbname));
+        MyBgworkerEntry->bgw_name, NameStr(bdr_apply_config->dbname));
 
    streamConn = bdr_establish_connection_and_slot(
-       &bdr_apply_worker->name, &slot_name, &bdr_apply_worker->sysid,
+       bdr_apply_config, &slot_name, &bdr_apply_worker->sysid,
        &bdr_apply_worker->timeline, &replication_identifier, NULL);
 
    bdr_apply_worker->origin_id = replication_identifier;
@@ -821,36 +771,39 @@ bdr_apply_main(Datum main_arg)
  *  num_used_databases
  *  Number of distinct databases named in conns
  *
- * out_worker
- * Initialize this BdrApplyWorker with the name and dbname found.
+ * out_config
+ *  Assigned a palloc'd pointer to GUC storage for this config'd connection
  *
- * TODO At some point we'll have to make the GUC setup dynamic so we can
- * handle workers being added/removed with a config reload SIGHUP.
+ * out_config is set even if false is returned, as the GUCs have still been
+ * created. Test out_config->is_valid to see whether the connection is usable.
  */
 static bool
 bdr_create_con_gucs(char  *name,
                    char **used_databases,
                    Size  *num_used_databases,
                    char **database_initcons,
-                   BdrApplyWorker *out_worker)
+                   BdrConnectionConfig **out_config)
 {
    int         off;
    char       *errmsg = NULL;
    PQconninfoOption *options;
    PQconninfoOption *cur_option;
-   BdrApplyWorkerConfigOptions *opts;
+   BdrConnectionConfig *opts;
 
    /* don't free, referenced by the guc machinery! */
    char       *optname_dsn = palloc(strlen(name) + 30);
    char       *optname_delay = palloc(strlen(name) + 30);
    char       *optname_replica = palloc(strlen(name) + 30);
    char       *optname_local_dsn = palloc(strlen(name) + 30);
-   opts = palloc(sizeof(BdrApplyWorkerConfigOptions));
 
    Assert(process_shared_preload_libraries_in_progress);
 
-   strncpy(NameStr(out_worker->name), name, NAMEDATALEN);
-   NameStr(out_worker->name)[NAMEDATALEN-1] = '\0';
+   opts = palloc0(sizeof(BdrConnectionConfig));
+   opts->is_valid = false;
+   *out_config = opts;
+
+   strncpy(NameStr(opts->name), name, NAMEDATALEN);
+   NameStr(opts->name)[NAMEDATALEN-1] = '\0';
 
    sprintf(optname_dsn, "bdr.%s_dsn", name);
    DefineCustomStringVariable(optname_dsn,
@@ -875,7 +828,7 @@ bdr_create_con_gucs(char  *name,
    DefineCustomBoolVariable(optname_replica,
                             optname_replica,
                             NULL,
-                            &opts->bdr_init_replica,
+                            &opts->init_replica,
                             false,
                             PGC_SIGHUP,
                             0,
@@ -892,11 +845,11 @@ bdr_create_con_gucs(char  *name,
 
    if (!opts->dsn)
    {
-       elog(WARNING, "no connection information for %s", name);
+       elog(WARNING, "bdr %s: no connection information", name);
        return false;
    }
 
-   elog(LOG, "bgworkers, connection: %s", opts->dsn);
+   elog(DEBUG2, "bdr %s: dsn=%s", name, opts->dsn);
 
    options = PQconninfoParse(opts->dsn, &errmsg);
    if (errmsg != NULL)
@@ -913,17 +866,18 @@ bdr_create_con_gucs(char  *name,
        if (strcmp(cur_option->keyword, "dbname") == 0)
        {
            if (cur_option->val == NULL)
-               elog(ERROR, "no dbname set");
+               elog(ERROR, "bdr %s: no dbname set", name);
 
-           strncpy(NameStr(out_worker->dbname), cur_option->val,
+           strncpy(NameStr(opts->dbname), cur_option->val,
                    NAMEDATALEN);
-           NameStr(out_worker->dbname)[NAMEDATALEN-1] = '\0';
+           NameStr(opts->dbname)[NAMEDATALEN-1] = '\0';
+           elog(DEBUG2, "bdr %s: dbname=%s", name, NameStr(opts->dbname));
        }
 
        if (cur_option->val != NULL)
        {
-           elog(LOG, "option: %s, val: %s",
-                cur_option->keyword, cur_option->val);
+           elog(DEBUG3, "bdr %s: opt %s, val: %s",
+                name, cur_option->keyword, cur_option->val);
        }
        cur_option++;
    }
@@ -937,7 +891,7 @@ bdr_create_con_gucs(char  *name,
     */
    for (off = 0; off < *num_used_databases; off++)
    {
-       if (strcmp(NameStr(out_worker->dbname), used_databases[off]) == 0)
+       if (strcmp(NameStr(opts->dbname), used_databases[off]) == 0)
            break;
    }
 
@@ -945,15 +899,18 @@ bdr_create_con_gucs(char  *name,
    {
        /* Didn't find a match, add new db name */
        used_databases[(*num_used_databases)++] =
-           pstrdup(NameStr(out_worker->dbname));
+           pstrdup(NameStr(opts->dbname));
+       elog(DEBUG2, "bdr %s: Saw new database %s, now %i known dbs",
+            name, NameStr(opts->dbname), (int)(*num_used_databases));
    }
 
    /*
     * Make sure that at most one of the worker configs for each DB can be
     * configured to run initialization.
     */
-   if (opts->bdr_init_replica)
+   if (opts->init_replica)
    {
+       elog(DEBUG2, "bdr %s: has init_replica=t", name);
        if (database_initcons[off] != NULL)
            elog(ERROR, "Connections %s and %s on database %s both have bdr_init_replica enabled, cannot continue",
                name, database_initcons[off], used_databases[off]);
@@ -961,7 +918,9 @@ bdr_create_con_gucs(char  *name,
            database_initcons[off] = name; /* no need to pstrdup, see _PG_init */
    }
 
-   /* optname vars and opts intentionally leaked, see above */
+   opts->is_valid = true;
+
+   /* optname vars intentionally leaked, see above */
    return true;
 }
 
@@ -1014,22 +973,25 @@ bdr_launch_apply_workers(char *dbname)
            case BDR_WORKER_APPLY:
                {
                    BdrApplyWorker *con = &worker->worker_data.apply_worker;
-                   if ( strcmp(NameStr(con->dbname), dbname) == 0 )
+                   BdrConnectionConfig *cfg =
+                       bdr_connection_configs[con->connection_config_idx];
+                   Assert(cfg != NULL);
+                   if ( strcmp(NameStr(cfg->dbname), dbname) == 0 )
                    {
                        /* It's an apply worker for our DB; register it */
                        BackgroundWorkerHandle *bgw_handle;
 
                        snprintf(apply_worker.bgw_name, BGW_MAXLEN,
-                                "bdr apply: %s", NameStr(con->name));
+                                "bdr apply: %s", NameStr(cfg->name));
                        apply_worker.bgw_main_arg = Int32GetDatum(i);
 
                        if (!RegisterDynamicBackgroundWorker(&apply_worker,
                                                             &bgw_handle))
                        {
-                           /* FIXME better error */
-                           elog(ERROR, "Failed to register background worker");
+                           elog(ERROR, "bdr: Failed to register background worker"
+                                " %s, see previous log messages",
+                                NameStr(cfg->name));
                        }
-                       elog(LOG, "Registered worker");
                        apply_workers = lcons(bgw_handle, apply_workers);
                    }
                }
@@ -1253,31 +1215,36 @@ bdr_worker_shmem_startup(void)
  *
  * The shm segment is initialized now, so do that.
  */
-/*
- * TODO: Do the required GUC parsing, etc in bdr_worker_shmem_create_workers
- * instead of in _PG_init.
- */
 static void
 bdr_worker_shmem_create_workers(void)
 {
-   ListCell *c;
+   int off;
 
    /*
-    * Copy the BdrApplyWorker configs created in _PG_init into shared memory,
-    * then free the palloc'd original.
+    * Create a BdrApplyWorker for each valid BdrConnectionConfig found during
+    * _PG_init so that the per-db worker will register it for startup after
+    * performing any BDR initialisation work.
     *
-    * This is necessary on EXEC_BACKEND (Windows) where postmaster memory
-    * isn't accessible by other backends, and is also required when launching
-    * one bgworker from another.
+    * Use of shared memory for this is required for EXEC_BACKEND (windows)
+    * where we can't share postmaster memory, and for when we're launching a
+    * bgworker from another bgworker where the fork() from postmaster doesn't
+    * provide access to the launching bgworker's memory.
     */
-   foreach(c, bdr_startup_context->workers)
+   for (off = 0; off < bdr_max_workers; off++)
    {
-       BdrApplyWorker *worker = (BdrApplyWorker *) lfirst(c);
+       BdrConnectionConfig *cfg = bdr_connection_configs[off];
        BdrWorker      *shmworker;
+       BdrApplyWorker *worker;
+
+       if (cfg == NULL || !cfg->is_valid)
+           continue;
 
        shmworker = (BdrWorker *) bdr_worker_shmem_alloc(BDR_WORKER_APPLY);
        Assert(shmworker->worker_type == BDR_WORKER_APPLY);
-       memcpy(&shmworker->worker_data, worker, sizeof(BdrApplyWorker));
+       worker = &shmworker->worker_data.apply_worker;
+       worker->connection_config_idx = off;
+       worker->replay_stop_lsn = InvalidXLogRecPtr;
+       worker->forward_changesets = false;
        n_configured_bdr_nodes++;
    }
 
@@ -1379,6 +1346,7 @@ _PG_init(void)
    char      **used_databases;
    char      **database_initcons;
    Size        num_used_databases = 0;
+   int         connection_config_idx;
 
    if (!process_shared_preload_libraries_in_progress)
        elog(ERROR, "bdr can only be loaded via shared_preload_libraries");
@@ -1496,12 +1464,13 @@ _PG_init(void)
     *
     * This registers a hook on shm initialization, bdr_worker_shmem_startup(),
     * which populates the shm segment with configured apply workers using data
-    * in bdr_startup_context.
+    * in bdr_connection_configs.
     */
    bdr_worker_alloc_shmem_segment();
 
-   /* Prepare storage to pass data into our shared memory startup hook */
-   bdr_startup_context = (BdrStartupContext *) palloc0(sizeof(BdrStartupContext));
+   /* Allocate space for BDR connection GUCs */
+   bdr_connection_configs = (BdrConnectionConfig**)
+       palloc0(bdr_max_workers * sizeof(BdrConnectionConfig*));
 
    /* Names of all databases we're going to be doing BDR for */
    used_databases = palloc0(sizeof(char *) * list_length(connames));
@@ -1516,10 +1485,11 @@ _PG_init(void)
     * parameters and sanity checking as we go. The structs are palloc'd, but
     * will be copied into shared memory and free'd during shm init.
     */
+   connection_config_idx = 0;
    foreach(c, connames)
    {
+       char           *name;
        BdrApplyWorker *apply_worker;
-       char *name;
 
        apply_worker = (BdrApplyWorker *) palloc0(sizeof(BdrApplyWorker));
        apply_worker->forward_changesets = false;
@@ -1527,10 +1497,11 @@ _PG_init(void)
        name = (char *) lfirst(c);
 
        if (!bdr_create_con_gucs(name, used_databases, &num_used_databases,
-                                database_initcons, apply_worker))
+                                database_initcons,
+                                &bdr_connection_configs[connection_config_idx]));
            continue;
-       apply_worker->origin_id = InvalidRepNodeId;
-       bdr_startup_context->workers = lcons(apply_worker, bdr_startup_context->workers);
+
+       Assert(bdr_connection_configs[connection_config_idx] != NULL);
    }
 
    /*
index 0f22cfad6633420aa743c0cad98ba7b4405297e0..0c5833b85c079a458e5f57bb3341d4650f902433 100644 (file)
@@ -44,11 +44,11 @@ typedef enum BdrOutputCommitFlags
  */
 typedef struct BdrApplyWorker
 {
-   /* local & remote database name */
-   NameData dbname;
-
-   /* connection name specified in configuration */
-   NameData name;
+   /*
+    * Index in bdr_connection_configs of this workers's GUCs
+    * and config info (including dbname, name, etc).
+    */
+   int connection_config_idx;
 
    /* TODO: Remove these from shm, into bdr worker global state */
    RepNodeId origin_id;
@@ -116,6 +116,30 @@ typedef struct BdrWorker
 
 } BdrWorker;
 
+/* GUC storage for a configured BDR connection. */
+typedef struct BdrConnectionConfig
+{
+   char *dsn;
+   int   apply_delay;
+   bool  init_replica;
+   char *replica_local_dsn;
+   /*
+    * These aren't technically GUCs, but are per-connection config
+    * information obtained from the GUCs.
+    */
+   NameData name;
+   NameData dbname;
+   /* Connection config might be broken (blank dsn, etc) */
+   bool is_valid;
+} BdrConnectionConfig;
+
+/*
+ * Params for every connection in bdr.connections.
+ *
+ * Contains n=bdr_max_workers elements, may have NULL entries.
+ */
+extern BdrConnectionConfig **bdr_connection_configs;
+
 /* GUCs */
 extern int bdr_default_apply_delay;
 extern int bdr_max_workers;
@@ -153,9 +177,6 @@ extern Oid  BdrSequenceValuesRelid;
 extern Oid BdrSequenceElectionsRelid;
 extern Oid BdrVotesRelid;
 
-/* Helpers for accessing configuration */
-const char *bdr_get_worker_option(const char * worker_name, const char * option_name, bool missing_ok);
-
 /* apply support */
 extern void process_remote_begin(StringInfo s);
 extern bool process_remote_commit(StringInfo s);
@@ -219,7 +240,7 @@ bdr_connect(char *conninfo_repl,
            uint64* remote_sysid_i, TimeLineID *remote_tlid_i);
 
 extern struct pg_conn *
-bdr_establish_connection_and_slot(Name connection_name, Name out_slot_name,
+bdr_establish_connection_and_slot(BdrConnectionConfig *cfg, Name out_slot_name,
    uint64 *out_sysid, TimeLineID* out_timeline, RepNodeId
    *out_replication_identifier, char **out_snapshot);
 
index 4874eed315ef7aee2f32f95a6ae1dc4df47fdf11..9980074a9dfb0a87e792b475a3cbac95e1636f5f 100644 (file)
@@ -84,6 +84,12 @@ Oid          QueuedDropsRelid = InvalidOid;
  */
 BdrApplyWorker *bdr_apply_worker = NULL;
 
+/*
+ * GUCs for this apply worker - again, this is fixed for the lifetime of the
+ * worker so we can stash it in a global.
+ */
+BdrConnectionConfig *bdr_apply_config = NULL;
+
 static void build_index_scan_keys(EState *estate, ScanKey *scan_keys, TupleTableSlot *slot);
 static void build_index_scan_key(ScanKey skey, Relation rel, Relation idx_rel, TupleTableSlot *slot);
 static bool find_pkey_tuple(ScanKey skey, Relation rel, Relation idx_rel, TupleTableSlot *slot,
@@ -119,8 +125,7 @@ process_remote_begin(StringInfo s)
    TimestampTz     committime;
    TimestampTz     current;
    char            statbuf[100];
-   int             apply_delay = -1;
-   const char     *apply_delay_str;
+   int             apply_delay = bdr_apply_config->apply_delay;
 
    Assert(bdr_apply_worker != NULL);
 
@@ -135,7 +140,7 @@ process_remote_begin(StringInfo s)
 
    snprintf(statbuf, sizeof(statbuf),
            "bdr_apply: BEGIN origin(source, orig_lsn, timestamp): %s, %X/%X, %s",
-            NameStr(bdr_apply_worker->name),
+            NameStr(bdr_apply_config->name),
            (uint32) (origlsn >> 32), (uint32) origlsn,
            timestamptz_to_str(committime));
 
@@ -143,11 +148,6 @@ process_remote_begin(StringInfo s)
 
    pgstat_report_activity(STATE_RUNNING, statbuf);
 
-   apply_delay_str = bdr_get_worker_option(NameStr(bdr_apply_worker->name), "apply_delay", true);
-   if (apply_delay_str)
-       /* This is an integer GUC, so parsing as an int can't fail */
-       (void) parse_int(apply_delay_str, &apply_delay, 0, NULL);
-
    if (apply_delay == -1)
        apply_delay = bdr_default_apply_delay;
 
@@ -259,7 +259,7 @@ process_remote_commit(StringInfo s)
    {
        ereport(LOG,
                (errmsg("bdr apply %s finished processing; replayed to %X/%X of required %X/%X",
-                NameStr(bdr_apply_worker->name),
+                NameStr(bdr_apply_config->name),
                 (uint32)(end_lsn>>32), (uint32)end_lsn,
                 (uint32)(bdr_apply_worker->replay_stop_lsn>>32), (uint32)bdr_apply_worker->replay_stop_lsn)));
        /*
index 30875da9529ae2608bceafa0af1dba6d543de598..40d8d4516767ffeae620ab72a8832792f992979f 100644 (file)
@@ -53,9 +53,9 @@
 
 char *bdr_temp_dump_directory = NULL;
 
-static void bdr_exec_init_replica(Name conn_name, char *snapshot);
+static void bdr_exec_init_replica(BdrConnectionConfig *cfg, char *snapshot);
 
-static void bdr_catchup_to_lsn(PGconn *conn, Name dbname, Name conn_name,
+static void bdr_catchup_to_lsn(int cfg_index,
                               XLogRecPtr target_lsn);
 
 /*
@@ -64,6 +64,7 @@ static void bdr_catchup_to_lsn(PGconn *conn, Name dbname, Name conn_name,
  * ensured there can only be one). If no match is found, return null.
  *
  * Must be called with at least a share lock on BdrWorkerCtl->lock
+ *
  */
 static BdrWorker*
 find_init_replica_worker(Name dbname)
@@ -74,23 +75,19 @@ find_init_replica_worker(Name dbname)
    /* Check whether one of our connections has init_replica set */
    for (off = 0; off < bdr_max_workers; off++)
    {
-       BdrApplyWorker *aw;
+       BdrApplyWorker         *aw;
+       BdrConnectionConfig    *cfg;
 
        if (BdrWorkerCtl->slots[off].worker_type != BDR_WORKER_APPLY)
            continue;
 
        aw = &BdrWorkerCtl->slots[off].worker_data.apply_worker;
+       cfg = bdr_connection_configs[aw->connection_config_idx];
 
-       if (strcmp(NameStr(aw->dbname), NameStr(*dbname)) == 0)
+       if ((strcmp(NameStr(cfg->dbname), NameStr(*dbname)) == 0)
+           && cfg->init_replica)
        {
-           const char *init_replica_str;
-           bool init_replica = false;
-           init_replica_str = bdr_get_worker_option(NameStr(aw->name),
-                                                    "init_replica", true);
-           if (init_replica_str
-               && parse_bool(init_replica_str, &init_replica)
-               && init_replica)
-               return &BdrWorkerCtl->slots[off];
+           return &BdrWorkerCtl->slots[off];
        }
    }
    return NULL;
@@ -421,11 +418,10 @@ bdr_delete_replication_identifier(RepNodeId repid)
 }
 
 static void
-bdr_drop_slot_and_replication_identifier(Name connection_name, Name dbname)
+bdr_drop_slot_and_replication_identifier(BdrConnectionConfig *cfg)
 {
 
    char        conninfo_repl[MAXCONNINFO + 75];
-   const char *dsn;
    char        remote_ident[256];
    PGconn     *streamConn;
    RepNodeId   replication_identifier;
@@ -437,12 +433,11 @@ bdr_drop_slot_and_replication_identifier(Name connection_name, Name dbname)
    char       *sqlstate;
 
    elog(LOG, "bdr %s: Dropping slot and local ident from connection %s",
-        NameStr(*dbname), NameStr(*connection_name));
+        NameStr(cfg->dbname), NameStr(cfg->name));
 
-   dsn = bdr_get_worker_option(NameStr(*connection_name), "dsn", false);
    snprintf(conninfo_repl, sizeof(conninfo_repl),
             "%s replication=database fallback_application_name=bdr",
-            dsn);
+            cfg->dsn);
 
    /* Establish BDR conn and IDENTIFY_SYSTEM */
    streamConn = bdr_connect(
@@ -458,13 +453,13 @@ bdr_drop_slot_and_replication_identifier(Name connection_name, Name dbname)
    {
        /* Local replication identifier exists and must be dropped. */
        elog(DEBUG2, "bdr %s: Deleting local replication identifier %hu",
-            NameStr(*dbname), replication_identifier);
+            NameStr(cfg->dbname), replication_identifier);
        bdr_delete_replication_identifier(replication_identifier);
    }
    else
    {
        elog(DEBUG2, "bdr %s: No local replication identifier to delete",
-            NameStr(*dbname));
+            NameStr(cfg->dbname));
    }
 
    /*
@@ -478,7 +473,7 @@ bdr_drop_slot_and_replication_identifier(Name connection_name, Name dbname)
    if (PQresultStatus(res) == PGRES_COMMAND_OK)
    {
        elog(DEBUG2, "bdr %s: remote replication slot %s deleted",
-            NameStr(*dbname), NameStr(slot_name));
+            NameStr(cfg->dbname), NameStr(slot_name));
    }
    else
    {
@@ -488,12 +483,12 @@ bdr_drop_slot_and_replication_identifier(Name connection_name, Name dbname)
        {
            ereport(ERROR,
                    (errmsg("'DROP_REPLICATION_SLOT %s' on bdr connection %s failed with sqlstate %s: %s",
-                           NameStr(slot_name), NameStr(*connection_name),
+                           NameStr(slot_name), NameStr(cfg->name),
                            sqlstate,PQresultErrorMessage(res))));
        }
        else
        {
-           elog(DEBUG2, "bdr %s: No slot to delete", NameStr(*dbname));
+           elog(DEBUG2, "bdr %s: No slot to delete", NameStr(cfg->dbname));
        }
    }
    CommitTransactionCommand();
@@ -518,14 +513,12 @@ bdr_init_replica_cleanup_tmpdir(int errcode, Datum tmpdir)
  * replica from an existing node.
  */
 static void
-bdr_exec_init_replica(Name conn_name, char *snapshot)
+bdr_exec_init_replica(BdrConnectionConfig *cfg, char *snapshot)
 {
 #ifndef WIN32
    pid_t pid;
    char *bindir;
    char *tmpdir;
-   char *remote_dsn;
-   char *replica_local_dsn;
    char  bdr_init_replica_script_path[MAXPGPATH];
    const char *envvar;
    StringInfoData path;
@@ -536,9 +529,6 @@ bdr_exec_init_replica(Name conn_name, char *snapshot)
    bindir = pstrdup(my_exec_path);
    get_parent_directory(bindir);
 
-   replica_local_dsn = pstrdup(bdr_get_worker_option(NameStr(*conn_name), "replica_local_dsn", false));
-   remote_dsn  = pstrdup(bdr_get_worker_option(NameStr(*conn_name), "dsn", false));
-
    if (!find_other_exec(my_exec_path, BDR_INIT_REPLICA_CMD,
                         BDR_INIT_REPLICA_CMD " " PG_VERSION,
                         &bdr_init_replica_script_path[0]))
@@ -548,7 +538,7 @@ bdr_exec_init_replica(Name conn_name, char *snapshot)
             PG_VERSION);
    }
 
-   if (!replica_local_dsn)
+   if (cfg->replica_local_dsn == NULL)
        elog(FATAL, "bdr init_replica: no replica_local_dsn specified");
 
    tmpdir = palloc(strlen(bdr_temp_dump_directory)+32);
@@ -589,8 +579,8 @@ bdr_exec_init_replica(Name conn_name, char *snapshot)
        char *const argv[] = {
            bdr_init_replica_script_path,
            "--snapshot", snapshot,
-           "--source", remote_dsn,
-           "--target", replica_local_dsn,
+           "--source", cfg->dsn,
+           "--target", cfg->replica_local_dsn,
            "--tmp-directory", tmpdir,
            NULL
        };
@@ -606,8 +596,8 @@ bdr_exec_init_replica(Name conn_name, char *snapshot)
        envp[0] = path.data;
 
        elog(LOG, "Creating replica with: %s --snapshot %s --source \"%s\" --target \"%s\" --tmp-directory \"%s\"",
-            bdr_init_replica_script_path, snapshot, remote_dsn,
-            replica_local_dsn, tmpdir);
+            bdr_init_replica_script_path, snapshot, cfg->dsn,
+            cfg->replica_local_dsn, tmpdir);
 
        n = execve(bdr_init_replica_script_path, argv, envp);
        if (n < 0)
@@ -661,8 +651,6 @@ bdr_exec_init_replica(Name conn_name, char *snapshot)
        bdr_init_replica_cleanup_tmpdir(0, CStringGetDatum(tmpdir));
    }
 
-   pfree(replica_local_dsn);
-   pfree(remote_dsn);
    pfree(tmpdir);
 #else
    /*
@@ -685,13 +673,12 @@ bdr_exec_init_replica(Name conn_name, char *snapshot)
 void
 bdr_init_replica(Name dbname)
 {
-   const char *connstr;
    char status;
    XLogRecPtr min_remote_lsn;
    PGconn *nonrepl_init_conn;
    StringInfoData query;
    BdrWorker  *init_replica_worker;
-   Name init_conn_name;
+   BdrConnectionConfig *init_replica_config;
 
    initStringInfo(&query);
 
@@ -716,9 +703,10 @@ bdr_init_replica(Name dbname)
        return;
    }
 
-   init_conn_name = &init_replica_worker->worker_data.apply_worker.name;
+   init_replica_config = bdr_connection_configs
+       [init_replica_worker->worker_data.apply_worker.connection_config_idx];
    elog(DEBUG2, "bdr %s: bdr_init_replica init from connection %s",
-        NameStr(*dbname), NameStr(*init_conn_name));
+        NameStr(*dbname), NameStr(init_replica_config->name));
 
    /*
     * Check the local bdr.bdr_nodes over SPI or direct scan to see if
@@ -737,8 +725,7 @@ bdr_init_replica(Name dbname)
     * system identifier. If there is, that'll tell us what stage of startup
     * we are up to and let us resume an incomplete start.
     */
-   connstr = bdr_get_worker_option(NameStr(*init_conn_name), "dsn", false);
-   nonrepl_init_conn = PQconnectdb(connstr);
+   nonrepl_init_conn = PQconnectdb(init_replica_config->dsn);
    if (PQstatus(nonrepl_init_conn) != CONNECTION_OK)
    {
        ereport(FATAL,
@@ -801,7 +788,7 @@ bdr_init_replica(Name dbname)
             */
            elog(DEBUG2, "bdr %s: previous failed initalization detected, cleaning up",
                 NameStr(*dbname));
-           bdr_drop_slot_and_replication_identifier(init_conn_name, dbname);
+           bdr_drop_slot_and_replication_identifier(init_replica_config);
            status = bdr_set_remote_status(nonrepl_init_conn, dbname,
                                           '\0', status);
            break;
@@ -834,12 +821,14 @@ bdr_init_replica(Name dbname)
        LWLockAcquire(BdrWorkerCtl->lock, LW_SHARED);
        for (off = 0; off < bdr_max_workers; off++)
        {
-           BdrWorker *worker = &BdrWorkerCtl->slots[off];
-           const char *worker_name =
-               NameStr(worker->worker_data.apply_worker.dbname);
+           BdrWorker              *worker = &BdrWorkerCtl->slots[off];
+           BdrConnectionConfig    *cfg;
+
+           cfg = bdr_connection_configs
+               [worker->worker_data.apply_worker.connection_config_idx];
 
            if (worker->worker_type == BDR_WORKER_APPLY
-               && strcmp(worker_name, NameStr(*dbname)) == 0)
+               && strcmp(NameStr(cfg->dbname), NameStr(*dbname)) == 0)
                my_conn_idxs[n_conns++] = off;
        }
        LWLockRelease(BdrWorkerCtl->lock);
@@ -863,6 +852,7 @@ bdr_init_replica(Name dbname)
        for (off = 0; off < n_conns; off++)
        {
            BdrWorker *w = &BdrWorkerCtl->slots[my_conn_idxs[off]];
+           BdrConnectionConfig *cfg;
            char *snapshot = NULL;
            PGconn *conn = NULL;
            RepNodeId replication_identifier;
@@ -870,17 +860,19 @@ bdr_init_replica(Name dbname)
            uint64 sysid;
            TimeLineID timeline;
 
+           cfg = bdr_connection_configs
+               [w->worker_data.apply_worker.connection_config_idx];
+
            elog(DEBUG1, "bdr %s: checking/creating slot for %s",
-                NameStr(*dbname), NameStr(w->worker_data.apply_worker.name));
+                NameStr(*dbname), NameStr(cfg->name));
            /*
             * Create the slot on the remote. The returned remote sysid and
             * timeline, the slot name, and the local replication identifier
             * are all discarded; they're not needed here, and will be obtained
             * again by the apply workers when they're launched after init.
             */
-           conn = bdr_establish_connection_and_slot(
-               &w->worker_data.apply_worker.name, &slot_name,
-               &sysid, &timeline, &replication_identifier, &snapshot);
+           conn = bdr_establish_connection_and_slot(cfg, &slot_name, &sysid,
+               &timeline, &replication_identifier, &snapshot);
 
            /* Always throws rather than returning failure */
            Assert(conn);
@@ -929,8 +921,8 @@ bdr_init_replica(Name dbname)
         * copied over.
         */
        elog(LOG, "bdr %s: creating and restoring dump for %s",
-            NameStr(*dbname), NameStr(*init_conn_name));
-       bdr_exec_init_replica(init_conn_name, init_snapshot);
+            NameStr(*dbname), NameStr(init_replica_config->name));
+       bdr_exec_init_replica(init_replica_config, init_snapshot);
        PQfinish(init_repl_conn);
 
        pfree(init_snapshot);
@@ -942,7 +934,9 @@ bdr_init_replica(Name dbname)
    /* Launch the catchup worker and wait for it to finish */
    elog(LOG, "bdr %s: launching catchup mode apply worker", NameStr(*dbname));
    min_remote_lsn = bdr_get_remote_lsn(nonrepl_init_conn);
-   bdr_catchup_to_lsn(nonrepl_init_conn, dbname, init_conn_name, min_remote_lsn);
+   bdr_catchup_to_lsn(
+       init_replica_worker->worker_data.apply_worker.connection_config_idx,
+       min_remote_lsn);
    status = bdr_set_remote_status(nonrepl_init_conn, dbname, 'r', status);
 
    elog(LOG, "bdr %s: catchup worker finished, ready for normal replication",
@@ -975,9 +969,17 @@ bdr_catchup_to_lsn_cleanup(int code, Datum offset)
  * When we finish applying and the worker exits, we'll be caught up with the
  * remote and in a consistent state where all our local replication identifiers
  * are consistent with the actual state of the local DB.
+ *
+ * Arguments:
+ *
+ * cfg_index: Index of the bdr connection for this dbname with init_worker=t
+ * set within bdr_connection_configs. Used to start the worker.
+ *
+ * target_lsn: LSN of immediate origin node at which catchup should stop.
  */
 static void
-bdr_catchup_to_lsn(PGconn *conn, Name dbname, Name conn_name, XLogRecPtr target_lsn)
+bdr_catchup_to_lsn(int cfg_index,
+                  XLogRecPtr target_lsn)
 {
    int worker_shmem_idx;
    pid_t bgw_pid;
@@ -985,12 +987,17 @@ bdr_catchup_to_lsn(PGconn *conn, Name dbname, Name conn_name, XLogRecPtr target_
    BackgroundWorker bgw;
    BackgroundWorkerHandle *bgw_handle;
    BgwHandleStatus bgw_status;
+   BdrConnectionConfig *cfg;
+
+   cfg = bdr_connection_configs[cfg_index];
+   Assert(cfg != NULL);
+   Assert(cfg->init_replica);
 
    elog(DEBUG1, "Registering bdr apply catchup worker %s for db %s to lsn %X/%X",
-        NameStr(*conn_name), NameStr(*dbname),
+        NameStr(cfg->name), NameStr(cfg->dbname),
         (uint32)(target_lsn>>32), (uint32)target_lsn);
 
-   /* Create the shm entry for the catchup worker */
+   /* Create the shmem entry for the catchup worker */
    LWLockAcquire(BdrWorkerCtl->lock, LW_SHARED);
    for (worker_shmem_idx = 0; worker_shmem_idx < bdr_max_workers; worker_shmem_idx++)
    {
@@ -1009,21 +1016,22 @@ bdr_catchup_to_lsn(PGconn *conn, Name dbname, Name conn_name, XLogRecPtr target_
    LWLockRelease(BdrWorkerCtl->lock);
 
    /*
-    * Make sure we free the shmem slot for the catchup worker even if we
-    * hit an error.
+    * Launch the catchup worker, ensuring that we free the shmem slot for the
+    * catchup worker even if we hit an error.
     *
     * There's a small race between claiming the worker and entering the ensure
-    * cleanup block.  Real consequences, pretty much nil, since this is really
-    * just startup code.
+    * cleanup block. The real consequences are pretty much nil, since this is
+    * really just startup code and all we leak is one shmem slot.
     */
    PG_ENSURE_ERROR_CLEANUP(bdr_catchup_to_lsn_cleanup,
                            Int32GetDatum(worker_shmem_idx));
    {
        pid_t prev_bgw_pid = 0;
 
+       /* Make sure the catchup worker can find its bdr.xxx_ GUCs */
+       catchup_worker->connection_config_idx = cfg_index;
+
        /* Set up the BdrApplyWorker struct in shmem */
-       strncpy(NameStr(catchup_worker->name), NameStr(*conn_name), NAMEDATALEN);
-       strncpy(NameStr(catchup_worker->dbname), NameStr(*dbname), NAMEDATALEN);
        catchup_worker->origin_id = InvalidRepNodeId;
        catchup_worker->sysid = 0;
        catchup_worker->timeline = 0;
@@ -1049,9 +1057,9 @@ bdr_catchup_to_lsn(PGconn *conn, Name dbname, Name conn_name, XLogRecPtr target_
 
        snprintf(bgw.bgw_name, BGW_MAXLEN,
                 "bdr %s: catchup apply to %X/%X on %s",
-                NameStr(*dbname),
+                NameStr(cfg->dbname),
                 (uint32)(target_lsn >> 32), (uint32)target_lsn,
-                NameStr(*conn_name));
+                NameStr(cfg->name));
        bgw.bgw_name[BGW_MAXLEN-1] = '\0';
 
        /* Launch the catchup worker and wait for it to start */
@@ -1114,13 +1122,13 @@ bdr_catchup_to_lsn(PGconn *conn, Name dbname, Name conn_name, XLogRecPtr target_
            /* Worker must've died before it finished */
            elog(ERROR,
                 "bdr %s: catchup worker exited before catching up to target LSN %X/%X",
-                NameStr(*dbname),
+                NameStr(cfg->dbname),
                 (uint32)(target_lsn>>32), (uint32)target_lsn);
        }
        else
        {
            elog(DEBUG1, "bdr %s: catchup worker caught up to target LSN",
-                NameStr(*dbname));
+                NameStr(cfg->dbname));
        }
    }
    PG_END_ENSURE_ERROR_CLEANUP(bdr_catchup_to_lsn_cleanup,