]> granicus.if.org Git - apache/blobdiff - modules/proxy/balancers/mod_lbmethod_heartbeat.c
Use ap_state_query() to fix many modules that were not correctly initializing
[apache] / modules / proxy / balancers / mod_lbmethod_heartbeat.c
index 914c367bb215d7da7761bc4f3c1e135369d8d80d..0987415ac60f043518c6dbf12f406c354fe96708 100644 (file)
@@ -19,6 +19,8 @@
 #include "ap_mpm.h"
 #include "apr_version.h"
 #include "apr_hooks.h"
+#include "ap_slotmem.h"
+#include "heartbeat.h"
 
 #ifndef LBM_HEARTBEAT_MAX_LASTSEEN
 /* If we haven't seen a heartbeat in the last N seconds, don't count this IP
 
 module AP_MODULE_DECLARE_DATA lbmethod_heartbeat_module;
 
+static const ap_slotmem_provider_t *storage = NULL;
+static ap_slotmem_instance_t *hm_serversmem = NULL;
+
+/*
+ * configuration structure
+ * path: path of the file where the heartbeat information is stored.
+ */
 typedef struct lb_hb_ctx_t
 {
     const char *path;
@@ -38,10 +47,17 @@ typedef struct hb_server_t {
     const char *ip;
     int busy;
     int ready;
-    int seen;
+    int port;
+    int id;
+    apr_time_t seen;
     proxy_worker *worker;
 } hb_server_t;
 
+typedef struct ctx_servers {
+    apr_time_t now;
+    apr_hash_t *servers;
+} ctx_servers_t;
+
 static void
 argstr_to_table(apr_pool_t *p, char *str, apr_table_t *parms)
 {
@@ -70,7 +86,7 @@ argstr_to_table(apr_pool_t *p, char *str, apr_table_t *parms)
     }
 }
 
