Index: docs/manual/mod/mod_proxy.xml
===================================================================
--- docs/manual/mod/mod_proxy.xml	(revision 440792)
+++ docs/manual/mod/mod_proxy.xml	(working copy)
@@ -578,6 +578,12 @@
     generally 120ms), and thus prevent the firewall to drop the connection.
     To enable keepalive set this property value to <code>On</code>. 
     </td></tr>
+    <tr><td>lbset</td>
+        <td>0</td>
+        <td>Sets the load balancer cluster set that the worker is a member
+         of. The load balancer will try all members of a lower numbered
+         lbset before trying higher numbered ones.
+    </td></tr>
     <tr><td>loadfactor</td>
         <td>1</td>
         <td>Worker load factor. Used with BalancerMember.
@@ -608,7 +614,7 @@
     <tr><td>status</td>
         <td>-</td>
         <td>Single letter value defining the initial status of
-        this worker: 'D' is disabled, 'S' is stopped
+        this worker: 'D' is disabled, 'S' is stopped, 'H' is hot-standby
         and 'E' is in an error state. Status can be set (which is the default)
         by prepending with '+' or cleared by prepending with '-'.
         Thus, a setting of 'S-E' sets this worker to Stopped and
@@ -685,6 +691,22 @@
       </indent>
       &lt;/Proxy&gt;
     </example>
+
+    <p>Setting up a hot-standby, that will only be used if no other
+     members are available</p>
+    <example>
+      ProxyPass / balancer://hotcluster/ <br />
+      &lt;Proxy balancer://hotcluster&gt;<br />
+      <indent>
+        BalancerMember http://1.2.3.4:8009 loadfactor=1<br />
+        BalancerMember http://1.2.3.5:8009 loadfactor=2<br />
+        # The below is the hot standby<br />
+        BalancerMember http://1.2.3.6:8009 status=+H<br />
+        ProxySet lbmethod=bytraffic
+      </indent>
+      &lt;/Proxy&gt;
+    </example>
+
     
     <p>When used inside a <directive type="section" module="core"
     >Location</directive> section, the first argument is omitted and the local
Index: CHANGES
===================================================================
--- CHANGES	(revision 440792)
+++ CHANGES	(working copy)
@@ -1,6 +1,10 @@
                                                         -*- coding: utf-8 -*-
 Changes with Apache 2.2.4
 
+  *) mod_proxy_balancer: Workers can now be defined as part of
+     a balancer cluster "set" in which members of a lower-numbered set
+     are preferred over higher numbered ones. [Jim Jagielski]
+
   *) mod_proxy_balancer: Workers can now be defined as "hot standby" which
      will only be used if all other workers are unusable (eg: in
      error or disabled). Also, the balancer-manager displays the election
Index: modules/proxy/mod_proxy_balancer.c
===================================================================
--- modules/proxy/mod_proxy_balancer.c	(revision 440792)
+++ modules/proxy/mod_proxy_balancer.c	(working copy)
@@ -93,6 +93,7 @@
         /* Set to the original configuration */
         workers[i].s->lbstatus = workers[i].s->lbfactor =
           (workers[i].lbfactor ? workers[i].lbfactor : 1);
