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";
}
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;
ps->badopt = bad_error;
ps->badopt_set = 0;
ps->pool = p;
-
- ap_proxy_add_lbmethods(ps);
-
+
return ps;
}
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;
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;
#include "http_connection.h"
#include "util_filter.h"
#include "util_ebcdic.h"
+#include "ap_provider.h"
#if APR_HAVE_NETINET_IN_H
#include <netinet/in.h>
} 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;
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
#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.
*/
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;
}
}
}
bsel->max_attempts);
ap_rputs("<tr><td>LB Method:</td><td><select name=\"lm\">", r);
{
- struct proxy_balancer_method *ent =
- (struct proxy_balancer_method *) conf->lbmethods->elts;
+ apr_array_header_t *methods;
+ ap_list_provider_names_t *method;
int i;
- for (i = 0; i < conf->lbmethods->nelts; i++) {
- ap_rprintf(r, "<option value=\"%s\" %s>%s</option>", ent->name,
- (!strcasecmp(bsel->lbmethod->name, ent->name)) ? "selected" : "",
- ent->name);
- ent++;
+ methods = ap_list_provider_names(r->pool, PROXY_LBMETHOD, "0");
+ method = (ap_list_provider_names_t *)methods->elts;
+ for (i = 0; i < methods->nelts; i++) {
+ ap_rprintf(r, "<option value=\"%s\" %s>%s</option>", method->provider_name,
+ (!strcasecmp(bsel->lbmethod->name, method->provider_name)) ? "selected" : "",
+ method->provider_name);
+ method++;
}
}
ap_rputs("</select></td></tr>\n", r);
}
+/*
+ * 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.
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 = {
const char *url)
{
char *c, *q, *uri = apr_pstrdup(p, url);
- int i;
proxy_balancer_method *lbmethod;
c = strchr(uri, ':');
* 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;
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;
-}