-static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers,
+static apr_status_t readfile_heartbeats(const char *path, apr_hash_t *servers,
                                     apr_pool_t *pool)
 {
     apr_finfo_t fi;
@@ -151,6 +167,7 @@ static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers,
             if (server == NULL) {
                 server = apr_pcalloc(pool, sizeof(hb_server_t));
                 server->ip = ip;
+                server->port = 80;
                 server->seen = -1;
 
                 apr_hash_set(servers, server->ip, APR_HASH_KEY_STRING, server);
@@ -172,6 +189,10 @@ static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers,
                 server->seen = atoi(apr_table_get(hbt, "lastseen"));
             }
 
+            if (apr_table_get(hbt, "port")) {
+                server->port = atoi(apr_table_get(hbt, "port"));
+            }
+
             if (server->busy == 0 && server->ready != 0) {
                 /* Server has zero threads active, but lots of them ready, 
                  * it likely just started up, so lets /4 the number ready, 
@@ -187,6 +208,51 @@ static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers,
     return APR_SUCCESS;
 }
 
+static apr_status_t hm_read(void* mem, void *data, apr_pool_t *pool)
+{
+    hm_slot_server_t *slotserver = (hm_slot_server_t *) mem;
+    ctx_servers_t *ctx = (ctx_servers_t *) data;
+    apr_hash_t *servers = (apr_hash_t *) ctx->servers;
+    hb_server_t *server = apr_hash_get(servers, slotserver->ip, APR_HASH_KEY_STRING);
+    if (server == NULL) {
+        server = apr_pcalloc(pool, sizeof(hb_server_t));
+        server->ip = apr_pstrdup(pool, slotserver->ip);
+        server->seen = -1;
+
+        apr_hash_set(servers, server->ip, APR_HASH_KEY_STRING, server);
+
+    }
+    server->busy = slotserver->busy;
+    server->ready = slotserver->ready;
+    server->seen = apr_time_sec(ctx->now - slotserver->seen);
+    server->id = slotserver->id;
+    if (server->busy == 0 && server->ready != 0) {
+        server->ready = server->ready / 4;
+    }
+    return APR_SUCCESS;
+}
+static apr_status_t readslot_heartbeats(ctx_servers_t *ctx,
+                                    apr_pool_t *pool)
+{
+    storage->doall(hm_serversmem, hm_read, ctx, pool);
+    return APR_SUCCESS;
+}
+
+
+static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers,
+                                        apr_pool_t *pool)
+{
+    apr_status_t rv;
+    if (hm_serversmem) {
+        ctx_servers_t ctx;
+        ctx.now = apr_time_now();
+        ctx.servers = servers;
+        rv = readslot_heartbeats(&ctx, pool);
+    } else
+        rv = readfile_heartbeats(path, servers, pool);
+    return rv;
+}
+
 /*
  * Finding a random number in a range. 
  *      n' = a + n(b-a+1)/(M+1)
@@ -252,9 +318,11 @@ static proxy_worker *find_best_hb(proxy_balancer *balancer,
 
     for (i = 0; i < balancer->workers->nelts; i++) {
         worker = &APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
-        server = apr_hash_get(servers, (*worker)->hostname, APR_HASH_KEY_STRING);
+        server = apr_hash_get(servers, (*worker)->s->hostname, APR_HASH_KEY_STRING);
 
         if (!server) {
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
+                      "lb_heartbeat: No server for worker %s", (*worker)->s->name);
             continue;
         }
 
@@ -273,7 +341,7 @@ static proxy_worker *find_best_hb(proxy_balancer *balancer,
 
     if (openslots > 0) {
         apr_uint32_t c = 0;
-        apr_uint32_t pick = 0;;
+        apr_uint32_t pick = 0;
 
         rv = random_pick(&pick, 0, openslots);
 
@@ -286,7 +354,7 @@ static proxy_worker *find_best_hb(proxy_balancer *balancer,
 
         for (i = 0; i < up_servers->nelts; i++) {
             server = APR_ARRAY_IDX(up_servers, i, hb_server_t *);
-            if (pick > c && pick <= c + server->ready) {
+            if (pick >= c && pick <= c + server->ready) {
                 mycandidate = server->worker;
             }
 
@@ -299,11 +367,11 @@ static proxy_worker *find_best_hb(proxy_balancer *balancer,
     return mycandidate;
 }
 
-static apr_status_t reset(proxy_balancer *balancer, request_rec *r) {
+static apr_status_t reset(proxy_balancer *balancer, server_rec *s) {
         return APR_SUCCESS;
 }
 
-static apr_status_t age(proxy_balancer *balancer, request_rec *r) {
+static apr_status_t age(proxy_balancer *balancer, server_rec *s) {
         return APR_SUCCESS;
 }
 
@@ -311,14 +379,47 @@ static const proxy_balancer_method heartbeat =
 {
     "heartbeat",
     &find_best_hb,
+    NULL,
     &reset,
-    &age,
-    NULL
+    &age
 };
 
+static int lb_hb_init(apr_pool_t *p, apr_pool_t *plog,
+                          apr_pool_t *ptemp, server_rec *s)
+{
+    apr_size_t size;
+    unsigned int num;
+    lb_hb_ctx_t *ctx = ap_get_module_config(s->module_config,
+                                            &lbmethod_heartbeat_module);
+    
+    /* do nothing on first call */
+    if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
+        return OK;
+
+    storage = ap_lookup_provider(AP_SLOTMEM_PROVIDER_GROUP, "shared", "0");
+    if (!storage) {
+        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, s, "ap_lookup_provider %s failed", AP_SLOTMEM_PROVIDER_GROUP);
+        return OK;
+    }
+
+    /* Try to use a slotmem created by mod_heartmonitor */
+    storage->attach(&hm_serversmem, "mod_heartmonitor", &size, &num, p);
+    if (!hm_serversmem) {
+        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, s, "No slotmem from mod_heartmonitor");
+    } else
+        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, s, "Using slotmem from mod_heartmonitor");
+
+    if (hm_serversmem)
+        ctx->path = "(slotmem)";
+
+    return OK;
+}
+
 static void register_hooks(apr_pool_t *p)
 {
+    static const char * const aszPred[]={ "mod_heartmonitor.c", NULL };
     ap_register_provider(p, PROXY_LBMETHOD, "heartbeat", "0", &heartbeat);
+    ap_hook_post_config(lb_hb_init, aszPred, NULL, APR_HOOK_MIDDLE);
 }
 
 static void *lb_hb_create_config(apr_pool_t *p, server_rec *s)
@@ -371,7 +472,7 @@ static const command_rec cmds[] = {
     {NULL}
 };
 
-module AP_MODULE_DECLARE_DATA lbmethod_heartbeat_module = {
+AP_DECLARE_MODULE(lbmethod_heartbeat) = {
     STANDARD20_MODULE_STUFF,
     NULL,                       /* create per-directory config structure */
     NULL,                       /* merge per-directory config structures */