Author: jfrederic.clere(a)jboss.com
Date: 2008-03-29 04:41:21 -0400 (Sat, 29 Mar 2008)
New Revision: 1485
Modified:
sandbox/httpd/src/native/mod_proxy_cluster/mod_proxy_cluster.c
Log:
Add assynchronous ping/pong (AJP only).
Modified: sandbox/httpd/src/native/mod_proxy_cluster/mod_proxy_cluster.c
===================================================================
--- sandbox/httpd/src/native/mod_proxy_cluster/mod_proxy_cluster.c 2008-03-29 08:30:00 UTC
(rev 1484)
+++ sandbox/httpd/src/native/mod_proxy_cluster/mod_proxy_cluster.c 2008-03-29 08:41:21 UTC
(rev 1485)
@@ -130,7 +130,11 @@
if (ids[j]) {
/* read the node and create the worker */
nodeinfo_t *node;
- node_storage->read_node(ids[j], &node);
+ if (node_storage->read_node(ids[j], &node) != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "create_workers_node can't read id %d",
ids[j]);
+ continue;
+ }
proxy_balancer *balancer = ap_proxy_get_balancer(r->pool, conf,
apr_pstrcat(r->pool, "balancer://", node->balancer,
NULL));
if (balancer) {
@@ -144,6 +148,81 @@
}
}
+/* reslist constructor */
+/* XXX: Should use the proxy_util one. */
+static apr_status_t connection_constructor(void **resource, void *params,
+ apr_pool_t *pool)
+{
+ apr_pool_t *ctx;
+ proxy_conn_rec *conn;
+ proxy_worker *worker = (proxy_worker *)params;
+
+ /*
+ * Create the subpool for each connection
+ * This keeps the memory consumption constant
+ * when disconnecting from backend.
+ */
+ apr_pool_create(&ctx, pool);
+ conn = apr_pcalloc(pool, sizeof(proxy_conn_rec));
+
+ conn->pool = ctx;
+ conn->worker = worker;
+#if APR_HAS_THREADS
+ conn->inreslist = 1;
+#endif
+ *resource = conn;
+
+ return APR_SUCCESS;
+}
+
+/* connection cleanup routine */
+/* XXX: Should use the proxy_util one. */
+static apr_status_t connection_cleanup(void *theconn)
+{
+ proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
+ proxy_worker *worker = conn->worker;
+
+ /*
+ * If the connection pool is NULL the worker
+ * cleanup has been run. Just return.
+ */
+ if (!worker->cp) {
+ return APR_SUCCESS;
+ }
+
+#if APR_HAS_THREADS
+ /* Sanity check: Did we already return the pooled connection? */
+ if (conn->inreslist) {
+ ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool,
+ "proxy: Pooled connection 0x%pp for worker %s has been"
+ " already returned to the connection pool.", conn,
+ worker->name);
+ return APR_SUCCESS;
+ }
+#endif
+
+ /* determine if the connection need to be closed */
+ if (conn->close_on_recycle || conn->close) {
+ apr_pool_t *p = conn->pool;
+ apr_pool_clear(conn->pool);
+ memset(conn, 0, sizeof(proxy_conn_rec));
+ conn->pool = p;
+ conn->worker = worker;
+ }
+#if APR_HAS_THREADS
+ if (worker->hmax && worker->cp->res) {
+ conn->inreslist = 1;
+ apr_reslist_release(worker->cp->res, (void *)conn);
+ }
+ else
+#endif
+ {
+ worker->cp->conn = conn;
+ }
+
+ /* Always return the SUCCESS */
+ return APR_SUCCESS;
+}
/* Retrieve the parameter with the given name
* Something like 'JSESSIONID=12345...N'
* XXX: Should use the mod_proxy_balancer ones.
@@ -204,6 +283,7 @@
}
return NULL;
}
+
/*
* Check that the request has a sessionid (even invalid)
*/
@@ -364,6 +444,160 @@
return mycandidate;
}
+/*
+ * Do a ping/pong to the node
+ */
+static apr_status_t proxy_cluster_try_pingpong(request_rec *r, proxy_worker *worker)
+{
+ apr_status_t rv;
+ proxy_conn_rec *conn;
+ /* get the proxy_conn_rec: from ap_proxy_acquire_connection */
+#if APR_HAS_THREADS
+ if (worker->hmax && worker->cp->res) {
+ rv = apr_reslist_acquire(worker->cp->res, (void **)&conn);
+ }
+ else
+#endif
+ {
+ /* create the new connection if the previous was destroyed */
+ if (!worker->cp->conn) {
+ connection_constructor((void **)&conn, worker, worker->cp->pool);
+ }
+ else {
+ conn = worker->cp->conn;
+ worker->cp->conn = NULL;
+ }
+ rv = APR_SUCCESS;
+ }
+
+ const char *scheme = "AJP";
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy_cluster_try_pingpong: failed acquiring
connection");
+ if (conn) {
+ conn->close = 1;
+ ap_proxy_release_connection(scheme, conn, r->server);
+ }
+ return rv;
+ }
+
+ conn->worker = worker;
+ conn->close = 0;
+#if APR_HAS_THREADS
+ conn->inreslist = 0;
+#endif
+
+ /* Replace ap_proxy_determine_connection XXX: Still not ok */
+ if (!conn->hostname) {
+ conn->hostname = apr_pstrdup(conn->pool, worker->hostname);
+ conn->port = worker->port;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy_cluster_try_pingpong: connection to %s : %d",
+ conn->hostname, conn->port);
+
+ if (conn->sock) {
+ apr_socket_close(conn->sock);
+ conn->sock = NULL;
+ }
+ if (conn->connection) {
+ apr_pool_cleanup_kill(conn->connection->pool, conn,
connection_cleanup);
+ conn->connection = NULL;
+ }
+ rv = apr_sockaddr_info_get(&(conn->addr),
+ conn->hostname, APR_UNSPEC,
+ conn->port, 0,
+ conn->pool);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy_cluster_try_pingpong: can't resolve %s",
+ conn->hostname);
+ ap_proxy_release_connection(scheme, conn, r->server);
+ return rv;
+ }
+ }
+
+ /* Connect to the backend */
+ rv = ap_proxy_connect_backend(scheme, conn, worker, r->server);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy_cluster_try_pingpong: can't connect to
backend");
+ ap_proxy_release_connection(scheme, conn, r->server);
+ return rv;
+ }
+
+ apr_interval_time_t timeout = worker->ping_timeout;
+ if (timeout <= 0)
+ timeout = apr_time_from_sec(10); /* 10 seconds */
+
+ rv = ajp_handle_cping_cpong(conn->sock, r, timeout);
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy_cluster_try_pingpong: cping_cpong failed");
+ }
+ ap_proxy_release_connection(scheme, conn, r->server);
+ return rv;
+}
+/*
+ * Check that we could connect to the node
+ * id : worker id
+ * load : load factor from the cluster manager.
+ */
+PROXY_DECLARE(int) proxy_cluster_isup(request_rec *r, int id, int load)
+{
+ void *sconf = r->server->module_config;
+ proxy_server_conf *conf = (proxy_server_conf *)
+ ap_get_module_config(sconf, &proxy_module);
+ int i;
+ apr_status_t rv;
+ proxy_worker *worker;
+
+ /* create the workers (that could be the first time) */
+ create_workers_node(r);
+
+ /* search for the worker */
+ worker = (proxy_worker *)conf->workers->elts;
+ for (i = 0; i < conf->workers->nelts; i++) {
+ if (worker->id == id)
+ break;
+ }
+ if (i == conf->workers->nelts) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy_cluster_isup: Can't find worker for %d", id);
+ return 500;
+ }
+
+ /* Try a ping/pong to check the node */
+ if (load > 0) {
+ /* Only try usuable nodes */
+ rv = proxy_cluster_try_pingpong(r, worker);
+ if (rv != APR_SUCCESS) {
+ worker->s->status |= PROXY_WORKER_IN_ERROR;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy_cluster_isup: pingpong failed");
+ return 500;
+ }
+ }
+ if (load == -1) {
+ worker->s->status |= PROXY_WORKER_IN_ERROR;
+ }
+ else if (load == 0) {
+ /*
+ * XXX: PROXY_WORKER_HOT_STANDBY Doesn't look supported
+ * mark worker in error for the moment
+ */
+ worker->s->status |= PROXY_WORKER_IN_ERROR;
+ worker->s->status |= PROXY_WORKER_HOT_STANDBY;
+ }
+ else {
+ worker->s->status &= ~PROXY_WORKER_IN_ERROR;
+ worker->s->status &= ~PROXY_WORKER_STOPPED;
+ worker->s->status &= ~PROXY_WORKER_DISABLED;
+ worker->s->status &= PROXY_WORKER_HOT_STANDBY;
+ worker->s->lbfactor = load;
+ }
+ return 0;
+}
+
static int proxy_cluster_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{