You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by wr...@apache.org on 2004/08/11 23:25:16 UTC

cvs commit: httpd-2.0/modules/proxy mod_proxy.c mod_proxy.h

wrowe       2004/08/11 14:25:16

  Modified:    modules/proxy mod_proxy.c mod_proxy.h
  Log:
  Use API instead directly obtaining worker and balancer.
  Add BalancerStickySession and BalanceMember directives.
  Add workers and balancers to create and merge config.
  
  Submitted by: mturk
  
  Revision  Changes    Path
  1.105     +265 -1    httpd-2.0/modules/proxy/mod_proxy.c
  
  Index: mod_proxy.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/proxy/mod_proxy.c,v
  retrieving revision 1.104
  retrieving revision 1.105
  diff -u -r1.104 -r1.105
  --- mod_proxy.c	11 Aug 2004 21:14:49 -0000	1.104
  +++ mod_proxy.c	11 Aug 2004 21:25:15 -0000	1.105
  @@ -535,6 +535,8 @@
       ps->noproxies = apr_array_make(p, 10, sizeof(struct noproxy_entry));
       ps->dirconn = apr_array_make(p, 10, sizeof(struct dirconn_entry));
       ps->allowed_connect_ports = apr_array_make(p, 10, sizeof(int));
  +    ps->workers = apr_array_make(p, 10, sizeof(proxy_worker));
  +    ps->balancers = apr_array_make(p, 10, sizeof(struct proxy_balancer));
       ps->domain = NULL;
       ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
       ps->viaopt_set = 0; /* 0 means default */
  @@ -576,6 +578,8 @@
       ps->noproxies = apr_array_append(p, base->noproxies, overrides->noproxies);
       ps->dirconn = apr_array_append(p, base->dirconn, overrides->dirconn);
       ps->allowed_connect_ports = apr_array_append(p, base->allowed_connect_ports, overrides->allowed_connect_ports);
  +    ps->workers = apr_array_append(p, base->workers, overrides->workers);
  +    ps->balancers = apr_array_append(p, base->balancers, overrides->balancers);
   
       ps->domain = (overrides->domain == NULL) ? base->domain : overrides->domain;
       ps->viaopt = (overrides->viaopt_set == 0) ? base->viaopt : overrides->viaopt;
  @@ -1023,6 +1027,136 @@
       return NULL;    
   }
   
  +static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg)
  +{
  +    server_rec *s = cmd->server;
  +    proxy_server_conf *conf =
  +    ap_get_module_config(s->module_config, &proxy_module);
  +    struct proxy_balancer *balancer, *balancers;
  +    proxy_worker *worker;
  +    char *path = NULL;
  +    char *name = NULL;
  +    char *args = apr_pstrdup(cmd->pool, arg);
  +    char *word;
  +    apr_table_t *params = apr_table_make(cmd->pool, 5);
  +    const apr_array_header_t *arr;
  +    const apr_table_entry_t *elts;
  +    int i;
  +    
  +    if (cmd->path)
  +        path = apr_pstrdup(cmd->pool, cmd->path);
  +    while (*args) {
  +        word = ap_getword_conf(cmd->pool, &args);
  +        if (!path)
  +            path = word;
  +        else if (!name)
  +            name = word;
  +        else {
  +            char *val = strchr(word, '=');
  +            if (!val)
  +                return "Invalid BalancerMember parameter. Paramet must be in the form key=value";
  +            else
  +                *val++ = '\0';
  +            apr_table_setn(params, word, val);
  +        }
  +    }
  +    if (!path)
  +        return "BalancerMember must define balancer name when outside <Proxy > section";
  +    if (!name)
  +        return "BalancerMember must define remote proxy server";
  +    
  +    ap_str_tolower(path);	/* lowercase scheme://hostname */
  +    ap_str_tolower(name);	/* lowercase scheme://hostname */
  +
  +    /* Try to find existing worker */
  +    worker = ap_proxy_get_worker(cmd->temp_pool, conf, name);
  +    if (!worker) {
  +        const char *err;
  +        if ((err = ap_proxy_add_worker(&worker, cmd->pool, conf, name)) != NULL)
  +            return apr_pstrcat(cmd->temp_pool, "BalancerMember: ", err, NULL); 
  +    }
  +
  +    arr = apr_table_elts(params);
  +    elts = (const apr_table_entry_t *)arr->elts;
  +    for (i = 0; i < arr->nelts; i++) {
  +        if (!strcasecmp(elts[i].key, "loadfactor")) {
  +            worker->lbfactor = atoi(elts[i].val);
  +            if (worker->lbfactor < 1 || worker->lbfactor > 100)
  +                return "BalancerMember: loadfactor must be number between 1..100";
  +        }
  +        else if (!strcasecmp(elts[i].key, "retry")) {
  +            int sec = atoi(elts[i].val);
  +            if (sec < 0)
  +                return "BalancerMember: retry must be positive number";
  +            worker->retry = apr_time_from_sec(sec);
  +        }
  +    }
  +    /* Try to find the balancer */
  +    balancers = (struct proxy_balancer *)conf->balancers->elts;
  +    for (i = 0; i < conf->balancers->nelts; i++) {
  +        if (!strcmp(name, balancers[i].name)) {
  +            balancer = &balancers[i];
  +            break;
  +        }
  +    }
  +
  +    if (!balancer) {
  +        apr_status_t rc = 0;
  +#if DEBUGGING
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
  +                     "Creating new balancer %s", path);
  +#endif
  +        balancer = (struct proxy_balancer *)apr_pcalloc(cmd->pool, sizeof(struct proxy_balancer));
  +        balancer->name = path;
  +        balancer->workers = apr_array_make(cmd->pool, 5, sizeof(proxy_runtime_worker));
  +        /* XXX Is this a right place to create mutex */
  +#if APR_HAS_THREADS
  +        if ((rc = apr_thread_mutex_create(&(balancer->mutex),
  +            APR_THREAD_MUTEX_DEFAULT, cmd->pool)) != APR_SUCCESS) {
  +            /* XXX: Do we need to log something here */
  +            return "BalancerMember: system error. Can not create thread mutex";
  +        }
  +#endif
  +    }
  +    /* Add the worker to the load balancer */
  +    ap_proxy_add_worker_to_balancer(balancer, worker);
  +
  +    return NULL;
  +}
  +
  +static const char *
  +    set_sticky_session(cmd_parms *cmd, void *dummy, const char *f, const char *r)
  +{
  +    server_rec *s = cmd->server;
  +    proxy_server_conf *conf =
  +    ap_get_module_config(s->module_config, &proxy_module);
  +    struct proxy_balancer *balancer;
  +    const char *name, *sticky;
  +
  +    if (r != NULL && cmd->path == NULL ) {
  +        name = f;
  +        sticky = r;
  +    } else if (r == NULL && cmd->path != NULL) {
  +        name = cmd->path;
  +        sticky = f;
  +    } else {
  +        if (r == NULL)
  +            return "BalancerStickySession needs a path when not defined in a location";
  +        else 
  +            return "BalancerStickySession can not have a path when defined in a location";
  +    }
  +    /* Try to find the balancer */
  +    balancer = ap_proxy_get_balancer(cmd->temp_pool, conf, name);
  +    if (!balancer)
  +        return apr_pstrcat(cmd->temp_pool, "BalancerStickySession: can not find a load balancer '",
  +                           name, "'", NULL);
  +    if (!strcasecmp(sticky, "nofailover"))
  +        balancer->sticky_force = 1;   
  +    else
  +        balancer->sticky = sticky;
  +    return NULL;
  +}
  +
   static void ap_add_per_proxy_conf(server_rec *s, ap_conf_vector_t *dir_config)
   {
       proxy_server_conf *sconf = ap_get_module_config(s->module_config,
  @@ -1163,7 +1297,10 @@
        "This overrides the server timeout"),
       AP_INIT_TAKE1("ProxyBadHeader", set_bad_opt, NULL, RSRC_CONF,
        "How to handle bad header line in response: IsError | Ignore | StartBody"),
  - 
  +    AP_INIT_ITERATE("BalancerMember", add_member, NULL, RSRC_CONF|ACCESS_CONF,
  +     "A balancer name and scheme with list of params"), 
  +    AP_INIT_TAKE12("BalancerStickySession", set_sticky_session, NULL, RSRC_CONF|ACCESS_CONF,
  +     "A balancer and sticky session name"),
       {NULL}
   };
   
  @@ -1190,6 +1327,133 @@
       }
   
       return 0;
  +}
  +
  +PROXY_DECLARE(struct proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p,
  +                                                             proxy_server_conf *conf,
  +                                                             const char *url)
  +{
  +    struct proxy_balancer *balancers;
  +    char *c, *uri = apr_pstrdup(p, url);
  +    int i;
  +    
  +    c = strchr(url, ':');   
  +    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
  +       return NULL;
  +    /* remove path from uri */
  +    if ((c = strchr(c + 3, '/')))
  +        *c = '\0';
  +    balancers = (struct proxy_balancer *)conf->balancers;
  +    for (i = 0; i < conf->balancers->nelts; i++) {
  +        if (strcasecmp(balancers[i].name, uri) == 0)
  +            return &balancers[i];
  +    }
  +    return NULL;
  +}
  +
  +PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p,
  +                                                  proxy_server_conf *conf,
  +                                                  const char *url)
  +{
  +    proxy_worker *workers;
  +    char *c, *uri = apr_pstrdup(p, url);
  +    int i;
  +    
  +    c = strchr(url, ':');   
  +    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
  +       return NULL;
  +    /* remove path from uri */
  +    if ((c = strchr(c + 3, '/')))
  +        *c = '\0';
  +    workers = (proxy_worker *)conf->workers;
  +    for (i = 0; i < conf->workers->nelts; i++) {
  +        if (strcasecmp(workers[i].name, uri) == 0)
  +            return &workers[i];
  +    }
  +    return NULL;
  +}
  +
  +PROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker,
  +                                                apr_pool_t *p,
  +                                                proxy_server_conf *conf,
  +                                                const char *url)
  +{
  +    char *c, *q, *uri = apr_pstrdup(p, url);
  +    int port;
  +    
  +    c = strchr(url, ':');   
  +    if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0')
  +       return "Bad syntax for a remote proxy server";
  +    /* remove path from uri */
  +    if ((q = strchr(c + 3, '/')))
  +        *q = '\0';
  +
  +    q = strchr(c + 3, ':');
  +    if (q != NULL) {
  +        if (sscanf(q + 1, "%u", &port) != 1 || port > 65535) {
  +            return "Bad syntax for a remote proxy server (bad port number)";
  +        }
  +        *q = '\0';
  +    }
  +    else
  +        port = -1;
  +    ap_str_tolower(uri);
  +    *worker = apr_array_push(conf->workers);
  +    (*worker)->name = apr_pstrdup(p, uri);
  +    *c = '\0';
  +    (*worker)->scheme = uri;
  +    if (port == -1)
  +        port = apr_uri_port_of_scheme((*worker)->scheme);
  +    (*worker)->port = port;
  +
  +    return NULL;
  +}
  +
  +PROXY_DECLARE(void) 
  +ap_proxy_add_worker_to_balancer(struct proxy_balancer *balancer, proxy_worker *worker)
  +{
  +    int i;
  +    double median, ffactor = 0.0;
  +    proxy_runtime_worker *runtime, *workers;
  +
  +    runtime = apr_array_push(balancer->workers);
  +    runtime->w = worker;
  +
  +    /* Recalculate lbfactors */
  +    workers = (proxy_runtime_worker *)balancer->workers->elts;
  +
  +    for (i = 0; i < balancer->workers->nelts; i++) {
  +        /* Set to the original configuration */
  +        workers[i].lbfactor = workers[i].w->lbfactor;
  +        ffactor += workers[i].lbfactor;
  +    }
  +    if (ffactor < 100.0) {
  +        int z = 0;
  +        for (i = 0; i < balancer->workers->nelts; i++) {
  +            if (workers[i].lbfactor == 0.0) 
  +                ++z;
  +        }
  +        if (z) {
  +            median = (100.0 - ffactor) / z;
  +            for (i = 0; i < balancer->workers->nelts; i++) {
  +                if (workers[i].lbfactor == 0.0) 
  +                    workers[i].lbfactor = median;
  +            }
  +        }
  +        else {
  +            median = (100.0 - ffactor) / balancer->workers->nelts;
  +            for (i = 0; i < balancer->workers->nelts; i++)
  +                workers[i].lbfactor += median;
  +        }
  +    }
  +    else if (ffactor > 100.0) {
  +        median = (ffactor - 100.0) / balancer->workers->nelts;
  +        for (i = 0; i < balancer->workers->nelts; i++) {
  +            if (workers[i].lbfactor > median)
  +                workers[i].lbfactor -= median;
  +        }
  +    } 
  +
   }
   
   static int proxy_post_config(apr_pool_t *pconf, apr_pool_t *plog,
  
  
  
  1.95      +5 -0      httpd-2.0/modules/proxy/mod_proxy.h
  
  Index: mod_proxy.h
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/proxy/mod_proxy.h,v
  retrieving revision 1.94
  retrieving revision 1.95
  diff -u -r1.94 -r1.95
  --- mod_proxy.h	11 Aug 2004 21:20:07 -0000	1.94
  +++ mod_proxy.h	11 Aug 2004 21:25:15 -0000	1.95
  @@ -219,6 +219,7 @@
       apr_interval_time_t retry;  /* retry interval */
       int             retries;    /* number of retries on this worker */
       int             lbfactor;   /* initial load balancing factor */
  +    const char      *name;
       const char      *scheme;    /* scheme to use ajp|http|https */
       const char      *hostname;  /* remote backend address */
       apr_port_t      port;
  @@ -313,6 +314,10 @@
   PROXY_DECLARE(int) ap_proxy_ssl_disable(conn_rec *c);
   
   /* Connection pool API */
  +PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, proxy_server_conf *conf, const char *url);
  +PROXY_DECLARE(const char *) ap_proxy_add_worker(proxy_worker **worker, apr_pool_t *p, proxy_server_conf *conf, const char *url);
  +PROXY_DECLARE(struct proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p, proxy_server_conf *conf, const char *url);
  +PROXY_DECLARE(void) ap_proxy_add_worker_to_balancer(struct proxy_balancer *balancer, proxy_worker *worker);
   
   
   /* For proxy_util */