+        workers[i].s->lbset = workers[i].lbset;
     }
     /* Set default number of attempts to the number of
      * workers.
@@ -172,10 +173,12 @@
                                        const char *route, request_rec *r)
 {
     int i;
-    int checking_standby = 0;
-    int checked_standby = 0;
+    int checking_standby;
+    int checked_standby;
     
     proxy_worker *worker;
+
+    checking_standby = checked_standby = 0;
     while (!checked_standby) {
         worker = (proxy_worker *)balancer->workers->elts;
         for (i = 0; i < balancer->workers->nelts; i++, worker++) {
@@ -601,6 +604,12 @@
             else if (!strcasecmp(val, "Enable"))
                 wsel->s->status &= ~PROXY_WORKER_DISABLED;
         }
+        if ((val = apr_table_get(params, "ls"))) {
+            int ival = atoi(val);
+            if (ival >= 0 && ival <= 99) {
+                wsel->s->lbset = ival;
+             }
+        }
 
     }
     if (apr_table_get(params, "xml")) {
@@ -663,13 +672,13 @@
             ap_rputs("\n\n<table border=\"0\" style=\"text-align: left;\"><tr>"
                 "<th>Worker URL</th>"
                 "<th>Route</th><th>RouteRedir</th>"
-                "<th>Factor</th><th>Status</th>"
+                "<th>Factor</th><th>Set</th><th>Status</th>"
                 "<th>Elected</th><th>To</th><th>From</th>"
                 "</tr>\n", r);
 
             worker = (proxy_worker *)balancer->workers->elts;
             for (n = 0; n < balancer->workers->nelts; n++) {
-
+                char fbuf[50];
                 ap_rvputs(r, "<tr>\n<td><a href=\"", r->uri, "?b=",
                           balancer->name + sizeof("balancer://") - 1, "&w=",
                           ap_escape_uri(r->pool, worker->name),
@@ -677,7 +686,8 @@
                 ap_rvputs(r, worker->name, "</a></td>", NULL);
                 ap_rvputs(r, "<td>", worker->s->route, NULL);
                 ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
-                ap_rprintf(r, "</td><td>%d</td><td>", worker->s->lbfactor);
+                ap_rprintf(r, "</td><td>%d</td>", worker->s->lbfactor);
+                ap_rprintf(r, "<td>%d</td><td>", worker->s->lbset);
                 if (worker->s->status & PROXY_WORKER_DISABLED)
                    ap_rputs("Dis ", r);
                 if (worker->s->status & PROXY_WORKER_IN_ERROR)
@@ -691,10 +701,11 @@
                 if (!PROXY_WORKER_IS_INITIALIZED(worker))
                     ap_rputs("-", r);
                 ap_rputs("</td>", r);
-                ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td>", worker->s->elected);
-                ap_rprintf(r, "<td>%" APR_OFF_T_FMT "</td>", worker->s->transferred);
-                ap_rprintf(r, "<td>%" APR_OFF_T_FMT "</td>", worker->s->read);
-                ap_rputs("</tr>\n", r);
+                ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td><td>", worker->s->elected);
+                ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r);
+                ap_rputs("</td><td>", r);
+                ap_rputs(apr_strfsize(worker->s->read, fbuf), r);
+                ap_rputs("</td></tr>\n", r);
 
                 ++worker;
             }
@@ -708,20 +719,22 @@
             ap_rvputs(r, "<form method=\"GET\" action=\"", NULL);
             ap_rvputs(r, r->uri, "\">\n<dl>", NULL);
             ap_rputs("<table><tr><td>Load factor:</td><td><input name=\"lf\" type=text ", r);
-            ap_rprintf(r, "value=\"%d\"></td><tr>\n", wsel->s->lbfactor);
+            ap_rprintf(r, "value=\"%d\"></td></tr>\n", wsel->s->lbfactor);
+            ap_rputs("<tr><td>LB Set:</td><td><input name=\"ls\" type=text ", r);
+            ap_rprintf(r, "value=\"%d\"></td></tr>\n", wsel->s->lbset);
             ap_rputs("<tr><td>Route:</td><td><input name=\"wr\" type=text ", r);
             ap_rvputs(r, "value=\"", wsel->route, NULL);
-            ap_rputs("\"></td><tr>\n", r);
+            ap_rputs("\"></td></tr>\n", r);
             ap_rputs("<tr><td>Route Redirect:</td><td><input name=\"rr\" type=text ", r);
             ap_rvputs(r, "value=\"", wsel->redirect, NULL);
-            ap_rputs("\"></td><tr>\n", r);
+            ap_rputs("\"></td></tr>\n", r);
             ap_rputs("<tr><td>Status:</td><td>Disabled: <input name=\"dw\" value=\"Disable\" type=radio", r);
             if (wsel->s->status & PROXY_WORKER_DISABLED)
                 ap_rputs(" checked", r);
             ap_rputs("> | Enabled: <input name=\"dw\" value=\"Enable\" type=radio", r);
             if (!(wsel->s->status & PROXY_WORKER_DISABLED))
                 ap_rputs(" checked", r);
-            ap_rputs("></td><tr>\n", r);
+            ap_rputs("></td></tr>\n", r);
             ap_rputs("<tr><td colspan=2><input type=submit value=\"Submit\"></td></tr>\n", r);
             ap_rvputs(r, "</table>\n<input type=hidden name=\"w\" ",  NULL);
             ap_rvputs(r, "value=\"", ap_escape_uri(r->pool, wsel->name), "\">\n", NULL);
@@ -844,39 +857,51 @@
     int total_factor = 0;
     proxy_worker *worker;
     proxy_worker *mycandidate = NULL;
-    int checking_standby = 0;
-    int checked_standby = 0;
+    int cur_lbset = 0;
+    int max_lbset = 0;
+    int checking_standby;
+    int checked_standby;
     
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                  "proxy: Entering byrequests for BALANCER (%s)",
                  balancer->name);
 
     /* First try to see if we have available candidate */
