proxy_balancer.c revision 19bb1e938b464a3e961f346e9e1ed8ffa85d55b5
/* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Load balancer module for Apache proxy */
#define CORE_PRIVATE
#include "mod_proxy.h"
#include "ap_mpm.h"
#include "scoreboard.h"
#include "apr_version.h"
#if APR_HAS_THREADS
#else
#define PROXY_BALANCER_LOCK(b) APR_SUCCESS
#define PROXY_BALANCER_UNLOCK(b) APR_SUCCESS
#endif
{
int i;
int mpm_daemons;
#else
void *score;
#endif
/* Check if we are prefork or single child */
}
else
#endif
{
/* Use the plain memory */
}
}
/* Recalculate lbfactors */
/* Set to the original configuration */
}
if (ffactor < 100.0) {
int z = 0;
++z;
}
if (z) {
}
}
else {
}
}
else if (ffactor > 100.0) {
}
}
/* Update the status entires */
}
return 0;
}
/* Retrieve the parameter with the given name */
const char *name)
{
if (*path == '=') {
/*
* Session path was found, get it's value
*/
++path;
char *q;
*q = '\0';
return path;
}
}
}
return NULL;
}
{
const char *cookies;
const char *start_cookie;
if (start_cookie == cookies ||
++start_cookie;
/*
* Session cookie was found, get it's value
*/
char *end_cookie, *cookie;
++start_cookie;
*end_cookie = '\0';
*end_cookie = '\0';
return cookie;
}
}
}
}
return NULL;
}
const char *route)
{
int i;
return worker;
}
worker++;
}
return NULL;
}
request_rec *r,
char **route,
char **url)
{
return NULL;
/* Try to find the sticky route inside url */
if (!*route)
if (*route) {
/* TODO: make worker status codes */
/* See if we have a redirection route */
/* Check if the redirect worker is usable */
}
else
return worker;
}
else
return NULL;
}
request_rec *r)
{
int i;
double total_factor = 0.0;
/* First try to see if we have available candidate */
/* See if the retry timeout is ellapsed
* for the workers flagged as IN_ERROR
*/
if (!PROXY_WORKER_IS_USABLE(worker->w))
/* If the worker is not in error state
* or not disabled.
*/
if (PROXY_WORKER_IS_USABLE(worker->w)) {
if (!candidate)
else {
/* See if the worker has a larger number of free channels */
}
/* Total factor should allways be 100.
* This is for cases when worker is in error state.
* It will force the even request distribution
*/
}
worker++;
}
if (!candidate) {
/* All the workers are in error state or disabled.
* If the balancer has a timeout wait.
*/
#if APR_HAS_THREADS
/* 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.
*/
/* Try again */
break;
}
/* restore the timeout */
}
#endif
}
else {
/* We have at least one candidate that is not in
* error state or disabled.
* Now calculate the appropriate one
*/
/* If the worker is not error state
* or not in disabled mode
*/
if (PROXY_WORKER_IS_USABLE(worker->w)) {
/* 1. Find the worker with higher lbstatus.
* Lbstatus is of higher importance then
* the number of empty slots.
*/
}
}
worker++;
}
/* If the worker is not error state
* or not in disabled mode
*/
if (PROXY_WORKER_IS_USABLE(worker->w)) {
/* XXX: The lbfactor can be update using bytes transfered
* Right now, use the round-robin scheme
*/
}
worker++;
}
}
return candidate;
}
char **url)
{
if (scheme)
/* we break the URL into host, port, uri */
if (!worker) {
"missing worker. URI cannot be parsed: ", *url,
NULL));
}
return OK;
}
request_rec *r,
{
int access_status;
char *route;
/* Step 1: check if the url is for us */
return DECLINED;
/* Initialize shared scoreboard data */
/* Step 2: find the session route */
if (!runtime) {
"proxy: BALANCER: (%s). All workers are in error state for route (%s)",
return HTTP_SERVICE_UNAVAILABLE;
}
}
else {
int i;
/* We have a sticky load balancer */
/* Update the workers status
* so that even session routes get
* into account.
*/
/* For now assume that all workers are OK */
workers++;
}
}
/* Lock the LoadBalancer
* XXX: perhaps we need the process lock here
*/
"proxy: BALANCER: lock");
return DECLINED;
}
if (!*worker) {
if (!runtime) {
"proxy: BALANCER: (%s). All workers are in error state",
return HTTP_SERVICE_UNAVAILABLE;
}
}
/* Decrease the free channels number */
/* XXX: This should be the function of apr_reslist */
/* Add the session route to request notes if present */
if (route) {
}
"proxy_balancer_pre_request rewriting to %s", *url);
"proxy_balancer_pre_request worker (%s) free %d",
return access_status;
}
request_rec *r,
{
"proxy: BALANCER: lock");
return HTTP_INTERNAL_SERVER_ERROR;
}
/* increase the free channels number */
/* TODO: calculate the bytes transfered */
/* TODO: update the scoreboard status */
return OK;
}
{
int i;
/* Recalculate lbfactors */
/* Special case if there is only one worker it's
* load factor will always be 100
*/
return;
}
}
if (ffactor < 100.0) {
}
}
}
}
else {
}
}
/* Update the status entires */
}
}
/* Invoke handler */
static int balancer_handler(request_rec *r)
{
int access_status;
int i, n;
const char *name;
/* is this for us? */
return DECLINED;
if (r->method_number != M_GET)
return DECLINED;
if (r->args) {
*val++ = '\0';
*tok++ = '\0';
return access_status;
}
else
return HTTP_BAD_REQUEST;
}
}
if (sc) {
}
if (ws) {
break;
}
++worker;
}
}
}
/* First set the params */
if (bsel) {
const char *val;
else
}
if (ival >= 0)
}
}
if (wsel) {
const char *val;
char *ep;
if (dval > 1) {
if (bsel)
}
}
else
}
else
}
else
}
ap_set_content_type(r, "text/xml");
ap_rputs("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", r);
ap_rputs("<httpd:manager xmlns:httpd=\"http://httpd.apache.org\">\n", r);
ap_rputs(" <httpd:balancers>\n", r);
ap_rputs(" <httpd:balancer>\n", r);
ap_rputs(" <httpd:workers>\n", r);
ap_rputs(" <httpd:worker>\n", r);
"</httpd:scheme>\n", NULL);
"</httpd:hostname>\n", NULL);
ap_rprintf(r, " <httpd:loadfactor>%.2f</httpd:loadfactor>\n",
ap_rputs(" </httpd:worker>\n", r);
++worker;
}
ap_rputs(" </httpd:workers>\n", r);
ap_rputs(" </httpd:balancer>\n", r);
++balancer;
}
ap_rputs(" </httpd:balancers>\n", r);
ap_rputs("</httpd:manager>", r);
}
else {
ap_set_content_type(r, "text/html");
"<html><head><title>Balancer Manager</title></head>\n", r);
ap_rputs("<body><h1>Load Balancer Manager for ", r);
ap_rvputs(r, "<dl><dt>Server Version: ",
ap_rvputs(r, "<dt>Server Built: ",
ap_rputs("<hr />\n<h3>LoadBalancer Status for ", r);
"\">", NULL);
ap_rputs("\n\n<table border=\"0\"><tr>"
"<th>StickySesion</th><th>Timeout</th>"
"</tr>\n<tr>", r);
ap_rputs("</table>\n", r);
ap_rputs("\n\n<table border=\"0\"><tr>"
"<th>Scheme</th><th>Host</th>"
"<th>Route</th><th>RouteRedir</th>"
"<th>Factor</th><th>Status</th>"
"</tr>\n", r);
"\">", NULL);
ap_rputs("Dis", r);
ap_rputs("Err", r);
ap_rputs("Ok", r);
else
ap_rputs("-", r);
ap_rputs("</td></tr>\n", r);
++worker;
}
ap_rputs("</table>\n", r);
++balancer;
}
ap_rputs("<hr />\n", r);
ap_rputs("<h3>Edit worker settings for ", r);
ap_rputs("<table><tr><td>Load factor:</td><td><input name=\"lf\" type=text ", r);
ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r);
ap_rputs("\"></td><tr>\n", r);
ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r);
ap_rputs("\"></td><tr>\n", r);
ap_rputs("<tr><td>Disabled:</td><td><input name=\"dw\" type=checkbox", r);
ap_rputs(" checked", r);
ap_rputs("></td><tr>\n", r);
ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
"\">\n</form>\n", NULL);
ap_rputs("<hr />\n", r);
}
else if (bsel) {
ap_rputs("<h3>Edit balancer settings for ", r);
ap_rputs("<table><tr><td>StickySession Identifier:</td><td><input name=\"ss\" type=text ", r);
ap_rputs("></td><tr>\n<tr><td>Timeout:</td><td><input name=\"tm\" type=text ", r);
ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
"\">\n</form>\n", NULL);
ap_rputs("<hr />\n", r);
}
ap_rputs("</body></html>\n", r);
}
return OK;
}
static void ap_proxy_balancer_register_hook(apr_pool_t *p)
{
/* manager handler */
}
NULL, /* create per-directory config structure */
NULL, /* merge per-directory config structures */
NULL, /* create per-server config structure */
NULL, /* merge per-server config structures */
NULL, /* command apr_table_t */
ap_proxy_balancer_register_hook /* register hooks */
};