-*- 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 <apache-bugzilla michael-kaufmann.ch>,
Yann Ylavic]
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
* 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" */
#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
#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;
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 */
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
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.
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) {
}
#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
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 */
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
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
}
worker->s->status |= (worker->status | PROXY_WORKER_INITIALIZED);
-
}
PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, server_rec *s)