Add an option to autobalance a HA cluster automatically
authorMartin Willi <martin@revosec.ch>
Tue, 19 Mar 2013 15:49:07 +0000 (16:49 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 19 Mar 2013 15:54:20 +0000 (16:54 +0100)
src/libcharon/plugins/ha/ha_segments.c

index a4ea9ef..cab38c6 100644 (file)
@@ -90,6 +90,11 @@ struct private_ha_segments_t {
         * Timeout for heartbeats received from other node
         */
        int heartbeat_timeout;
+
+       /**
+        * Interval to check for autobalance, 0 to disable
+        */
+       int autobalance;
 };
 
 /**
@@ -374,6 +379,54 @@ static void start_heartbeat(private_ha_segments_t *this)
                        this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
 }
 
+/**
+ * Take a segment if we are handling less than half of segments
+ */
+static job_requeue_t autobalance(private_ha_segments_t *this)
+{
+       int i, active = 0;
+
+       this->mutex->lock(this->mutex);
+
+       for (i = 1; i <= this->count; i++)
+       {
+               if (this->active & SEGMENTS_BIT(i))
+               {
+                       active++;
+               }
+       }
+       if (active < this->count / 2)
+       {
+               for (i = 1; i <= this->count; i++)
+               {
+                       if (!(this->active & SEGMENTS_BIT(i)))
+                       {
+                               DBG1(DBG_CFG, "autobalancing HA (%d/%d active), taking %d",
+                                        active, this->count, i);
+                               enable_disable(this, i, TRUE, TRUE);
+                               /* we claim only one in each interval */
+                               break;
+                       }
+               }
+       }
+
+       this->mutex->unlock(this->mutex);
+
+       return JOB_RESCHEDULE(this->autobalance);
+}
+
+/**
+ * Schedule autobalancing
+ */
+static void start_autobalance(private_ha_segments_t *this)
+{
+       DBG1(DBG_CFG, "scheduling HA autobalance every %ds", this->autobalance);
+       lib->scheduler->schedule_job(lib->scheduler,
+               (job_t*)callback_job_create_with_prio((callback_job_cb_t)autobalance,
+                       this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL),
+               this->autobalance);
+}
+
 METHOD(ha_segments_t, is_active, bool,
        private_ha_segments_t *this, u_int segment)
 {
@@ -421,6 +474,8 @@ ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
                .heartbeat_timeout = lib->settings->get_int(lib->settings,
                                "%s.plugins.ha.heartbeat_timeout", DEFAULT_HEARTBEAT_TIMEOUT,
                                charon->name),
+               .autobalance = lib->settings->get_int(lib->settings,
+                               "%s.plugins.ha.autobalance", 0, charon->name),
        );
 
        if (monitor)
@@ -430,6 +485,10 @@ ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
                start_heartbeat(this);
                start_watchdog(this);
        }
+       if (this->autobalance)
+       {
+               start_autobalance(this);
+       }
 
        return &this->public;
 }