From: Jim Jagielski Date: Fri, 9 Sep 2005 12:28:02 +0000 (+0000) Subject: Proxy balancer lbmethods are now registered as providers and not X-Git-Tag: 2.3.0~3016 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22c5cb47286201159272033868f91eb18731d51c;p=thirdparty%2Fapache%2Fhttpd.git Proxy balancer lbmethods are now registered as providers and not via hooks. Move various find() functions back to mod_proxy_balancer where they belong :) git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@279752 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 2c1ba35a453..3053592f46d 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -273,15 +273,10 @@ static const char *set_balancer_param(proxy_server_conf *conf, balancer->max_attempts_set = 1; } else if (!strcasecmp(key, "lbmethod")) { - struct proxy_balancer_method *ent = - (struct proxy_balancer_method *) conf->lbmethods->elts; - int i; - for (i = 0; i < conf->lbmethods->nelts; i++) { - if (!strcasecmp(val, ent->name)) { - balancer->lbmethod = ent; - return NULL; - } - ent++; + proxy_balancer_method *provider; + if (provider = ap_lookup_provider(PROXY_LBMETHOD, val, "0")) { + balancer->lbmethod = provider; + return NULL; } return "unknown lbmethod"; } @@ -798,7 +793,6 @@ static void * create_proxy_config(apr_pool_t *p, server_rec *s) 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(proxy_balancer)); - ps->lbmethods = apr_array_make(p, 10, sizeof(proxy_balancer_method)); ps->forward = NULL; ps->reverse = NULL; ps->domain = NULL; @@ -821,9 +815,7 @@ static void * create_proxy_config(apr_pool_t *p, server_rec *s) ps->badopt = bad_error; ps->badopt_set = 0; ps->pool = p; - - ap_proxy_add_lbmethods(ps); - + return ps; } @@ -841,7 +833,6 @@ static void * merge_proxy_config(apr_pool_t *p, void *basev, void *overridesv) 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->lbmethods = base->lbmethods; ps->forward = overrides->forward ? overrides->forward : base->forward; ps->reverse = overrides->reverse ? overrides->reverse : base->reverse; @@ -1522,7 +1513,7 @@ static const char * err = set_balancer_param(conf, cmd->pool, balancer, word, val); if (err) - return apr_pstrcat(cmd->temp_pool, "ProxySet ", err, " ", word, " ", name, NULL); + return apr_pstrcat(cmd->temp_pool, "ProxySet: ", err, " ", word, "=", val, "; ", name, NULL); } return NULL; diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 5cbaed148c4..63ed1afe2cf 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -73,6 +73,7 @@ #include "http_connection.h" #include "util_filter.h" #include "util_ebcdic.h" +#include "ap_provider.h" #if APR_HAVE_NETINET_IN_H #include @@ -185,7 +186,6 @@ typedef struct { } proxy_status; /* Status display options */ char proxy_status_set; apr_pool_t *pool; /* Pool used for allocating this struct */ - apr_array_header_t *lbmethods; } proxy_server_conf; @@ -670,14 +670,6 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, proxy_conn_rec *conn, conn_rec *c, server_rec *s); -/** - * Load in available lb methods - * @param conf server conf - * @return OK or HTTP_XXX error - */ - -PROXY_DECLARE(int) ap_proxy_add_lbmethods(proxy_server_conf *conf); - /* Scoreboard */ #if MODULE_MAGIC_NUMBER_MAJOR > 20020903 #define PROXY_HAS_SCOREBOARD 1 @@ -685,6 +677,8 @@ PROXY_DECLARE(int) ap_proxy_add_lbmethods(proxy_server_conf *conf); #define PROXY_HAS_SCOREBOARD 0 #endif +#define PROXY_LBMETHOD "proxylbmethod" + /* The number of dynamic workers that can be added when reconfiguring. * If this limit is reached you must stop and restart the server. */ diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index 7bb3d1252f0..8a629bff002 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -516,15 +516,9 @@ static int balancer_handler(request_rec *r) bsel->max_attempts_set = 1; } if ((val = apr_table_get(params, "lm"))) { - struct proxy_balancer_method *ent = - (struct proxy_balancer_method *) conf->lbmethods->elts; - int i; - for (i = 0; i < conf->lbmethods->nelts; i++) { - if (!strcasecmp(val, ent->name)) { - bsel->lbmethod = ent; - break; - } - ent++; + proxy_balancer_method *provider; + if (provider = ap_lookup_provider(PROXY_LBMETHOD, val, "0")) { + bsel->lbmethod = provider; } } } @@ -695,14 +689,16 @@ static int balancer_handler(request_rec *r) bsel->max_attempts); ap_rputs("LB Method:\n", r); @@ -738,6 +734,176 @@ static void child_init(apr_pool_t *p, server_rec *s) } +/* + * The idea behind the find_best_byrequests scheduler is the following: + * + * lbfactor is "how much we expect this worker to work", or "the worker's + * normalized work quota". + * + * lbstatus is "how urgent this worker has to work to fulfill its quota + * of work". + * + * We distribute each worker's work quota to the worker, and then look + * which of them needs to work most urgently (biggest lbstatus). This + * worker is then selected for work, and its lbstatus reduced by the + * total work quota we distributed to all workers. Thus the sum of all + * lbstatus does not change.(*) + * + * If some workers are disabled, the others will + * still be scheduled correctly. + * + * If a balancer is configured as follows: + * + * worker a b c d + * lbfactor 25 25 25 25 + * + * And b gets disabled, the following schedule is produced: + * + * a c d a c d a c d ... + * + * Note that the above lbfactor setting is the *exact* same as: + * + * worker a b c d + * lbfactor 1 1 1 1 + * + * Asymmetric configurations work as one would expect. For + * example: + * + * worker a b c d + * lbfactor 1 1 1 2 + * + * would have a, b and c all handling about the same + * amount of load with d handling twice what a or b + * or c handles individually. So we could see: + * + * b a d c d a c d b d ... + * + */ + +static proxy_worker *find_best_byrequests(proxy_balancer *balancer, + request_rec *r) +{ + int i; + int total_factor = 0; + proxy_worker *worker = (proxy_worker *)balancer->workers->elts; + proxy_worker *mycandidate = NULL; + + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: Entering byrequests for BALANCER (%s)", + balancer->name); + + /* First try to see if we have available candidate */ + for (i = 0; i < balancer->workers->nelts; i++) { + /* If the worker is in error state run + * retry on that worker. It will be marked as + * operational if the retry timeout is elapsed. + * The worker might still be unusable, but we try + * anyway. + */ + if (!PROXY_WORKER_IS_USABLE(worker)) + ap_proxy_retry_worker("BALANCER", worker, r->server); + /* Take into calculation only the workers that are + * not in error state or not disabled. + */ + if (PROXY_WORKER_IS_USABLE(worker)) { + worker->s->lbstatus += worker->s->lbfactor; + total_factor += worker->s->lbfactor; + if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus) + mycandidate = worker; + } + worker++; + } + + if (mycandidate) { + mycandidate->s->lbstatus -= total_factor; + mycandidate->s->elected++; + } + + return mycandidate; +} + +/* + * The idea behind the find_best_bytraffic scheduler is the following: + * + * We know the amount of traffic (bytes in and out) handled by each + * worker. We normalize that traffic by each workers' weight. So assuming + * a setup as below: + * + * worker a b c + * lbfactor 1 1 3 + * + * the scheduler will allow worker c to handle 3 times the + * traffic of a and b. If each request/response results in the + * same amount of traffic, then c would be accessed 3 times as + * often as a or b. If, for example, a handled a request that + * resulted in a large i/o bytecount, then b and c would be + * chosen more often, to even things out. + */ +static proxy_worker *find_best_bytraffic(proxy_balancer *balancer, + request_rec *r) +{ + int i; + apr_off_t mytraffic = 0; + apr_off_t curmin = 0; + proxy_worker *worker = (proxy_worker *)balancer->workers->elts; + proxy_worker *mycandidate = NULL; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, + "proxy: Entering bytraffic for BALANCER (%s)", + balancer->name); + + /* First try to see if we have available candidate */ + for (i = 0; i < balancer->workers->nelts; i++) { + /* If the worker is in error state run + * retry on that worker. It will be marked as + * operational if the retry timeout is elapsed. + * The worker might still be unusable, but we try + * anyway. + */ + if (!PROXY_WORKER_IS_USABLE(worker)) + ap_proxy_retry_worker("BALANCER", worker, r->server); + /* Take into calculation only the workers that are + * not in error state or not disabled. + */ + if (PROXY_WORKER_IS_USABLE(worker)) { + mytraffic = (worker->s->transferred/worker->s->lbfactor) + + (worker->s->read/worker->s->lbfactor); + if (!mycandidate || mytraffic < curmin) { + mycandidate = worker; + curmin = mytraffic; + } + } + worker++; + } + + if (mycandidate) { + mycandidate->s->elected++; + } + + return mycandidate; +} + +/* + * How to add additional lbmethods: + * 1. Create func which determines "best" candidate worker + * (eg: find_best_bytraffic, above) + * 2. Register it as a provider. + */ +static const proxy_balancer_method byrequests = +{ + "byrequests", + &find_best_byrequests, + NULL +}; + +static const proxy_balancer_method bytraffic = +{ + "bytraffic", + &find_best_bytraffic, + NULL +}; + static void ap_proxy_balancer_register_hook(apr_pool_t *p) { /* Only the mpm_winnt has child init hook handler. @@ -751,6 +917,8 @@ static void ap_proxy_balancer_register_hook(apr_pool_t *p) proxy_hook_pre_request(proxy_balancer_pre_request, NULL, NULL, APR_HOOK_FIRST); proxy_hook_post_request(proxy_balancer_post_request, NULL, NULL, APR_HOOK_FIRST); proxy_hook_canon_handler(proxy_balancer_canon, NULL, NULL, APR_HOOK_FIRST); + ap_register_provider(p, PROXY_LBMETHOD, "bytraffic", "0", &bytraffic); + ap_register_provider(p, PROXY_LBMETHOD, "byrequests", "0", &byrequests); } module AP_MODULE_DECLARE_DATA proxy_balancer_module = { diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 15d9c610423..08f7f85a1b3 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1155,7 +1155,6 @@ PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer, const char *url) { char *c, *q, *uri = apr_pstrdup(p, url); - int i; proxy_balancer_method *lbmethod; c = strchr(uri, ':'); @@ -1173,12 +1172,9 @@ PROXY_DECLARE(const char *) ap_proxy_add_balancer(proxy_balancer **balancer, * NOTE: The default method is byrequests, which we assume * exists! */ - lbmethod = (proxy_balancer_method *)conf->lbmethods->elts; - for (i = 0; i < conf->lbmethods->nelts; i++) { - if (!strcasecmp(lbmethod->name, "byrequests")) { - break; - } - lbmethod++; + lbmethod = ap_lookup_provider(PROXY_LBMETHOD, "byrequests", "0"); + if (!lbmethod) { + return "Can't find 'byrequests' lb method"; } (*balancer)->name = uri; @@ -2069,176 +2065,3 @@ int ap_proxy_lb_workers(void) lb_workers_limit = proxy_lb_workers + PROXY_DYNAMIC_BALANCER_LIMIT; return lb_workers_limit; } - -/* - * The idea behind the find_best_byrequests scheduler is the following: - * - * lbfactor is "how much we expect this worker to work", or "the worker's - * normalized work quota". - * - * lbstatus is "how urgent this worker has to work to fulfill its quota - * of work". - * - * We distribute each worker's work quota to the worker, and then look - * which of them needs to work most urgently (biggest lbstatus). This - * worker is then selected for work, and its lbstatus reduced by the - * total work quota we distributed to all workers. Thus the sum of all - * lbstatus does not change.(*) - * - * If some workers are disabled, the others will - * still be scheduled correctly. - * - * If a balancer is configured as follows: - * - * worker a b c d - * lbfactor 25 25 25 25 - * - * And b gets disabled, the following schedule is produced: - * - * a c d a c d a c d ... - * - * Note that the above lbfactor setting is the *exact* same as: - * - * worker a b c d - * lbfactor 1 1 1 1 - * - * Asymmetric configurations work as one would expect. For - * example: - * - * worker a b c d - * lbfactor 1 1 1 2 - * - * would have a, b and c all handling about the same - * amount of load with d handling twice what a or b - * or c handles individually. So we could see: - * - * b a d c d a c d b d ... - * - */ - -static proxy_worker *find_best_byrequests(proxy_balancer *balancer, - request_rec *r) -{ - int i; - int total_factor = 0; - proxy_worker *worker = (proxy_worker *)balancer->workers->elts; - proxy_worker *mycandidate = NULL; - - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: Entering byrequests for BALANCER (%s)", - balancer->name); - - /* First try to see if we have available candidate */ - for (i = 0; i < balancer->workers->nelts; i++) { - /* If the worker is in error state run - * retry on that worker. It will be marked as - * operational if the retry timeout is elapsed. - * The worker might still be unusable, but we try - * anyway. - */ - if (!PROXY_WORKER_IS_USABLE(worker)) - ap_proxy_retry_worker("BALANCER", worker, r->server); - /* Take into calculation only the workers that are - * not in error state or not disabled. - */ - if (PROXY_WORKER_IS_USABLE(worker)) { - worker->s->lbstatus += worker->s->lbfactor; - total_factor += worker->s->lbfactor; - if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus) - mycandidate = worker; - } - worker++; - } - - if (mycandidate) { - mycandidate->s->lbstatus -= total_factor; - mycandidate->s->elected++; - } - - return mycandidate; -} - -/* - * The idea behind the find_best_bytraffic scheduler is the following: - * - * We know the amount of traffic (bytes in and out) handled by each - * worker. We normalize that traffic by each workers' weight. So assuming - * a setup as below: - * - * worker a b c - * lbfactor 1 1 3 - * - * the scheduler will allow worker c to handle 3 times the - * traffic of a and b. If each request/response results in the - * same amount of traffic, then c would be accessed 3 times as - * often as a or b. If, for example, a handled a request that - * resulted in a large i/o bytecount, then b and c would be - * chosen more often, to even things out. - */ -static proxy_worker *find_best_bytraffic(proxy_balancer *balancer, - request_rec *r) -{ - int i; - apr_off_t mytraffic = 0; - apr_off_t curmin = 0; - proxy_worker *worker = (proxy_worker *)balancer->workers->elts; - proxy_worker *mycandidate = NULL; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: Entering bytraffic for BALANCER (%s)", - balancer->name); - - /* First try to see if we have available candidate */ - for (i = 0; i < balancer->workers->nelts; i++) { - /* If the worker is in error state run - * retry on that worker. It will be marked as - * operational if the retry timeout is elapsed. - * The worker might still be unusable, but we try - * anyway. - */ - if (!PROXY_WORKER_IS_USABLE(worker)) - ap_proxy_retry_worker("BALANCER", worker, r->server); - /* Take into calculation only the workers that are - * not in error state or not disabled. - */ - if (PROXY_WORKER_IS_USABLE(worker)) { - mytraffic = (worker->s->transferred/worker->s->lbfactor) + - (worker->s->read/worker->s->lbfactor); - if (!mycandidate || mytraffic < curmin) { - mycandidate = worker; - curmin = mytraffic; - } - } - worker++; - } - - if (mycandidate) { - mycandidate->s->elected++; - } - - return mycandidate; -} - -/* - * How to add additional lbmethods: - * 1. Create func which determines "best" candidate worker - * (eg: find_best_bytraffic, above) - * 2. Create proxy_balancer_method struct which - * defines the method and add it to - * available server methods using - * ap_proxy_add_lbmethods. - */ -PROXY_DECLARE(int) ap_proxy_add_lbmethods(proxy_server_conf *conf) -{ - proxy_balancer_method *new; - - new = apr_array_push(conf->lbmethods); - new->name = "byrequests"; - new->finder = find_best_byrequests; - new = apr_array_push(conf->lbmethods); - new->name = "bytraffic"; - new->finder = find_best_bytraffic; - - return OK; -}