bdr: Improve sequencer wakeup logic.
authorAndres Freund <[email protected]>
Fri, 4 Apr 2014 11:07:03 +0000 (13:07 +0200)
committerAndres Freund <[email protected]>
Thu, 3 Jul 2014 15:55:23 +0000 (17:55 +0200)
Schedule a sequencer wakeup at EOXact whenever a sequence is created
or it's setttings are modified. This allows to significantly decrease
the frequency of unneccessary sequencer wakeups and also significantly
reduces the time until a new sequence is initialized.

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

index f9470dc581f19c495acd5021c300a6da9d43c664..a52ec53bef5b61949d455e1fe96e330a3c2e03bb 100644 (file)
@@ -583,10 +583,14 @@ bdr_sequencer_main(Datum main_arg)
         * instead, they may wait on their process latch, which sleeps as
         * necessary, but is awakened if postmaster dies.  That way the
         * background process goes away immediately in an emergency.
+        *
+        * We wake up everytime our latch gets set or if 180 seconds have
+        * passed without events. That's a stopgap for the case a backend
+        * committed sequencer changes but died before setting the latch.
         */
        rc = WaitLatch(&MyProc->procLatch,
                       WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
-                      10000L);
+                      180000L);
 
        ResetLatch(&MyProc->procLatch);
 
index 84e05aadf3eb3ba35b73342d89a23eb7fbe14b84..524b63c51e6c26ed8193039a726f565acdc8a503 100644 (file)
@@ -56,6 +56,8 @@ typedef struct BdrSequenceValues {
    int64       end_value;
 } BdrSequenceValues;
 
+static void bdr_schedule_eoxact_sequencer_wakeup(void);
+
 /* cached relids */
 Oid    BdrSequenceValuesRelid;     /* bdr_sequence_values */
 Oid    BdrSequenceElectionsRelid;  /* bdr_sequence_elections */
@@ -71,6 +73,8 @@ static size_t bdr_seq_nsequencers = 0;
 
 static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
 
+static bool bdr_seq_pending_wakeup = false;
+
 /* vote */
 const char* vote_sql =
 "INSERT INTO bdr_votes (\n"
@@ -535,6 +539,43 @@ bdr_sequencer_wakeup(void)
    }
 }
 
+
+static void
+bdr_sequence_xact_callback(XactEvent event, void *arg)
+{
+   if (event != XACT_EVENT_COMMIT)
+       return;
+
+   if (bdr_seq_pending_wakeup)
+   {
+       bdr_sequencer_wakeup();
+       bdr_seq_pending_wakeup = false;
+   }
+}
+
+/*
+ * Schedule a wakeup of all sequencer workers, as soon as this transaction
+ * commits.
+ *
+ * This is e.g. useful when a new sequnece is created, and the voting process
+ * should start immediately.
+ *
+ * NB: There's a window between the commit and this callback in which this
+ * backend could die without causing a cluster wide restart. So we need to
+ * periodically check whether we've missed wakeups.
+ */
+static void bdr_schedule_eoxact_sequencer_wakeup(void)
+{
+   static bool registered = false;
+
+   if (!registered)
+   {
+       RegisterXactCallback(bdr_sequence_xact_callback, NULL);
+       registered = true;
+   }
+   bdr_seq_pending_wakeup = true;
+}
+
 void
 bdr_sequencer_init(void)
 {
@@ -1131,6 +1172,9 @@ bdr_sequence_alloc(PG_FUNCTION_ARGS)
    result = elm->last;
 
    END_CRIT_SECTION();
+
+   /* schedule wakeup as soon as other xacts can see the seuqence */
+   bdr_schedule_eoxact_sequencer_wakeup();
 }
 
 PG_FUNCTION_INFO_V1(bdr_sequence_setval);
@@ -1158,6 +1202,9 @@ bdr_sequence_setval(PG_FUNCTION_ARGS)
    log_sequence_tuple(seqrel, seqtuple, page);
 
    END_CRIT_SECTION();
+
+   /* schedule wakeup as soon as other xacts can see the seuqence */
+   bdr_schedule_eoxact_sequencer_wakeup();
 }
 
 PG_FUNCTION_INFO_V1(bdr_sequence_options);
@@ -1173,4 +1220,7 @@ bdr_sequence_options(PG_FUNCTION_ARGS)
        PG_RETURN_BYTEA_P(result);
 
    PG_RETURN_NULL();
+
+   /* schedule wakeup as soon as other xacts can see the seuqence */
+   bdr_schedule_eoxact_sequencer_wakeup();
 }