From: Jim Jagielski Date: Wed, 30 Aug 2006 17:50:47 +0000 (+0000) Subject: Merge r420936, r420954, r420986, r421283 from trunk: X-Git-Tag: 2.2.4~182 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=920d31a23d5611fbfe5ec3616996e13c7d52e021;p=thirdparty%2Fapache%2Fhttpd.git Merge r420936, r420954, r420986, r421283 from trunk: Restructure the find_route_worker() function. Basically, it should take care of knowing about usable and unusable workers. By centralizing this logic, it will make it easier and more streamlined to add in the forthcoming hot-standby status workers. Clean up some proxy macros. Avoid the use of magic numbers, and instead use pre-defined defines. Also, ensure that usable workers have been initialized :) Allocate a bit for hot standbys. Adjust so that normal "usable" workers don't count these. Add in hot-standby balancer member. If all other members are disabled or not-usable, ONLY THEN will the hot standby's be used. Reviewed by: jim git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@438563 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 8403fa60b83..916b9c64fa8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ -*- coding: utf-8 -*- Changes with Apache 2.2.4 + *) mod_proxy_balancer: Workers can now be defined as "hot standby" which + will only be used if all other workers are unusable (eg: in + error or disabled). Also, the balancer-manager displays the election + count and I/O counts of all workers. [Jim Jagielski] + *) mod_proxy_ajp: Close connection to backend if reading of request body fails. PR 40310. [Ian Abel ] diff --git a/STATUS b/STATUS index c6b29c2f4ed..3c8a3d5ea31 100644 --- a/STATUS +++ b/STATUS @@ -94,16 +94,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: Trunk version works +1: jim, mturk, rpluem - * mod_proxy_balancer: Add in Hot Standby worker functionality. - Trunk version of patch: - http://svn.apache.org/viewvc?view=rev&revision=420936 - http://svn.apache.org/viewvc?view=rev&revision=420954 - http://svn.apache.org/viewvc?view=rev&revision=420986 - http://svn.apache.org/viewvc?view=rev&revision=421283 - 2.2.x version of patch: - http://people.apache.org/~jim/patches/hot-standby.txt - +1: jim, mturk, rpluem - PATCHES PROPOSED TO BACKPORT FROM TRUNK: * mpm_winnt: Fix return values from wait_for_many_objects. diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 09ef3a72a59..41f7c0fb9df 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -213,8 +213,14 @@ static const char *set_worker_param(apr_pool_t *p, else worker->status &= ~PROXY_WORKER_IN_ERROR; } + else if (*v == 'H' || *v == 'h') { + if (mode) + worker->status |= PROXY_WORKER_HOT_STANDBY; + else + worker->status &= ~PROXY_WORKER_HOT_STANDBY; + } else { - return "Unknow status parameter option"; + return "Unknown status parameter option"; } } } diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 2af400dc158..e0fb8adc949 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -241,15 +241,26 @@ struct proxy_conn_pool { proxy_conn_rec *conn; /* Single connection for prefork mpm's */ }; -/* woker status flags */ +/* worker status flags */ #define PROXY_WORKER_INITIALIZED 0x0001 #define PROXY_WORKER_IGNORE_ERRORS 0x0002 #define PROXY_WORKER_IN_SHUTDOWN 0x0010 #define PROXY_WORKER_DISABLED 0x0020 #define PROXY_WORKER_STOPPED 0x0040 #define PROXY_WORKER_IN_ERROR 0x0080 +#define PROXY_WORKER_HOT_STANDBY 0x0100 -#define PROXY_WORKER_IS_USABLE(f) (!((f)->s->status & 0x00F0)) +#define PROXY_WORKER_NOT_USABLE_BITMAP ( PROXY_WORKER_IN_SHUTDOWN | \ +PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR ) + +#define PROXY_WORKER_IS_INITIALIZED(f) ( (f)->s->status & \ + PROXY_WORKER_INITIALIZED ) + +#define PROXY_WORKER_IS_STANDBY(f) ( (f)->s->status & \ + PROXY_WORKER_HOT_STANDBY ) + +#define PROXY_WORKER_IS_USABLE(f) ( !((f)->s->status & \ + (PROXY_WORKER_NOT_USABLE_BITMAP)) && PROXY_WORKER_IS_INITIALIZED(f) ) /* default worker retry timeout in seconds */ #define PROXY_WORKER_DEFAULT_RETRY 60 diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index 1fb57db9d43..d06dad46034 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -169,15 +169,63 @@ static char *get_cookie_param(request_rec *r, const char *name) /* Find the worker that has the 'route' defined */ static proxy_worker *find_route_worker(proxy_balancer *balancer, - const char *route) + const char *route, request_rec *r) { int i; - proxy_worker *worker = (proxy_worker *)balancer->workers->elts; - for (i = 0; i < balancer->workers->nelts; i++) { - if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) { - return worker; + int checking_standby = 0; + int checked_standby = 0; + + proxy_worker *worker; + while (!checked_standby) { + worker = (proxy_worker *)balancer->workers->elts; + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) + continue; + if (*(worker->s->route) && strcmp(worker->s->route, route) == 0) { + if (worker && PROXY_WORKER_IS_USABLE(worker)) { + return worker; + } else { + /* + * 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. + */ + ap_proxy_retry_worker("BALANCER", worker, r->server); + if (PROXY_WORKER_IS_USABLE(worker)) { + return worker; + } else { + /* + * We have a worker that is unusable. + * It can be in error or disabled, but in case + * it has a redirection set use that redirection worker. + * This enables to safely remove the member from the + * balancer. Of course you will need some kind of + * session replication between those two remote. + */ + if (*worker->s->redirect) { + proxy_worker *rworker = NULL; + rworker = find_route_worker(balancer, worker->s->redirect, r); + /* Check if the redirect worker is usable */ + if (rworker && !PROXY_WORKER_IS_USABLE(rworker)) { + /* + * 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. + */ + ap_proxy_retry_worker("BALANCER", rworker, r->server); + } + if (rworker && PROXY_WORKER_IS_USABLE(rworker)) + return rworker; + } + } + } + } } - worker++; + checked_standby = checking_standby++; } return NULL; } @@ -210,42 +258,7 @@ static proxy_worker *find_session_route(proxy_balancer *balancer, /* We have a route in path or in cookie * Find the worker that has this route defined. */ - worker = find_route_worker(balancer, *route); - if (worker && !PROXY_WORKER_IS_USABLE(worker)) { - /* - * 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. - */ - ap_proxy_retry_worker("BALANCER", worker, r->server); - if (!PROXY_WORKER_IS_USABLE(worker)) { - /* - * We have a worker that is unusable. - * It can be in error or disabled, but in case - * it has a redirection set use that redirection worker. - * This enables to safely remove the member from the - * balancer. Of course you will need some kind of - * session replication between those two remote. - */ - if (*worker->s->redirect) - worker = find_route_worker(balancer, worker->s->redirect); - /* Check if the redirect worker is usable */ - if (worker && !PROXY_WORKER_IS_USABLE(worker)) { - /* - * 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. - */ - ap_proxy_retry_worker("BALANCER", worker, r->server); - if (!PROXY_WORKER_IS_USABLE(worker)) - worker = NULL; - } - } - } + worker = find_route_worker(balancer, *route, r); return worker; } else @@ -370,6 +383,9 @@ static int proxy_balancer_pre_request(proxy_worker **worker, for (i = 0; i < (*balancer)->workers->nelts; i++) { /* Take into calculation only the workers that are * not in error state or not disabled. + * + * TODO: Abstract the below, since this is dependent + * on the LB implementation */ if (PROXY_WORKER_IS_USABLE(workers)) { workers->s->lbstatus += workers->s->lbfactor; @@ -662,12 +678,16 @@ static int balancer_handler(request_rec *r) ap_rvputs(r, "", worker->s->redirect, NULL); ap_rprintf(r, "%d", worker->s->lbfactor); if (worker->s->status & PROXY_WORKER_DISABLED) - ap_rputs("Dis", r); - else if (worker->s->status & PROXY_WORKER_IN_ERROR) - ap_rputs("Err", r); - else if (worker->s->status & PROXY_WORKER_INITIALIZED) + ap_rputs("Dis ", r); + if (worker->s->status & PROXY_WORKER_IN_ERROR) + ap_rputs("Err ", r); + if (worker->s->status & PROXY_WORKER_STOPPED) + ap_rputs("Stop ", r); + if (worker->s->status & PROXY_WORKER_HOT_STANDBY) + ap_rputs("Stby ", r); + if (PROXY_WORKER_IS_USABLE(worker)) ap_rputs("Ok", r); - else + if (!PROXY_WORKER_IS_INITIALIZED(worker)) ap_rputs("-", r); ap_rputs("\n", r); @@ -817,34 +837,40 @@ static proxy_worker *find_best_byrequests(proxy_balancer *balancer, { int i; int total_factor = 0; - proxy_worker *worker = (proxy_worker *)balancer->workers->elts; + proxy_worker *worker; proxy_worker *mycandidate = NULL; - - + int checking_standby = 0; + int checked_standby = 0; + 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; + while (!mycandidate && !checked_standby) { + worker = (proxy_worker *)balancer->workers->elts; + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) + continue; + /* 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++; + checked_standby = checking_standby++; } if (mycandidate) { @@ -878,7 +904,9 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer, int i; apr_off_t mytraffic = 0; apr_off_t curmin = 0; - proxy_worker *worker = (proxy_worker *)balancer->workers->elts; + proxy_worker *worker; + int checking_standby = 0; + int checked_standby = 0; proxy_worker *mycandidate = NULL; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, @@ -886,27 +914,32 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer, 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; + while (!mycandidate && !checked_standby) { + worker = (proxy_worker *)balancer->workers->elts; + for (i = 0; i < balancer->workers->nelts; i++, worker++) { + if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) ) + continue; + /* 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++; + checked_standby = checking_standby++; } if (mycandidate) { diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 908c704a032..a6f9874d4bc 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1605,7 +1605,7 @@ PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf, void *score = NULL; #endif - if (worker->s && (worker->s->status & PROXY_WORKER_INITIALIZED)) { + if (worker->s && PROXY_WORKER_IS_INITIALIZED(worker)) { /* The worker share is already initialized */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: worker %s already initialized", @@ -1639,7 +1639,7 @@ PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf, * recheck to see if we've already been here. Possible * if proxy is using scoreboard to hold shared stats */ - if (worker->s->status & PROXY_WORKER_INITIALIZED) { + if (PROXY_WORKER_IS_INITIALIZED(worker)) { /* The worker share is already initialized */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: worker %s already initialized", @@ -1667,7 +1667,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser int mpm_threads; #endif - if (worker->status & PROXY_WORKER_INITIALIZED) { + if (PROXY_WORKER_IS_INITIALIZED(worker)) { /* The worker is already initialized */ return APR_SUCCESS; }