bdr: avoid race conditions when installing bdr extensions
authorAndres Freund <[email protected]>
Tue, 4 Mar 2014 00:56:33 +0000 (01:56 +0100)
committerAndres Freund <[email protected]>
Thu, 3 Jul 2014 15:55:19 +0000 (17:55 +0200)
Previously installing the bdr (and prerequisite) extensions was racy
because only the sequencer installed them. Initially that wasn't much
of a problem since only the sequencer and manual queries needed the
schema, but that's not true anymore.

Instead check whether the schema exists in every started worker and
prevent races by acquiring a suitably strong lock on pg_extension
while checking/creating.

contrib/bdr/bdr.c
contrib/bdr/bdr_seq.c

index 9445a0527db4a8586038eada68f1c072aca40d04..4f3a071e7e18dc02e1e16adc94e70ceb4f05fb15 100644 (file)
 #include "pgstat.h"
 
 #include "access/committs.h"
+#include "access/heapam.h"
 #include "access/xact.h"
+#include "catalog/pg_extension.h"
 #include "catalog/pg_index.h"
+#include "commands/extension.h"
 #include "lib/stringinfo.h"
 #include "replication/replication_identifier.h"
 #include "utils/builtins.h"
 #include "utils/guc.h"
 #include "utils/memutils.h"
+#include "utils/snapmgr.h"
 #include "utils/timestamp.h"
 
 /* sequencer */
@@ -58,6 +62,8 @@ PG_MODULE_MAGIC;
 
 void       _PG_init(void);
 
+static void bdr_maintain_schema(void);
+
 /*
  * Converts an int64 to network byte order.
  */
@@ -246,6 +252,9 @@ bdr_apply_main(Datum main_arg)
    /* Connect to our database */
    BackgroundWorkerInitializeConnection(bdr_apply_con->dbname, NULL);
 
+   /* make sure BDR extension exists */
+   bdr_maintain_schema();
+
    /* always work in our own schema */
    SetConfigOption("search_path", "bdr, pg_catalog",
                    PGC_BACKEND, PGC_S_OVERRIDE);
@@ -552,6 +561,9 @@ bdr_sequencer_main(Datum main_arg)
    /* Connect to our database */
    BackgroundWorkerInitializeConnection(bdr_sequencer_con->dbname, NULL);
 
+   /* make sure BDR extension exists */
+   bdr_maintain_schema();
+
    /* always work in our own schema */
    SetConfigOption("search_path", "bdr, pg_catalog",
                    PGC_BACKEND, PGC_S_OVERRIDE);
@@ -561,7 +573,7 @@ bdr_sequencer_main(Datum main_arg)
 
    elog(WARNING, "starting sequencer on db \"%s\"", bdr_sequencer_con->dbname);
 
-   /* make sure BDR extension exists */
+   /* initialize sequencer */
    bdr_sequencer_init();
 
    while (!got_sigterm)
@@ -820,3 +832,55 @@ out:
 
    MemoryContextSwitchTo(old_context);
 }
+
+/*
+ * Make sure all required extensions are installed in the correct version for
+ * the current database.
+ *
+ * Concurrent executions will block, but not fail.
+ */
+static void
+bdr_maintain_schema(void)
+{
+   Relation extrel;
+   Oid     extoid;
+
+   StartTransactionCommand();
+   PushActiveSnapshot(GetTransactionSnapshot());
+
+   /* make sure we're operating without other bdr workers interfering */
+   extrel = heap_open(ExtensionRelationId, ShareUpdateExclusiveLock);
+
+    extoid = get_extension_oid("bdr", true);
+
+   /* create required extension if they don't exists yet */
+   if (extoid == InvalidOid)
+   {
+       CreateExtensionStmt create_stmt;
+
+       create_stmt.if_not_exists = false;
+       create_stmt.options = NIL;
+       create_stmt.extname = (char *)"btree_gist";
+
+       CreateExtension(&create_stmt);
+
+       create_stmt.extname = (char *)"bdr";
+       CreateExtension(&create_stmt);
+   }
+   else
+   {
+       AlterExtensionStmt alter_stmt;
+
+       alter_stmt.options = NIL;
+       alter_stmt.extname = (char *)"btree_gist";
+       ExecAlterExtensionStmt(&alter_stmt);
+
+       alter_stmt.extname = (char *)"bdr";
+       ExecAlterExtensionStmt(&alter_stmt);
+   }
+
+   heap_close(extrel, ShareUpdateExclusiveLock);
+
+   PopActiveSnapshot();
+   CommitTransactionCommand();
+}
index d9e543c2c97518f39d8ccf65d557882c596a103c..b04579a9ee740cbcb13d598b12d071b17e8c96a3 100644 (file)
@@ -26,7 +26,6 @@
 #include "access/xact.h"
 #include "catalog/pg_type.h"
 #include "catalog/namespace.h"
-#include "commands/extension.h"
 #include "commands/sequence.h"
 #include "executor/spi.h"
 #include "utils/builtins.h"
@@ -534,8 +533,6 @@ bdr_sequencer_wakeup(void)
 void
 bdr_sequencer_init(void)
 {
-   CreateExtensionStmt create_stmt;
-   AlterExtensionStmt alter_stmt;
    BdrSequencerSlot *slot;
 
    Assert(bdr_sequencer_con != NULL);
@@ -543,32 +540,6 @@ bdr_sequencer_init(void)
    slot = &BdrSequencerCtl->slots[bdr_sequencer_con->slot];
    slot->database_oid = MyDatabaseId;
    slot->proclatch = &MyProc->procLatch;
-
-   create_stmt.if_not_exists = true;
-   create_stmt.options = NIL;
-
-   alter_stmt.options = NIL;
-
-   StartTransactionCommand();
-   PushActiveSnapshot(GetTransactionSnapshot());
-
-   create_stmt.extname = (char *)"btree_gist";
-   alter_stmt.extname = (char *)"btree_gist";
-
-   /* create extension if not exists */
-   CreateExtension(&create_stmt);
-   /* update extension otherwise */
-   ExecAlterExtensionStmt(&alter_stmt);
-
-   create_stmt.extname = (char *)"bdr";
-   alter_stmt.extname = (char *)"bdr";
-   /* create extension if not exists */
-   CreateExtension(&create_stmt);
-   /* update extension otherwise */
-   ExecAlterExtensionStmt(&alter_stmt);
-
-   PopActiveSnapshot();
-   CommitTransactionCommand();
 }
 
 static void