X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=modules%2Fproxy%2Fmod_proxy_balancer.c;h=ffc2ef60a73eab6ff5b167586dfe5a11fb5a6e04;hb=7cc83fe9abdabc41b3d389280f2455fc9ce7ae25;hp=e7566051c79502854b587843cd58cf0d3db4308a;hpb=31c4a9e21ebf55a7252a6e9363e671264e281425;p=apache diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index e7566051c7..ffc2ef60a7 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -20,7 +20,7 @@ #include "scoreboard.h" #include "ap_mpm.h" #include "apr_version.h" -#include "apr_hooks.h" +#include "ap_hooks.h" #include "apr_date.h" static const char *balancer_mutex_type = "proxy-balancer-shm"; @@ -28,6 +28,11 @@ ap_slotmem_provider_t *storage = NULL; module AP_MODULE_DECLARE_DATA proxy_balancer_module; +static APR_OPTIONAL_FN_TYPE(set_worker_hc_param) *set_worker_hc_param_f = NULL; + +static int (*ap_proxy_retry_worker_fn)(const char *proxy_function, + proxy_worker *worker, server_rec *s) = NULL; + /* * Register our mutex type before the config is read so we * can adjust the mutex settings using the Mutex directive. @@ -43,7 +48,7 @@ static int balancer_pre_config(apr_pool_t *pconf, apr_pool_t *plog, if (rv != APR_SUCCESS) { return rv; } - + set_worker_hc_param_f = APR_RETRIEVE_OPTIONAL_FN(set_worker_hc_param); return OK; } @@ -60,22 +65,21 @@ static int proxy_balancer_canon(request_rec *r, char *url) apr_port_t port = 0; /* TODO: offset of BALANCER_PREFIX ?? */ - if (strncasecmp(url, "balancer:", 9) == 0) { + if (ap_casecmpstrn(url, "balancer:", 9) == 0) { url += 9; } else { return DECLINED; } - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, r->server, - "proxy: BALANCER: canonicalising URL %s", url); + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "canonicalising URL %s", url); /* do syntatic check. * We break the URL into host, port, path, search */ err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); if (err) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01157) "error parsing URL %s: %s", url, err); return HTTP_BAD_REQUEST; @@ -96,7 +100,7 @@ static int proxy_balancer_canon(request_rec *r, char *url) if (path == NULL) return HTTP_BAD_REQUEST; - r->filename = apr_pstrcat(r->pool, "proxy:", BALANCER_PREFIX, host, + r->filename = apr_pstrcat(r->pool, "proxy:" BALANCER_PREFIX, host, "/", path, (search) ? "?" : "", (search) ? search : "", NULL); r->path_info = apr_pstrcat(r->pool, "/", path, NULL); @@ -104,7 +108,7 @@ static int proxy_balancer_canon(request_rec *r, char *url) return OK; } -static void init_balancer_members(proxy_server_conf *conf, server_rec *s, +static void init_balancer_members(apr_pool_t *p, server_rec *s, proxy_balancer *balancer) { int i; @@ -115,11 +119,12 @@ static void init_balancer_members(proxy_server_conf *conf, server_rec *s, for (i = 0; i < balancer->workers->nelts; i++) { int worker_is_initialized; proxy_worker *worker = *workers; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Looking at %s -> %s initialized?", balancer->name, worker->s->name); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01158) + "Looking at %s -> %s initialized?", balancer->s->name, + ap_proxy_worker_name(p, worker)); worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(worker); if (!worker_is_initialized) { - ap_proxy_initialize_worker(worker, s, conf->pool); + ap_proxy_initialize_worker(worker, s, p); } ++workers; } @@ -127,9 +132,9 @@ static void init_balancer_members(proxy_server_conf *conf, server_rec *s, /* Set default number of attempts to the number of * workers. */ - if (!balancer->max_attempts_set && balancer->workers->nelts > 1) { - balancer->max_attempts = balancer->workers->nelts - 1; - balancer->max_attempts_set = 1; + if (!balancer->s->max_attempts_set && balancer->workers->nelts > 1) { + balancer->s->max_attempts = balancer->workers->nelts - 1; + balancer->s->max_attempts_set = 1; } } @@ -149,7 +154,7 @@ static char *get_path_param(apr_pool_t *pool, char *url, path += strlen(name); if (*path == '=') { /* - * Session path was found, get it's value + * Session path was found, get its value */ ++path; if (*path) { @@ -180,7 +185,7 @@ static char *get_cookie_param(request_rec *r, const char *name) ++start_cookie; if (*start_cookie++ == '=' && *start_cookie) { /* - * Session cookie was found, get it's value + * Session cookie was found, get its value */ char *end_cookie, *cookie; cookie = apr_pstrdup(r->pool, start_cookie); @@ -215,7 +220,7 @@ static proxy_worker *find_route_worker(proxy_balancer *balancer, 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)) { + if (PROXY_WORKER_IS_USABLE(worker)) { return worker; } else { /* @@ -225,7 +230,7 @@ static proxy_worker *find_route_worker(proxy_balancer *balancer, * The worker might still be unusable, but we try * anyway. */ - ap_proxy_retry_worker("BALANCER", worker, r->server); + ap_proxy_retry_worker_fn("BALANCER", worker, r->server); if (PROXY_WORKER_IS_USABLE(worker)) { return worker; } else { @@ -249,7 +254,7 @@ static proxy_worker *find_route_worker(proxy_balancer *balancer, * The worker might still be unusable, but we try * anyway. */ - ap_proxy_retry_worker("BALANCER", rworker, r->server); + ap_proxy_retry_worker_fn("BALANCER", rworker, r->server); } if (rworker && PROXY_WORKER_IS_USABLE(rworker)) return rworker; @@ -271,34 +276,34 @@ static proxy_worker *find_session_route(proxy_balancer *balancer, { proxy_worker *worker = NULL; - if (!balancer->sticky) + if (!*balancer->s->sticky) return NULL; /* Try to find the sticky route inside url */ - *route = get_path_param(r->pool, *url, balancer->sticky_path, balancer->scolonsep); + *route = get_path_param(r->pool, *url, balancer->s->sticky_path, balancer->s->scolonsep); if (*route) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER: Found value %s for " - "stickysession %s", *route, balancer->sticky_path); - *sticky_used = balancer->sticky_path; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01159) + "Found value %s for stickysession %s", + *route, balancer->s->sticky_path); + *sticky_used = balancer->s->sticky_path; } else { - *route = get_cookie_param(r, balancer->sticky); + *route = get_cookie_param(r, balancer->s->sticky); if (*route) { - *sticky_used = balancer->sticky; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER: Found value %s for " - "stickysession %s", *route, balancer->sticky); + *sticky_used = balancer->s->sticky; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01160) + "Found value %s for stickysession %s", + *route, balancer->s->sticky); } } /* - * If we found a value for sticksession, find the first '.' within. - * Everything after '.' (if present) is our route. + * If we found a value for stickysession, find the first '.' (or whatever + * sticky_separator is set to) within. Everything after '.' (if present) + * is our route. */ - if ((*route) && ((*route = strchr(*route, '.')) != NULL )) + if ((*route) && (balancer->s->sticky_separator != 0) && ((*route = strchr(*route, balancer->s->sticky_separator)) != NULL )) (*route)++; if ((*route) && (**route)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER: Found route %s", *route); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01161) "Found route %s", *route); /* We have a route in path or in cookie * Find the worker that has this route defined. */ @@ -309,9 +314,9 @@ static proxy_worker *find_session_route(proxy_balancer *balancer, * the route supplied by the client. */ apr_table_setn(r->subprocess_env, "BALANCER_ROUTE_CHANGED", "1"); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER: Route changed from %s to %s", - *route, worker->s->route); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01162) + "Route changed from %s to %s", + *route, worker->s->route); } return worker; } @@ -325,9 +330,10 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, proxy_worker *candidate = NULL; apr_status_t rv; - if ((rv = PROXY_GLOBAL_LOCK(balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Lock failed for find_best_worker()", balancer->name); + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01163) + "%s: Lock failed for find_best_worker()", + balancer->s->name); return NULL; } @@ -336,14 +342,10 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, if (candidate) candidate->s->elected++; -/* - PROXY_GLOBAL_UNLOCK(conf); - return NULL; -*/ - - if ((rv = PROXY_GLOBAL_UNLOCK(balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Unlock failed for find_best_worker()", balancer->name); + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01164) + "%s: Unlock failed for find_best_worker()", + balancer->s->name); } if (candidate == NULL) { @@ -354,18 +356,18 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, * By default the timeout is not set, and the server * returns SERVER_BUSY. */ - if (balancer->timeout) { + if (balancer->s->timeout) { /* XXX: This can perhaps be build using some * smarter mechanism, like tread_cond. * But since the statuses can came from * different childs, use the provided algo. */ - apr_interval_time_t timeout = balancer->timeout; + apr_interval_time_t timeout = balancer->s->timeout; apr_interval_time_t step, tval = 0; /* Set the timeout to 0 so that we don't * end in infinite loop */ - balancer->timeout = 0; + balancer->s->timeout = 0; step = timeout / 100; while (tval < timeout) { apr_sleep(step); @@ -375,7 +377,7 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, tval += step; } /* restore the timeout */ - balancer->timeout = timeout; + balancer->s->timeout = timeout; } } @@ -418,27 +420,38 @@ static void force_recovery(proxy_balancer *balancer, server_rec *s) } else { /* Try if we can recover */ - ap_proxy_retry_worker("BALANCER", *worker, s); + ap_proxy_retry_worker_fn("BALANCER", *worker, s); if (!((*worker)->s->status & PROXY_WORKER_IN_ERROR)) { ok = 1; break; } } } - if (!ok) { + if (!ok && balancer->s->forcerecovery) { /* If all workers are in error state force the recovery. */ worker = (proxy_worker **)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++, worker++) { ++(*worker)->s->retries; (*worker)->s->status &= ~PROXY_WORKER_IN_ERROR; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "proxy: BALANCER: (%s). Forcing recovery for worker (%s)", - balancer->name, (*worker)->s->hostname); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01165) + "%s: Forcing recovery for worker (%s)", + balancer->s->name, (*worker)->s->hostname); } } } +static apr_status_t decrement_busy_count(void *worker_) +{ + proxy_worker *worker = worker_; + + if (worker->s->busy) { + worker->s->busy--; + } + + return APR_SUCCESS; +} + static int proxy_balancer_pre_request(proxy_worker **worker, proxy_balancer **balancer, request_rec *r, @@ -457,16 +470,15 @@ static int proxy_balancer_pre_request(proxy_worker **worker, * for balancer, because this is failover attempt. */ if (!*balancer && - !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url))) + !(*balancer = ap_proxy_get_balancer(r->pool, conf, *url, 1))) return DECLINED; /* Step 2: Lock the LoadBalancer * XXX: perhaps we need the process lock here */ - if ((rv = PROXY_GLOBAL_LOCK(*balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Lock failed for pre_request", - (*balancer)->name); + if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01166) + "%s: Lock failed for pre_request", (*balancer)->s->name); return DECLINED; } @@ -475,7 +487,7 @@ static int proxy_balancer_pre_request(proxy_worker **worker, /* Step 3.5: Update member list for the balancer */ /* TODO: Implement as provider! */ - /* proxy_update_members(balancer, r, conf); */ + ap_proxy_sync_balancer(*balancer, r->server, conf); /* Step 4: find the session route */ runtime = find_session_route(*balancer, r, &route, &sticky, url); @@ -509,7 +521,7 @@ static int proxy_balancer_pre_request(proxy_worker **worker, *worker = runtime; } - else if (route && (*balancer)->sticky_force) { + else if (route && (*balancer)->s->sticky_force) { int i, member_of = 0; proxy_worker **workers; /* @@ -526,39 +538,39 @@ static int proxy_balancer_pre_request(proxy_worker **worker, workers++; } if (member_of) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "proxy: BALANCER: (%s). All workers are in error state for route (%s)", - (*balancer)->name, route); - if ((rv = PROXY_GLOBAL_UNLOCK(*balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Unlock failed for pre_request", - (*balancer)->name); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01167) + "%s: All workers are in error state for route (%s)", + (*balancer)->s->name, route); + if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01168) + "%s: Unlock failed for pre_request", + (*balancer)->s->name); } return HTTP_SERVICE_UNAVAILABLE; } } - if ((rv = PROXY_GLOBAL_UNLOCK(*balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Unlock failed for pre_request", - (*balancer)->name); + if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01169) + "%s: Unlock failed for pre_request", + (*balancer)->s->name); } if (!*worker) { runtime = find_best_worker(*balancer, r); if (!runtime) { if ((*balancer)->workers->nelts) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "proxy: BALANCER: (%s). All workers are in error state", - (*balancer)->name); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01170) + "%s: All workers are in error state", + (*balancer)->s->name); } else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "proxy: BALANCER: (%s). No workers in balancer", - (*balancer)->name); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01171) + "%s: No workers in balancer", + (*balancer)->s->name); } return HTTP_SERVICE_UNAVAILABLE; } - if ((*balancer)->sticky && runtime) { + if (*(*balancer)->s->sticky && runtime) { /* * This balancer has sticky sessions and the client either has not * supplied any routing information or all workers for this route @@ -573,10 +585,12 @@ static int proxy_balancer_pre_request(proxy_worker **worker, } (*worker)->s->busy++; + apr_pool_cleanup_register(r->pool, *worker, decrement_busy_count, + apr_pool_cleanup_null); /* Add balancer/worker info to env. */ apr_table_setn(r->subprocess_env, - "BALANCER_NAME", (*balancer)->name); + "BALANCER_NAME", (*balancer)->s->name); apr_table_setn(r->subprocess_env, "BALANCER_WORKER_NAME", (*worker)->s->name); apr_table_setn(r->subprocess_env, @@ -599,9 +613,9 @@ static int proxy_balancer_pre_request(proxy_worker **worker, apr_table_setn(r->subprocess_env, "BALANCER_SESSION_ROUTE", route); } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy: BALANCER (%s) worker (%s) rewritten to %s", - (*balancer)->name, (*worker)->s->name, *url); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01172) + "%s: worker (%s) rewritten to %s", + (*balancer)->s->name, (*worker)->s->name, *url); return access_status; } @@ -614,21 +628,25 @@ static int proxy_balancer_post_request(proxy_worker *worker, apr_status_t rv; - if ((rv = PROXY_GLOBAL_LOCK(balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Lock failed for post_request", - balancer->name); + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01173) + "%s: Lock failed for post_request", + balancer->s->name); return HTTP_INTERNAL_SERVER_ERROR; } - if (!apr_is_empty_array(balancer->errstatuses)) { + if (!apr_is_empty_array(balancer->errstatuses) + && !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) { int i; for (i = 0; i < balancer->errstatuses->nelts; i++) { int val = ((int *)balancer->errstatuses->elts)[i]; if (r->status == val) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Forcing recovery for worker (%s), failonstatus %d", - balancer->name, worker->s->name, val); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01174) + "%s: Forcing worker (%s) into error state " + "due to status code %d matching 'failonstatus' " + "balancer parameter", + balancer->s->name, ap_proxy_worker_name(r->pool, worker), + val); worker->s->status |= PROXY_WORKER_IN_ERROR; worker->s->error_time = apr_time_now(); break; @@ -636,19 +654,26 @@ static int proxy_balancer_post_request(proxy_worker *worker, } } - if ((rv = PROXY_GLOBAL_UNLOCK(balancer)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, - "proxy: BALANCER: (%s). Unlock failed for post_request", - balancer->name); + if (balancer->failontimeout + && !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS) + && (apr_table_get(r->notes, "proxy_timedout")) != NULL) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02460) + "%s: Forcing worker (%s) into error state " + "due to timeout and 'failontimeout' parameter being set", + balancer->s->name, ap_proxy_worker_name(r->pool, worker)); + worker->s->status |= PROXY_WORKER_IN_ERROR; + worker->s->error_time = apr_time_now(); + } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "proxy_balancer_post_request for (%s)", balancer->name); - if (worker && worker->s->busy) - worker->s->busy--; + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01175) + "%s: Unlock failed for post_request", balancer->s->name); + } + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01176) + "proxy_balancer_post_request for (%s)", balancer->s->name); return OK; - } static void recalc_factors(proxy_balancer *balancer) @@ -659,7 +684,7 @@ static void recalc_factors(proxy_balancer *balancer) /* Recalculate lbfactors */ workers = (proxy_worker **)balancer->workers->elts; - /* Special case if there is only one worker it's + /* Special case if there is only one worker its * load factor will always be 1 */ if (balancer->workers->nelts == 1) { @@ -682,9 +707,9 @@ static apr_status_t lock_remove(void *data) balancer = (proxy_balancer *)conf->balancers->elts; for (i = 0; i < conf->balancers->nelts; i++, balancer++) { - if (balancer->mutex) { - apr_global_mutex_destroy(balancer->mutex); - balancer->mutex = NULL; + if (balancer->gmutex) { + apr_global_mutex_destroy(balancer->gmutex); + balancer->gmutex = NULL; } } return(0); @@ -694,95 +719,201 @@ static apr_status_t lock_remove(void *data) static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { - void *data; - void *sconf = s->module_config; - proxy_server_conf *conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); - const char *userdata_key = "mod_proxy_balancer_init"; + apr_status_t rv; + proxy_server_conf *conf; + ap_slotmem_instance_t *new = NULL; + apr_time_t tstamp; - /* balancer_post_config() will be called twice during startup. So, only + /* balancer_post_config() will be called twice during startup. So, don't * set up the static data the 1st time through. */ - apr_pool_userdata_get(&data, userdata_key, s->process->pool); - if (!data) { - apr_pool_userdata_set((const void *)1, userdata_key, - apr_pool_cleanup_null, s->process->pool); + if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) { return OK; } + if (!ap_proxy_retry_worker_fn) { + ap_proxy_retry_worker_fn = + APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker); + if (!ap_proxy_retry_worker_fn) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02230) + "mod_proxy must be loaded for mod_proxy_balancer"); + return !OK; + } + } + /* - * Get worker slotmem setup + * Get slotmem setups */ - storage = ap_lookup_provider(AP_SLOTMEM_PROVIDER_GROUP, "shared", "0"); + storage = ap_lookup_provider(AP_SLOTMEM_PROVIDER_GROUP, "shm", + AP_SLOTMEM_PROVIDER_VERSION); if (!storage) { - ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_EMERG, 0, s, - "ap_lookup_provider %s failed", AP_SLOTMEM_PROVIDER_GROUP); + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01177) + "Failed to lookup provider 'shm' for '%s': is " + "mod_slotmem_shm loaded??", + AP_SLOTMEM_PROVIDER_GROUP); return !OK; } + + tstamp = apr_time_now(); /* * Go thru each Vhost and create the shared mem slotmem for * each balancer's workers */ while (s) { int i,j; - apr_status_t rv; + char *id; proxy_balancer *balancer; - sconf = s->module_config; + ap_slotmem_type_t type; + void *sconf = s->module_config; conf = (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module); + /* + * During create_proxy_config() we created a dummy id. Now that + * we have identifying info, we can create the real id + */ + id = apr_psprintf(pconf, "%s.%s.%d.%s.%s.%u.%s", + (s->server_scheme ? s->server_scheme : "????"), + (s->server_hostname ? s->server_hostname : "???"), + (int)s->port, + (s->server_admin ? s->server_admin : "??"), + (s->defn_name ? s->defn_name : "?"), + s->defn_line_number, + (s->error_fname ? s->error_fname : DEFAULT_ERRORLOG)); + conf->id = apr_psprintf(pconf, "p%x", + ap_proxy_hashfunc(id, PROXY_HASHFUNC_DEFAULT)); + if (conf->bslot) { + /* Shared memory already created for this proxy_server_conf. + */ + s = s->next; + continue; + } + if (conf->bal_persist) { + type = AP_SLOTMEM_TYPE_PERSIST; + } else { + type = 0; + } + if (conf->balancers->nelts) { + conf->max_balancers = conf->balancers->nelts + conf->bgrowth; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01178) "Doing balancers create: %d, %d (%d)", + (int)ALIGNED_PROXY_BALANCER_SHARED_SIZE, + (int)conf->balancers->nelts, conf->max_balancers); + + rv = storage->create(&new, conf->id, + ALIGNED_PROXY_BALANCER_SHARED_SIZE, + conf->max_balancers, type, pconf); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01179) "balancer slotmem_create failed"); + return !OK; + } + conf->bslot = new; + } + conf->storage = storage; /* Initialize shared scoreboard data */ balancer = (proxy_balancer *)conf->balancers->elts; for (i = 0; i < conf->balancers->nelts; i++, balancer++) { proxy_worker **workers; proxy_worker *worker; - ap_slotmem_instance_t *new = NULL; + proxy_balancer_shared *bshm; + const char *sname; + unsigned int index; + + /* now that we have the right id, we need to redo the sname field */ + ap_pstr2_alnum(pconf, balancer->s->name + sizeof(BALANCER_PREFIX) - 1, + &sname); + sname = apr_pstrcat(pconf, conf->id, "_", sname, NULL); + PROXY_STRNCPY(balancer->s->sname, sname); /* We know this will succeed */ balancer->max_workers = balancer->workers->nelts + balancer->growth; - balancer->sname = ap_md5(pconf, (const unsigned char *)balancer->name); /* Create global mutex */ - rv = ap_global_mutex_create(&(balancer->mutex), NULL, balancer_mutex_type, - balancer->sname, s, pconf, 0); - if (rv != APR_SUCCESS || !balancer->mutex) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, + rv = ap_global_mutex_create(&(balancer->gmutex), NULL, balancer_mutex_type, + balancer->s->sname, s, pconf, 0); + if (rv != APR_SUCCESS || !balancer->gmutex) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01180) "mutex creation of %s : %s failed", balancer_mutex_type, - balancer->sname); + balancer->s->sname); return HTTP_INTERNAL_SERVER_ERROR; } apr_pool_cleanup_register(pconf, (void *)s, lock_remove, apr_pool_cleanup_null); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Doing create: %s (%s), %d, %d", - balancer->name, balancer->sname, - (int)sizeof(proxy_worker_shared), - (int)balancer->max_workers); + /* setup shm for balancers */ + bshm = ap_proxy_find_balancershm(storage, conf->bslot, balancer, &index); + if (bshm) { + if ((rv = storage->fgrab(conf->bslot, index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02408) "balancer slotmem_fgrab failed"); + return !OK; + } + } + else { + if ((rv = storage->grab(conf->bslot, &index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01181) "balancer slotmem_grab failed"); + return !OK; + } + if ((rv = storage->dptr(conf->bslot, index, (void *)&bshm)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01182) "balancer slotmem_dptr failed"); + return !OK; + } + } + if ((rv = ap_proxy_share_balancer(balancer, bshm, index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01183) "Cannot share balancer"); + return !OK; + } + + /* create slotmem slots for workers */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01184) "Doing workers create: %s (%s), %d, %d [%u]", + balancer->s->name, balancer->s->sname, + (int)ALIGNED_PROXY_WORKER_SHARED_SIZE, + (int)balancer->max_workers, i); - rv = storage->create(&new, balancer->sname, sizeof(proxy_worker_shared), - balancer->max_workers, AP_SLOTMEM_TYPE_PREGRAB, pconf); + rv = storage->create(&new, balancer->s->sname, + ALIGNED_PROXY_WORKER_SHARED_SIZE, + balancer->max_workers, type, pconf); if (rv != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "slotmem_create failed"); + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01185) "worker slotmem_create failed"); return !OK; } - balancer->slot = new; + balancer->wslot = new; + balancer->storage = storage; + /* sync all timestamps */ + balancer->wupdated = balancer->s->wupdated = tstamp; + + /* now go thru each worker */ workers = (proxy_worker **)balancer->workers->elts; for (j = 0; j < balancer->workers->nelts; j++, workers++) { proxy_worker_shared *shm; - unsigned int index; worker = *workers; - if ((rv = storage->grab(balancer->slot, &index)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "slotmem_grab failed"); - return !OK; + shm = ap_proxy_find_workershm(storage, balancer->wslot, worker, &index); + if (shm) { + if ((rv = storage->fgrab(balancer->wslot, index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02409) "worker slotmem_fgrab failed"); + return !OK; + } } - if ((rv = storage->dptr(balancer->slot, index, (void *)&shm)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "slotmem_dptr failed"); - return !OK; + else { + if ((rv = storage->grab(balancer->wslot, &index)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01186) "worker slotmem_grab failed"); + return !OK; + + } + if ((rv = storage->dptr(balancer->wslot, index, (void *)&shm)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01187) "worker slotmem_dptr failed"); + return !OK; + } } if ((rv = ap_proxy_share_worker(worker, shm, index)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, "Cannot share worker"); + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(01188) "Cannot share worker"); return !OK; } + worker->s->updated = tstamp; + } + if (conf->bal_persist) { + /* We could have just read-in a persisted config. Force a sync. */ + balancer->wupdated--; + ap_proxy_sync_balancer(balancer, s, conf); } } s = s->next; @@ -791,7 +922,64 @@ static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog, return OK; } +static void create_radio(const char *name, unsigned int flag, request_rec *r) +{ + ap_rvputs(r, "