b5d34bc3082c1164ce20df48567d192e3e9f229fjim/* Licensed to the Apache Software Foundation (ASF) under one or more
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * contributor license agreements. See the NOTICE file distributed with
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * this work for additional information regarding copyright ownership.
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * The ASF licenses this file to You under the Apache License, Version 2.0
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * (the "License"); you may not use this file except in compliance with
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * the License. You may obtain a copy of the License at
b5d34bc3082c1164ce20df48567d192e3e9f229fjim *
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * http://www.apache.org/licenses/LICENSE-2.0
b5d34bc3082c1164ce20df48567d192e3e9f229fjim *
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * Unless required by applicable law or agreed to in writing, software
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * distributed under the License is distributed on an "AS IS" BASIS,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * See the License for the specific language governing permissions and
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * limitations under the License.
b5d34bc3082c1164ce20df48567d192e3e9f229fjim */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim#include "mod_proxy.h"
b5d34bc3082c1164ce20df48567d192e3e9f229fjim#include "scoreboard.h"
b5d34bc3082c1164ce20df48567d192e3e9f229fjim#include "ap_mpm.h"
b5d34bc3082c1164ce20df48567d192e3e9f229fjim#include "apr_version.h"
12b170a812f740fafc96da32a188a8b2761a3d5cjim#include "ap_hooks.h"
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere#include "ap_slotmem.h"
57a049796ba191c87b588cbde1323e8f65e3fea5jfclere#include "heartbeat.h"
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
a231b4cbdf1bd3d65dc13ead8d8a4f7e8b307314pquerna#ifndef LBM_HEARTBEAT_MAX_LASTSEEN
a231b4cbdf1bd3d65dc13ead8d8a4f7e8b307314pquerna/* If we haven't seen a heartbeat in the last N seconds, don't count this IP
a231b4cbdf1bd3d65dc13ead8d8a4f7e8b307314pquerna * as allive.
a231b4cbdf1bd3d65dc13ead8d8a4f7e8b307314pquerna */
a231b4cbdf1bd3d65dc13ead8d8a4f7e8b307314pquerna#define LBM_HEARTBEAT_MAX_LASTSEEN (10)
a231b4cbdf1bd3d65dc13ead8d8a4f7e8b307314pquerna#endif
a231b4cbdf1bd3d65dc13ead8d8a4f7e8b307314pquerna
b5d34bc3082c1164ce20df48567d192e3e9f229fjimmodule AP_MODULE_DECLARE_DATA lbmethod_heartbeat_module;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrinstatic int (*ap_proxy_retry_worker_fn)(const char *proxy_function,
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin proxy_worker *worker, server_rec *s) = NULL;
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin
94b9a8750697ea0bf67a2a828e8034e5fe103ccatrawickstatic const ap_slotmem_provider_t *storage = NULL;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclerestatic ap_slotmem_instance_t *hm_serversmem = NULL;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere/*
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere * configuration structure
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere * path: path of the file where the heartbeat information is stored.
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere */
b5d34bc3082c1164ce20df48567d192e3e9f229fjimtypedef struct lb_hb_ctx_t
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
b5d34bc3082c1164ce20df48567d192e3e9f229fjim const char *path;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim} lb_hb_ctx_t;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjimtypedef struct hb_server_t {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim const char *ip;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim int busy;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim int ready;
c87ed6a25f669f7137024ccde3771d95b9c37e07jfclere int port;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere int id;
4c25fdfa5f370d29e55aea846eb9fe6c1d51ede3wrowe apr_time_t seen;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim proxy_worker *worker;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim} hb_server_t;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
a515c3892232a3497bb58eeec5a1b9523571cf67jfcleretypedef struct ctx_servers {
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere apr_time_t now;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere apr_hash_t *servers;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere} ctx_servers_t;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere
b5d34bc3082c1164ce20df48567d192e3e9f229fjimstatic void
b5d34bc3082c1164ce20df48567d192e3e9f229fjimargstr_to_table(apr_pool_t *p, char *str, apr_table_t *parms)
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
b5d34bc3082c1164ce20df48567d192e3e9f229fjim char *key;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim char *value;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim char *strtok_state;
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim key = apr_strtok(str, "&", &strtok_state);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim while (key) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim value = strchr(key, '=');
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (value) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim *value = '\0'; /* Split the string in two */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim value++; /* Skip passed the = */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim else {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim value = "1";
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim ap_unescape_url(key);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim ap_unescape_url(value);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_table_set(parms, key, value);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim /*
b5d34bc3082c1164ce20df48567d192e3e9f229fjim ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim "Found query arg: %s = %s", key, value);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim key = apr_strtok(NULL, "&", &strtok_state);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim}
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclerestatic apr_status_t readfile_heartbeats(const char *path, apr_hash_t *servers,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_pool_t *pool)
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_finfo_t fi;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_status_t rv;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_file_t *fp;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (!path) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return APR_SUCCESS;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim rv = apr_file_open(&fp, path, APR_READ|APR_BINARY|APR_BUFFERED,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim APR_OS_DEFAULT, pool);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (rv) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return rv;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim rv = apr_file_info_get(&fi, APR_FINFO_SIZE, fp);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (rv) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return rv;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim char *t;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim int lineno = 0;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_bucket_alloc_t *ba = apr_bucket_alloc_create(pool);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_bucket_brigade *bb = apr_brigade_create(pool, ba);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_bucket_brigade *tmpbb = apr_brigade_create(pool, ba);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_table_t *hbt = apr_table_make(pool, 10);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_brigade_insert_file(bb, fp, 0, fi.size, pool);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim do {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim hb_server_t *server;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim char buf[4096];
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_size_t bsize = sizeof(buf);
a84a6c5a1f176c4fc6ccbc1183dc7c9f401e18f1pquerna const char *ip;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_brigade_cleanup(tmpbb);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (APR_BRIGADE_EMPTY(bb)) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim break;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim rv = apr_brigade_split_line(tmpbb, bb,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim APR_BLOCK_READ, sizeof(buf));
b5d34bc3082c1164ce20df48567d192e3e9f229fjim lineno++;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (rv) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return rv;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_brigade_flatten(tmpbb, buf, &bsize);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (bsize == 0) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim break;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim buf[bsize - 1] = 0;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim /* comment */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (buf[0] == '#') {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim continue;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim /* line format: <IP> <query_string>\n */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim t = strchr(buf, ' ');
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (!t) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim continue;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
1dcda0a389b6f7d7bece49fc99052312df4751a5jailletc ip = apr_pstrmemdup(pool, buf, t - buf);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim t++;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server = apr_hash_get(servers, ip, APR_HASH_KEY_STRING);
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (server == NULL) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server = apr_pcalloc(pool, sizeof(hb_server_t));
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server->ip = ip;
c87ed6a25f669f7137024ccde3771d95b9c37e07jfclere server->port = 80;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server->seen = -1;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_hash_set(servers, server->ip, APR_HASH_KEY_STRING, server);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_table_clear(hbt);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim argstr_to_table(pool, apr_pstrdup(pool, t), hbt);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (apr_table_get(hbt, "busy")) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server->busy = atoi(apr_table_get(hbt, "busy"));
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (apr_table_get(hbt, "ready")) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server->ready = atoi(apr_table_get(hbt, "ready"));
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (apr_table_get(hbt, "lastseen")) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server->seen = atoi(apr_table_get(hbt, "lastseen"));
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
c87ed6a25f669f7137024ccde3771d95b9c37e07jfclere if (apr_table_get(hbt, "port")) {
c87ed6a25f669f7137024ccde3771d95b9c37e07jfclere server->port = atoi(apr_table_get(hbt, "port"));
c87ed6a25f669f7137024ccde3771d95b9c37e07jfclere }
c87ed6a25f669f7137024ccde3771d95b9c37e07jfclere
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (server->busy == 0 && server->ready != 0) {
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim /* Server has zero threads active, but lots of them ready,
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim * it likely just started up, so lets /4 the number ready,
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim * to prevent us from completely flooding it with all new
b5d34bc3082c1164ce20df48567d192e3e9f229fjim * requests.
b5d34bc3082c1164ce20df48567d192e3e9f229fjim */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server->ready = server->ready / 4;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim } while (1);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return APR_SUCCESS;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim}
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclerestatic apr_status_t hm_read(void* mem, void *data, apr_pool_t *pool)
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere{
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere hm_slot_server_t *slotserver = (hm_slot_server_t *) mem;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere ctx_servers_t *ctx = (ctx_servers_t *) data;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere apr_hash_t *servers = (apr_hash_t *) ctx->servers;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere hb_server_t *server = apr_hash_get(servers, slotserver->ip, APR_HASH_KEY_STRING);
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere if (server == NULL) {
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere server = apr_pcalloc(pool, sizeof(hb_server_t));
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere server->ip = apr_pstrdup(pool, slotserver->ip);
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere server->seen = -1;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere apr_hash_set(servers, server->ip, APR_HASH_KEY_STRING, server);
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere }
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere server->busy = slotserver->busy;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere server->ready = slotserver->ready;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere server->seen = apr_time_sec(ctx->now - slotserver->seen);
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere server->id = slotserver->id;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere if (server->busy == 0 && server->ready != 0) {
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere server->ready = server->ready / 4;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere }
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere return APR_SUCCESS;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere}
a515c3892232a3497bb58eeec5a1b9523571cf67jfclerestatic apr_status_t readslot_heartbeats(ctx_servers_t *ctx,
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere apr_pool_t *pool)
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere{
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere storage->doall(hm_serversmem, hm_read, ctx, pool);
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere return APR_SUCCESS;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere}
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjimstatic apr_status_t read_heartbeats(const char *path, apr_hash_t *servers,
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim apr_pool_t *pool)
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim{
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim apr_status_t rv;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere if (hm_serversmem) {
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere ctx_servers_t ctx;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere ctx.now = apr_time_now();
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere ctx.servers = servers;
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere rv = readslot_heartbeats(&ctx, pool);
a515c3892232a3497bb58eeec5a1b9523571cf67jfclere } else
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim rv = readfile_heartbeats(path, servers, pool);
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim return rv;
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim}
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjimstatic proxy_worker *find_best_hb(proxy_balancer *balancer,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim request_rec *r)
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_status_t rv;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim int i;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_uint32_t openslots = 0;
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere proxy_worker **worker;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim hb_server_t *server;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_array_header_t *up_servers;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim proxy_worker *mycandidate = NULL;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_pool_t *tpool;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_hash_t *servers;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim lb_hb_ctx_t *ctx =
b5d34bc3082c1164ce20df48567d192e3e9f229fjim ap_get_module_config(r->server->module_config,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim &lbmethod_heartbeat_module);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin if (!ap_proxy_retry_worker_fn) {
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin ap_proxy_retry_worker_fn =
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker);
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin if (!ap_proxy_retry_worker_fn) {
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin /* can only happen if mod_proxy isn't loaded */
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin return NULL;
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin }
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin }
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_pool_create(&tpool, r->pool);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim servers = apr_hash_make(tpool);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim rv = read_heartbeats(ctx->path, servers, tpool);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (rv) {
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01213)
b5d34bc3082c1164ce20df48567d192e3e9f229fjim "lb_heartbeat: Unable to read heartbeats at '%s'",
b5d34bc3082c1164ce20df48567d192e3e9f229fjim ctx->path);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_pool_destroy(tpool);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return NULL;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim up_servers = apr_array_make(tpool, apr_hash_count(servers), sizeof(hb_server_t *));
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim for (i = 0; i < balancer->workers->nelts; i++) {
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere worker = &APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim server = apr_hash_get(servers, (*worker)->s->hostname, APR_HASH_KEY_STRING);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (!server) {
185aa71728867671e105178b4c66fbc22b65ae26sf ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, APLOGNO(01214)
23a31b10f869a72c9197b5f153f4f3e1a4c68f28jim "lb_heartbeat: No server for worker %s", (*worker)->s->name);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim continue;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere if (!PROXY_WORKER_IS_USABLE(*worker)) {
4ab0fd1b54ce76f0fb6812b89b0b4dc7541014d6minfrin ap_proxy_retry_worker_fn("BALANCER", *worker, r->server);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere if (PROXY_WORKER_IS_USABLE(*worker)) {
834fc281be8e0f7f2614961f12d8bbf603382a17jfclere server->worker = *worker;
a231b4cbdf1bd3d65dc13ead8d8a4f7e8b307314pquerna if (server->seen < LBM_HEARTBEAT_MAX_LASTSEEN) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim openslots += server->ready;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim APR_ARRAY_PUSH(up_servers, hb_server_t *) = server;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (openslots > 0) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_uint32_t c = 0;
01dcd2ce89010d33f43e0910ec69ecf05ef7b90ejfclere apr_uint32_t pick = 0;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
7bf4eb9638a127fbfbc402d2c0e4ec0085934cf0sf pick = ap_random_pick(0, openslots);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim for (i = 0; i < up_servers->nelts; i++) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim server = APR_ARRAY_IDX(up_servers, i, hb_server_t *);
95f51623ec0cea8b4c1551fcc0bb5816bcfe0000jfclere if (pick >= c && pick <= c + server->ready) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim mycandidate = server->worker;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim c += server->ready;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_pool_destroy(tpool);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return mycandidate;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim}
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
19f5359fc7b955a110e5ebe345ef4962cdd76473jailletcstatic apr_status_t reset(proxy_balancer *balancer, server_rec *s)
19f5359fc7b955a110e5ebe345ef4962cdd76473jailletc{
19f5359fc7b955a110e5ebe345ef4962cdd76473jailletc return APR_SUCCESS;
b1e3273c2e70ad5ac64feef979b2ed1d98c09963jim}
b1e3273c2e70ad5ac64feef979b2ed1d98c09963jim
19f5359fc7b955a110e5ebe345ef4962cdd76473jailletcstatic apr_status_t age(proxy_balancer *balancer, server_rec *s)
19f5359fc7b955a110e5ebe345ef4962cdd76473jailletc{
19f5359fc7b955a110e5ebe345ef4962cdd76473jailletc return APR_SUCCESS;
b1e3273c2e70ad5ac64feef979b2ed1d98c09963jim}
b1e3273c2e70ad5ac64feef979b2ed1d98c09963jim
b5d34bc3082c1164ce20df48567d192e3e9f229fjimstatic const proxy_balancer_method heartbeat =
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
b5d34bc3082c1164ce20df48567d192e3e9f229fjim "heartbeat",
b5d34bc3082c1164ce20df48567d192e3e9f229fjim &find_best_hb,
9a0e1ad272fdbe3fee989e93bdae8253418429edjfclere NULL,
b1e3273c2e70ad5ac64feef979b2ed1d98c09963jim &reset,
9a0e1ad272fdbe3fee989e93bdae8253418429edjfclere &age
b5d34bc3082c1164ce20df48567d192e3e9f229fjim};
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclerestatic int lb_hb_init(apr_pool_t *p, apr_pool_t *plog,
19f5359fc7b955a110e5ebe345ef4962cdd76473jailletc apr_pool_t *ptemp, server_rec *s)
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere{
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere apr_size_t size;
8f16dee9dcd6c792c931c797b12c9be9701031f2trawick unsigned int num;
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim lb_hb_ctx_t *ctx = ap_get_module_config(s->module_config,
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim &lbmethod_heartbeat_module);
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
59d316b83d42d2a07e25c20d8c35a07b369618bdsf /* do nothing on first call */
59d316b83d42d2a07e25c20d8c35a07b369618bdsf if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere return OK;
59d316b83d42d2a07e25c20d8c35a07b369618bdsf
e8a023c6d3ea9f0faa895cbc7bdd649efb8a01d6sf storage = ap_lookup_provider(AP_SLOTMEM_PROVIDER_GROUP, "shm",
714a36287cb6cc92748d7e87bbe549d660acae1ctrawick AP_SLOTMEM_PROVIDER_VERSION);
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere if (!storage) {
5400544d62947907986d570435dd16f02ca824e0sf ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(02281)
e8a023c6d3ea9f0faa895cbc7bdd649efb8a01d6sf "Failed to lookup provider 'shm' for '%s'. Maybe you "
e8a023c6d3ea9f0faa895cbc7bdd649efb8a01d6sf "need to load mod_slotmem_shm?",
e8a023c6d3ea9f0faa895cbc7bdd649efb8a01d6sf AP_SLOTMEM_PROVIDER_GROUP);
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere return OK;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere }
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere /* Try to use a slotmem created by mod_heartmonitor */
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere storage->attach(&hm_serversmem, "mod_heartmonitor", &size, &num, p);
5a493ffe535de283863dcaa6756b00e5324e5f61sf if (!hm_serversmem)
5400544d62947907986d570435dd16f02ca824e0sf ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(02282)
5a493ffe535de283863dcaa6756b00e5324e5f61sf "No slotmem from mod_heartmonitor");
5a493ffe535de283863dcaa6756b00e5324e5f61sf else
5400544d62947907986d570435dd16f02ca824e0sf ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(02283)
5a493ffe535de283863dcaa6756b00e5324e5f61sf "Using slotmem from mod_heartmonitor");
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim if (hm_serversmem)
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim ctx->path = "(slotmem)";
dc75ae85aef46bf3df41b96a4509ab19c07fe20cjim
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere return OK;
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere}
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere
b5d34bc3082c1164ce20df48567d192e3e9f229fjimstatic void register_hooks(apr_pool_t *p)
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere static const char * const aszPred[]={ "mod_heartmonitor.c", NULL };
b5d34bc3082c1164ce20df48567d192e3e9f229fjim ap_register_provider(p, PROXY_LBMETHOD, "heartbeat", "0", &heartbeat);
2806775e45dfd5164d53fcb3d850d358f8ec2415jfclere ap_hook_post_config(lb_hb_init, aszPred, NULL, APR_HOOK_MIDDLE);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim}
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjimstatic void *lb_hb_create_config(apr_pool_t *p, server_rec *s)
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
b5d34bc3082c1164ce20df48567d192e3e9f229fjim lb_hb_ctx_t *ctx = (lb_hb_ctx_t *) apr_palloc(p, sizeof(lb_hb_ctx_t));
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
9b778cf6122bc2ecd5704aaec99ee22f95764e62trawick ctx->path = ap_runtime_dir_relative(p, DEFAULT_HEARTBEAT_STORAGE);
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return ctx;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim}
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjimstatic void *lb_hb_merge_config(apr_pool_t *p, void *basev, void *overridesv)
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
b5d34bc3082c1164ce20df48567d192e3e9f229fjim lb_hb_ctx_t *ps = apr_pcalloc(p, sizeof(lb_hb_ctx_t));
b5d34bc3082c1164ce20df48567d192e3e9f229fjim lb_hb_ctx_t *base = (lb_hb_ctx_t *) basev;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim lb_hb_ctx_t *overrides = (lb_hb_ctx_t *) overridesv;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (overrides->path) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim ps->path = apr_pstrdup(p, overrides->path);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim else {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim ps->path = apr_pstrdup(p, base->path);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return ps;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim}
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjimstatic const char *cmd_lb_hb_storage(cmd_parms *cmd,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim void *dconf, const char *path)
b5d34bc3082c1164ce20df48567d192e3e9f229fjim{
b5d34bc3082c1164ce20df48567d192e3e9f229fjim apr_pool_t *p = cmd->pool;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim lb_hb_ctx_t *ctx =
b5d34bc3082c1164ce20df48567d192e3e9f229fjim (lb_hb_ctx_t *) ap_get_module_config(cmd->server->module_config,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim &lbmethod_heartbeat_module);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim if (err != NULL) {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return err;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim }
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
9b778cf6122bc2ecd5704aaec99ee22f95764e62trawick ctx->path = ap_runtime_dir_relative(p, path);
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjim return NULL;
b5d34bc3082c1164ce20df48567d192e3e9f229fjim}
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
b5d34bc3082c1164ce20df48567d192e3e9f229fjimstatic const command_rec cmds[] = {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim AP_INIT_TAKE1("HeartbeatStorage", cmd_lb_hb_storage, NULL, RSRC_CONF,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim "Path to read heartbeat data."),
b5d34bc3082c1164ce20df48567d192e3e9f229fjim {NULL}
b5d34bc3082c1164ce20df48567d192e3e9f229fjim};
b5d34bc3082c1164ce20df48567d192e3e9f229fjim
36ef8f77bffe75d1aa327882be1b5bdbe2ff567asfAP_DECLARE_MODULE(lbmethod_heartbeat) = {
b5d34bc3082c1164ce20df48567d192e3e9f229fjim STANDARD20_MODULE_STUFF,
b5d34bc3082c1164ce20df48567d192e3e9f229fjim NULL, /* create per-directory config structure */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim NULL, /* merge per-directory config structures */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim lb_hb_create_config, /* create per-server config structure */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim lb_hb_merge_config, /* merge per-server config structures */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim cmds, /* command apr_table_t */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim register_hooks /* register hooks */
b5d34bc3082c1164ce20df48567d192e3e9f229fjim};