From: Yann Ylavic Date: Thu, 21 May 2015 16:24:30 +0000 (+0000) Subject: 2.2.x only. X-Git-Tag: 2.2.30~85 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6b04ab92dc1445026ac8497e5cfdfb2a634d1e87;p=thirdparty%2Fapache%2Fhttpd.git 2.2.x only. mod_proxy: Reuse proxy/balancer workers' parameters and scores across graceful restarts, even if new workers are added, old ones removed, or the order changes. Proposed by: jkaluza Reviewed by: ylavic, jkaluza, wrowe Backported by: ylavic git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@1680920 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 055722ef58a..f594dc9b4fd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ -*- coding: utf-8 -*- Changes with Apache 2.2.30 + *) mod_proxy: Reuse proxy/balancer workers' parameters and scores across + graceful restarts, even if new workers are added, old ones removed, or + the order changes. [Jan Kaluza, Yann Ylavic] + *) mod_ssl: 'SSLProtocol ALL' was being ignored in virtual host context. PR 57100. [Michael Kaufmann , Yann Ylavic] diff --git a/STATUS b/STATUS index b9c3da5cbb3..a0bfe65d168 100644 --- a/STATUS +++ b/STATUS @@ -101,13 +101,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - * mod_proxy: Reuse proxy workers' parameters and scores across graceful - restarts, even if new workers added, old ones removed, or the order - changes. PR 44736. [Jan Kaluza] - 2.2.x patch: http://people.apache.org/~ylavic/httpd-2.2.x-graceful_share_full-v7.patch - ylavic: trunk/2.4.x not concerned, 2.2.x only. - +1: ylavic, jkaluza, wrowe - * mod_ssl: Propose a more modern Cipher and Protocol list, honor server cipher priority and add explanations relative to RFC 7525 guidance. http://svn.apache.org/r1679428 diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 975e951d9a9..6956adbd027 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -155,6 +155,7 @@ * 20051115.35 (2.2.28) Add SSL reusable SNI to mod_proxy.h's proxy_conn_rec * 20051115.36 (2.2.28) Add r->trailers_{in,out} * 20051115.37 (2.2.30) Add ap_get_server_name_for_url() + * 20051115.38 (2.2.30) Add ap_proxy_set_scoreboard_lb() in mod_proxy.h */ #define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */ @@ -162,7 +163,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20051115 #endif -#define MODULE_MAGIC_NUMBER_MINOR 37 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 38 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 2d4998d9432..78e20bdd35b 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -293,6 +293,13 @@ PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR ) #define PROXY_WORKER_DEFAULT_RETRY 60 #define PROXY_WORKER_MAX_ROUTE_SIZ 63 +/* Scoreboard */ +#if MODULE_MAGIC_NUMBER_MAJOR > 20020903 +#define PROXY_HAS_SCOREBOARD 1 +#else +#define PROXY_HAS_SCOREBOARD 0 +#endif + /* Runtime worker status informations. Shared in scoreboard */ typedef struct { int status; @@ -308,6 +315,9 @@ typedef struct { void *context; /* general purpose storage */ apr_size_t busy; /* busyness factor */ int lbset; /* load balancer cluster set */ +#if PROXY_HAS_SCOREBOARD + unsigned char digest[APR_MD5_DIGESTSIZE]; /* hash of the worker->name */ +#endif } proxy_worker_stat; /* Worker configuration */ @@ -742,13 +752,6 @@ PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, PROXY_DECLARE(void) ap_proxy_backend_broke(request_rec *r, apr_bucket_brigade *brigade); -/* Scoreboard */ -#if MODULE_MAGIC_NUMBER_MAJOR > 20020903 -#define PROXY_HAS_SCOREBOARD 1 -#else -#define PROXY_HAS_SCOREBOARD 0 -#endif - /** * Transform buckets from one bucket allocator to another one by creating a * transient bucket for each data bucket and let it use the data read from @@ -772,6 +775,12 @@ PROXY_DECLARE(apr_status_t) ap_proxy_buckets_lifetime_transform(request_rec *r, apr_bucket_brigade *from, apr_bucket_brigade *to); +#if PROXY_HAS_SCOREBOARD +void *ap_proxy_set_scoreboard_lb(proxy_worker *worker, + proxy_balancer *balancer, + server_rec *server); +#endif + #define PROXY_LBMETHOD "proxylbmethod" /* The number of dynamic workers that can be added when reconfiguring. diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index f5792ec0ffa..ef7ebbc808b 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -83,25 +83,23 @@ static int init_balancer_members(proxy_server_conf *conf, server_rec *s, int i; proxy_worker *workers; int worker_is_initialized; - proxy_worker_stat *slot; workers = (proxy_worker *)balancer->workers->elts; for (i = 0; i < balancer->workers->nelts; i++) { worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(workers); +#if PROXY_HAS_SCOREBOARD + /* + * If the worker is not initialized but has a scoreboard + * slot, check whether it was already initialized in a + * previous generation to avoid resetting the shared lb + * parameters below. + */ if (!worker_is_initialized) { - /* - * If the worker is not initialized check whether its scoreboard - * slot is already initialized. - */ - slot = (proxy_worker_stat *) ap_get_scoreboard_lb(workers->id); - if (slot) { - worker_is_initialized = slot->status & PROXY_WORKER_INITIALIZED; - } - else { - worker_is_initialized = 0; - } + ap_proxy_set_scoreboard_lb(workers, balancer, s); + worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(workers); } +#endif ap_proxy_initialize_worker_share(conf, workers, s); ap_proxy_initialize_worker(workers, s); if (!worker_is_initialized) { diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 454004a5fb4..fccf13d235f 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1794,6 +1794,76 @@ static apr_status_t connection_destructor(void *resource, void *params, } #endif +#if PROXY_HAS_SCOREBOARD +void *ap_proxy_set_scoreboard_lb(proxy_worker *worker, + proxy_balancer *balancer, + server_rec *server) +{ + if (ap_scoreboard_image && !worker->s) { + int i = 0; + proxy_worker_stat *free_slot = NULL; + proxy_worker_stat *s; + unsigned char digest[APR_MD5_DIGESTSIZE]; + apr_md5_ctx_t ctx; + + /* The scoreboard entry must be unique per server and balancer, + * so when asked to (given by the caller) use their respective + * unique identifiers for the hash. + */ + apr_md5_init(&ctx); + apr_md5_update(&ctx, (unsigned char *)worker->name, + strlen(worker->name)); + if (balancer) { + apr_md5_update(&ctx, (unsigned char *)balancer->name, + strlen(balancer->name)); + } + if (server) { + server_addr_rec *addr; + /* Assumes the unique identifier of a vhost is its address(es) + * plus the ServerName:Port. Should two or more vhosts have this + * same identifier, the first one would always be elected to + * handle the requests, so this shouldn't be an issue... + */ + for (addr = server->addrs; addr; addr = addr->next) { + char host_ip[64]; /* for any IPv[46] string */ + apr_sockaddr_ip_getbuf(host_ip, sizeof host_ip, + addr->host_addr); + apr_md5_update(&ctx, (unsigned char *)host_ip, + strlen(host_ip)); + apr_md5_update(&ctx, (unsigned char *)&addr->host_port, + sizeof(addr->host_port)); + } + apr_md5_update(&ctx, (unsigned char *)server->server_hostname, + strlen(server->server_hostname)); + apr_md5_update(&ctx, (unsigned char *)&server->port, + sizeof(server->port)); + } + apr_md5_final(digest, &ctx); + + /* Try to find out the right shared memory according to the hash */ + while ((s = (proxy_worker_stat *)ap_get_scoreboard_lb(i++)) != NULL) { + if ((s->status & PROXY_WORKER_INITIALIZED) == 0) { + if (free_slot == NULL) { + free_slot = s; + } + continue; + } + if (memcmp(s->digest, digest, APR_MD5_DIGESTSIZE) == 0) { + worker->s = s; + return s; + } + } + + /* We failed to find out shared memory, so just use a free slot (if any) */ + if (free_slot) { + memcpy(free_slot->digest, digest, APR_MD5_DIGESTSIZE); + worker->s = free_slot; + } + } + return worker->s; +} +#endif + /* * ap_proxy_initialize_worker_share() concerns itself * with initializing those parts of worker which @@ -1803,11 +1873,7 @@ PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf, proxy_worker *worker, server_rec *s) { -#if PROXY_HAS_SCOREBOARD - lb_score *score = NULL; -#else void *score = NULL; -#endif if (PROXY_WORKER_IS_INITIALIZED(worker)) { /* The worker share is already initialized */ @@ -1817,18 +1883,18 @@ PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf, return; } #if PROXY_HAS_SCOREBOARD - /* Get scoreboard slot */ + /* Get scoreboard slot */ if (ap_scoreboard_image) { - score = ap_get_scoreboard_lb(worker->id); - if (!score) { + if (!ap_proxy_set_scoreboard_lb(worker, NULL, s)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "proxy: ap_get_scoreboard_lb(%d) failed in child %" APR_PID_T_FMT " for worker %s", + "proxy: ap_proxy_set_scoreboard_lb(%d) failed in child %" APR_PID_T_FMT " for worker %s", worker->id, getpid(), worker->name); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: grabbed scoreboard slot %d in child %" APR_PID_T_FMT " for worker %s", worker->id, getpid(), worker->name); + score = worker->s; } } #endif @@ -1837,8 +1903,8 @@ PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "proxy: initialized plain memory in child %" APR_PID_T_FMT " for worker %s", getpid(), worker->name); + worker->s = (proxy_worker_stat *)score; } - worker->s = (proxy_worker_stat *)score; /* * recheck to see if we've already been here. Possible * if proxy is using scoreboard to hold shared stats @@ -1864,7 +1930,6 @@ PROXY_DECLARE(void) ap_proxy_initialize_worker_share(proxy_server_conf *conf, } worker->s->status |= (worker->status | PROXY_WORKER_INITIALIZED); - } PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s)