-    while (!mycandidate && !checked_standby) {
-        worker = (proxy_worker *)balancer->workers->elts;
-        for (i = 0; i < balancer->workers->nelts; i++, worker++) {
-            if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
-                continue;
-            /* If the worker is in error state run
-             * retry on that worker. It will be marked as
-             * operational if the retry timeout is elapsed.
-             * The worker might still be unusable, but we try
-             * anyway.
-             */
-            if (!PROXY_WORKER_IS_USABLE(worker))
-                ap_proxy_retry_worker("BALANCER", worker, r->server);
-            /* Take into calculation only the workers that are
-             * not in error state or not disabled.
-             */
-            if (PROXY_WORKER_IS_USABLE(worker)) {
-                worker->s->lbstatus += worker->s->lbfactor;
-                total_factor += worker->s->lbfactor;
-                if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus)
-                    mycandidate = worker;
+    do {
+        checking_standby = checked_standby = 0;
+        while (!mycandidate && !checked_standby) {
+            worker = (proxy_worker *)balancer->workers->elts;
+            for (i = 0; i < balancer->workers->nelts; i++, worker++) {
+                if (!checking_standby) {    /* first time through */
+                    if (worker->s->lbset > max_lbset)
+                        max_lbset = worker->s->lbset;
+                }
+                if (worker->s->lbset > cur_lbset)
+                    continue;
+                if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
+                    continue;
+                /* If the worker is in error state run
+                 * retry on that worker. It will be marked as
+                 * operational if the retry timeout is elapsed.
+                 * The worker might still be unusable, but we try
+                 * anyway.
+                 */
+                if (!PROXY_WORKER_IS_USABLE(worker))
+                    ap_proxy_retry_worker("BALANCER", worker, r->server);
+                /* Take into calculation only the workers that are
+                 * not in error state or not disabled.
+                 */
+                if (PROXY_WORKER_IS_USABLE(worker)) {
+                    worker->s->lbstatus += worker->s->lbfactor;
+                    total_factor += worker->s->lbfactor;
+                    if (!mycandidate || worker->s->lbstatus > mycandidate->s->lbstatus)
+                        mycandidate = worker;
+                }
             }
+            checked_standby = checking_standby++;
         }
-        checked_standby = checking_standby++;
-    }
+        cur_lbset++;
+    } while (cur_lbset <= max_lbset && !mycandidate);
 
     if (mycandidate) {
         mycandidate->s->lbstatus -= total_factor;
@@ -910,42 +935,54 @@
     apr_off_t mytraffic = 0;
     apr_off_t curmin = 0;
     proxy_worker *worker;
-    int checking_standby = 0;
-    int checked_standby = 0;
     proxy_worker *mycandidate = NULL;
+    int cur_lbset = 0;
+    int max_lbset = 0;
+    int checking_standby;
+    int checked_standby;
 
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                  "proxy: Entering bytraffic for BALANCER (%s)",
                  balancer->name);
 
     /* First try to see if we have available candidate */
-    while (!mycandidate && !checked_standby) {
-        worker = (proxy_worker *)balancer->workers->elts;
-        for (i = 0; i < balancer->workers->nelts; i++, worker++) {
-            if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
-                continue;
-            /* If the worker is in error state run
-             * retry on that worker. It will be marked as
-             * operational if the retry timeout is elapsed.
-             * The worker might still be unusable, but we try
-             * anyway.
-             */
-            if (!PROXY_WORKER_IS_USABLE(worker))
-                ap_proxy_retry_worker("BALANCER", worker, r->server);
-            /* Take into calculation only the workers that are
-             * not in error state or not disabled.
-             */
-            if (PROXY_WORKER_IS_USABLE(worker)) {
-                mytraffic = (worker->s->transferred/worker->s->lbfactor) +
-                            (worker->s->read/worker->s->lbfactor);
-                if (!mycandidate || mytraffic < curmin) {
-                    mycandidate = worker;
-                    curmin = mytraffic;
+    do {
+        checking_standby = checked_standby = 0;
+        while (!mycandidate && !checked_standby) {
+            worker = (proxy_worker *)balancer->workers->elts;
+            for (i = 0; i < balancer->workers->nelts; i++, worker++) {
+                if (!checking_standby) {    /* first time through */
+                    if (worker->s->lbset > max_lbset)
+                        max_lbset = worker->s->lbset;
                 }
+                if (worker->s->lbset > cur_lbset)
+                    continue;
+                if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
+                    continue;
+                /* If the worker is in error state run
+                 * retry on that worker. It will be marked as
+                 * operational if the retry timeout is elapsed.
+                 * The worker might still be unusable, but we try
+                 * anyway.
+                 */
+                if (!PROXY_WORKER_IS_USABLE(worker))
+                    ap_proxy_retry_worker("BALANCER", worker, r->server);
+                /* Take into calculation only the workers that are
+                 * not in error state or not disabled.
+                 */
+                if (PROXY_WORKER_IS_USABLE(worker)) {
+                    mytraffic = (worker->s->transferred/worker->s->lbfactor) +
+                                (worker->s->read/worker->s->lbfactor);
+                    if (!mycandidate || mytraffic < curmin) {
+                        mycandidate = worker;
+                        curmin = mytraffic;
+                    }
+                }
             }
+            checked_standby = checking_standby++;
         }
-        checked_standby = checking_standby++;
-    }
+        cur_lbset++;
+    } while (cur_lbset <= max_lbset && !mycandidate);
 
     if (mycandidate) {
         mycandidate->s->elected++;
Index: modules/proxy/mod_proxy.c
===================================================================
--- modules/proxy/mod_proxy.c	(revision 440792)
+++ modules/proxy/mod_proxy.c	(working copy)
@@ -244,6 +244,12 @@
         else
             worker->flush_wait = ival * 1000;    /* change to microseconds */
     }
+    else if (!strcasecmp(key, "lbset")) {
+        ival = atoi(val);
+        if (ival < 0 || ival > 99)
+            return "lbset must be between 0 and 99";
+        worker->lbset = ival;
+    }
     else {
         return "unknown Worker parameter";
     }
@@ -1800,7 +1806,7 @@
         ap_rputs("\n\n<table border=\"0\"><tr>"
                  "<th>Sch</th><th>Host</th><th>Stat</th>"
                  "<th>Route</th><th>Redir</th>"
-                 "<th>F</th><th>Acc</th><th>Wr</th><th>Rd</th>"
+                 "<th>F</th><th>Set</th><th>Acc</th><th>Wr</th><th>Rd</th>"
                  "</tr>\n", r);
 
         worker = (proxy_worker *)balancer->workers->elts;
@@ -1819,7 +1825,8 @@
             ap_rvputs(r, "</td><td>", worker->s->route, NULL);
             ap_rvputs(r, "</td><td>", worker->s->redirect, NULL);
             ap_rprintf(r, "</td><td>%d</td>", worker->s->lbfactor);
-            ap_rprintf(r, "<td>%d</td><td>", (int)(worker->s->elected));
+            ap_rprintf(r, "<td>%d</td>", worker->s->lbset);
+            ap_rprintf(r, "<td>%" APR_SIZE_T_FMT "</td><td>", worker->s->elected);
             ap_rputs(apr_strfsize(worker->s->transferred, fbuf), r);
             ap_rputs("</td><td>", r);
             ap_rputs(apr_strfsize(worker->s->read, fbuf), r);
Index: modules/proxy/mod_proxy.h
===================================================================
--- modules/proxy/mod_proxy.h	(revision 440792)
+++ modules/proxy/mod_proxy.h	(working copy)
@@ -279,6 +279,8 @@
     char            route[PROXY_WORKER_MAX_ROUTE_SIZ+1];
     char            redirect[PROXY_WORKER_MAX_ROUTE_SIZ+1];
     void            *context;   /* general purpose storage */
+    apr_size_t      busy;       /* busyness factor */
+    int             lbset;      /* load balancer cluster set */
 } proxy_worker_stat;
 
 /* Worker configuration */
@@ -299,29 +301,30 @@
     apr_interval_time_t ttl;    /* maximum amount of time in seconds a connection
                                  * may be available while exceeding the soft limit */
     apr_interval_time_t timeout; /* connection timeout */
-    char                timeout_set;
+    char            timeout_set;
     apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */
-    char                acquire_set;
-    apr_size_t          recv_buffer_size;
-    char                recv_buffer_size_set;
-    apr_size_t          io_buffer_size;
-    char                io_buffer_size_set;
-    char                keepalive;
-    char                keepalive_set;
+    char            acquire_set;
+    apr_size_t      recv_buffer_size;
+    char            recv_buffer_size_set;
+    apr_size_t      io_buffer_size;
+    char            io_buffer_size_set;
+    char            keepalive;
+    char            keepalive_set;
     proxy_conn_pool     *cp;        /* Connection pool to use */
     proxy_worker_stat   *s;         /* Shared data */
-    void                *opaque;    /* per scheme worker data */
-    int                 is_address_reusable;
+    void            *opaque;    /* per scheme worker data */
+    int             is_address_reusable;
 #if APR_HAS_THREADS
     apr_thread_mutex_t  *mutex;  /* Thread lock for updating address cache */
 #endif
-    void                *context;   /* general purpose storage */
+    void            *context;   /* general purpose storage */
     enum {
          flush_off,
          flush_on,
          flush_auto
     } flush_packets;           /* control AJP flushing */
-    int                 flush_wait;  /* poll wait time in microseconds if flush_auto */
+    int             flush_wait;  /* poll wait time in microseconds if flush_auto */
+    int             lbset;      /* load balancer cluster set */
 };
 
 /*
