View | Details | Raw Unified | Return to bug 61140
Collapse All | Expand All

(-)a/docs/manual/howto/reverse_proxy.xml (-6 / +7 lines)
Lines 228-238 Link Here
228
    </highlight>
228
    </highlight>
229
229
230
    <p>
230
    <p>
231
      For failover, hot spares are used as replacements for failed or unusable
231
      For failover, hot spares are used as replacements for unusable workers in
232
      workers in the same load balancer set. Hot standbys are used if all
232
      the same load balancer set. A worker is considered unusable if it is
233
      workers and spares in the load balancer set are unavailable. Load balancer
233
      draining, stopped, or otherwise in an error/failed state. Hot standbys are
234
      sets (with their respective hot spares and standbys) are always tried in
234
      used if all workers and spares in the load balancer set are
235
      order from lowest to highest.
235
      unavailable. Load balancer sets (with their respective hot spares and
236
      standbys) are always tried in order from lowest to highest.
236
    </p>
237
    </p>
237
238
238
  </section>
239
  </section>
Lines 323-329 Link Here
323
                    and will not be automatically retried</td></tr>
324
                    and will not be automatically retried</td></tr>
324
        <tr><td><code>I</code></td><td><em>Ign</em></td><td>Worker is in ignore-errors mode and will always be considered available.</td></tr>
325
        <tr><td><code>I</code></td><td><em>Ign</em></td><td>Worker is in ignore-errors mode and will always be considered available.</td></tr>
325
        <tr><td><code>R</code></td><td><em>Spar</em></td><td>Worker is a hot spare. For each worker in a given lbset that is unusable
326
        <tr><td><code>R</code></td><td><em>Spar</em></td><td>Worker is a hot spare. For each worker in a given lbset that is unusable
326
                    (disabled, stopped, in error, etc.), a usable hot spare with the same lbset will be used in
327
                    (draining, stopped, in error, etc.), a usable hot spare with the same lbset will be used in
327
                    its place. Hot spares can help ensure that a specific number of workers are always available
328
                    its place. Hot spares can help ensure that a specific number of workers are always available
328
                    for use by a balancer.</td></tr>
329
                    for use by a balancer.</td></tr>
329
        <tr><td><code>H</code></td><td><em>Stby</em></td><td>Worker is in hot-standby mode and will only be used if no other
330
        <tr><td><code>H</code></td><td><em>Stby</em></td><td>Worker is in hot-standby mode and will only be used if no other
(-)a/docs/manual/mod/mod_proxy.xml (-2 / +2 lines)
Lines 1181-1187 Link Here
1181
                    and will not be automatically retried</td></tr>
1181
                    and will not be automatically retried</td></tr>
1182
         <tr><td><code>I</code></td><td>Worker is in ignore-errors mode and will always be considered available.</td></tr>
1182
         <tr><td><code>I</code></td><td>Worker is in ignore-errors mode and will always be considered available.</td></tr>
1183
         <tr><td><code>R</code></td><td>Worker is a hot spare. For each worker in a given lbset that is unusable
1183
         <tr><td><code>R</code></td><td>Worker is a hot spare. For each worker in a given lbset that is unusable
1184
                    (disabled, stopped, in error, etc.), a usable hot spare with the same lbset will be used in
1184
                    (draining, stopped, in error, etc.), a usable hot spare with the same lbset will be used in
1185
                    its place. Hot spares can help ensure that a specific number of workers are always available
1185
                    its place. Hot spares can help ensure that a specific number of workers are always available
1186
                    for use by a balancer.</td></tr>
1186
                    for use by a balancer.</td></tr>
1187
         <tr><td><code>H</code></td><td>Worker is in hot-standby mode and will only be used if no other
1187
         <tr><td><code>H</code></td><td>Worker is in hot-standby mode and will only be used if no other
Lines 1347-1353 Link Here
1347
    BalancerMember ajp://1.2.3.4:8009
1347
    BalancerMember ajp://1.2.3.4:8009
1348
    BalancerMember ajp://1.2.3.5:8009
1348
    BalancerMember ajp://1.2.3.5:8009
1349
    # The servers below are hot spares. For each server above that is unusable
1349
    # The servers below are hot spares. For each server above that is unusable
1350
    # (disabled, stopped, unreachable, in error state, etc.), one of these spares
1350
    # (draining, stopped, unreachable, in error state, etc.), one of these spares
1351
    # will be used in its place. Two servers will always be available for a request
1351
    # will be used in its place. Two servers will always be available for a request
1352
    # unless one or more of the spares is also unusable.
1352
    # unless one or more of the spares is also unusable.
1353
    BalancerMember ajp://1.2.3.6:8009 status=+R
1353
    BalancerMember ajp://1.2.3.6:8009 status=+R
(-)a/modules/proxy/balancers/mod_lbmethod_bybusyness.c (-49 / +20 lines)
Lines 22-84 Link Here
22
22
23
module AP_MODULE_DECLARE_DATA lbmethod_bybusyness_module;
23
module AP_MODULE_DECLARE_DATA lbmethod_bybusyness_module;
24
24
25
static int (*ap_proxy_retry_worker_fn)(const char *proxy_function,
25
static int is_best_bybusyness(proxy_worker *current, proxy_worker *prev_best, void *baton)
26
        proxy_worker *worker, server_rec *s) = NULL;
26
{
27
    int *total_factor = (int *)baton;
28
29
    current->s->lbstatus += current->s->lbfactor;
30
    *total_factor += current->s->lbfactor;
31
32
    return (
33
        !prev_best
34
        || (current->s->busy < prev_best->s->busy)
35
        || (
36
            (current->s->busy == prev_best->s->busy)
37
            && (current->s->lbstatus > prev_best->s->lbstatus)
38
        )
39
    );
40
}
27
41
28
static proxy_worker *find_best_bybusyness(proxy_balancer *balancer,
42
static proxy_worker *find_best_bybusyness(proxy_balancer *balancer,
29
                                          request_rec *r)
43
                                          request_rec *r)
30
{
44
{
31
    int i;
32
    int total_factor = 0;
45
    int total_factor = 0;
33
    apr_array_header_t *workers;
46
    proxy_worker *worker = ap_proxy_balancer_get_best_worker(balancer, r, is_best_bybusyness, &total_factor);
34
    proxy_worker **worker;
35
    proxy_worker *mycandidate = NULL;
36
    apr_pool_t *wpool;
37
47
38
    if (!ap_proxy_retry_worker_fn) {
48
    if (worker) {
39
        ap_proxy_retry_worker_fn =
49
        worker->s->lbstatus -= total_factor;
40
                APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker);
41
        if (!ap_proxy_retry_worker_fn) {
42
            /* can only happen if mod_proxy isn't loaded */
43
            return NULL;
44
        }
45
    }
50
    }
46
51
47
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01211)
52
    return worker;
48
                 "proxy: Entering bybusyness for BALANCER (%s)",
49
                 balancer->s->name);
50
51
    apr_pool_create(&wpool, r->pool);
52
53
    workers = ap_proxy_balancer_usable_workers(balancer, r, wpool);
54
55
    for (i = 0; i < workers->nelts; i++) {
56
        worker = &APR_ARRAY_IDX(workers, i, proxy_worker *);
57
        (*worker)->s->lbstatus += (*worker)->s->lbfactor;
58
        total_factor += (*worker)->s->lbfactor;
59
60
        if (
61
            !mycandidate
62
            || ((*worker)->s->busy < mycandidate->s->busy)
63
            || (
64
                ((*worker)->s->busy == mycandidate->s->busy)
65
                && ((*worker)->s->lbstatus > mycandidate->s->lbstatus)
66
            )
67
        ) {
68
            mycandidate = *worker;
69
        }
70
    }
71
72
    apr_pool_destroy(wpool);
73
74
    if (mycandidate) {
75
        mycandidate->s->lbstatus -= total_factor;
76
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01212)
77
                     "proxy: bybusyness selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d",
78
                     mycandidate->s->name, mycandidate->s->busy, mycandidate->s->lbstatus);
79
    }
80
81
    return mycandidate;
82
}
53
}
83
54
84
/* assumed to be mutex protected by caller */
55
/* assumed to be mutex protected by caller */
(-)a/modules/proxy/balancers/mod_lbmethod_byrequests.c (-46 / +13 lines)
Lines 22-29 Link Here
22
22
23
module AP_MODULE_DECLARE_DATA lbmethod_byrequests_module;
23
module AP_MODULE_DECLARE_DATA lbmethod_byrequests_module;
24
24
25
static int (*ap_proxy_retry_worker_fn)(const char *proxy_function,
25
static int is_best_byrequests(proxy_worker *current, proxy_worker *prev_best, void *baton)
26
        proxy_worker *worker, server_rec *s) = NULL;
26
{
27
    int *total_factor = (int *)baton;
28
29
    current->s->lbstatus += current->s->lbfactor;
30
    *total_factor += current->s->lbfactor;
31
32
    return (!prev_best || (current->s->lbstatus > prev_best->s->lbstatus));
33
}
27
34
28
/*
35
/*
29
 * The idea behind the find_best_byrequests scheduler is the following:
36
 * The idea behind the find_best_byrequests scheduler is the following:
Lines 70-126 Link Here
70
 *   b a d c d a c d b d ...
77
 *   b a d c d a c d b d ...
71
 *
78
 *
72
 */
79
 */
73
74
static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
80
static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
75
                                          request_rec *r)
81
                                          request_rec *r)
76
{
82
{
77
    int i;
78
    int total_factor = 0;
83
    int total_factor = 0;
79
    apr_array_header_t *workers;
84
    proxy_worker *worker = ap_proxy_balancer_get_best_worker(balancer, r, is_best_byrequests, &total_factor);
80
    proxy_worker **worker;
81
    proxy_worker *mycandidate = NULL;
82
    apr_pool_t *wpool;
83
85
84
    if (!ap_proxy_retry_worker_fn) {
86
    if (worker) {
85
        ap_proxy_retry_worker_fn =
87
        worker->s->lbstatus -= total_factor;
86
                APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker);
87
        if (!ap_proxy_retry_worker_fn) {
88
            /* can only happen if mod_proxy isn't loaded */
89
            return NULL;
90
        }
91
    }
88
    }
92
89
93
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01207)
90
    return worker;
94
                 "proxy: Entering byrequests for BALANCER (%s)",
95
                 balancer->s->name);
96
97
    apr_pool_create(&wpool, r->pool);
98
99
    workers = ap_proxy_balancer_usable_workers(balancer, r, wpool);
100
101
    for (i = 0; i < workers->nelts; i++) {
102
        worker = &APR_ARRAY_IDX(workers, i, proxy_worker *);
103
        (*worker)->s->lbstatus += (*worker)->s->lbfactor;
104
        total_factor += (*worker)->s->lbfactor;
105
106
        if (
107
            !mycandidate
108
            || ((*worker)->s->lbstatus > mycandidate->s->lbstatus)
109
        ) {
110
            mycandidate = *worker;
111
        }
112
    }
113
114
    apr_pool_destroy(wpool);
115
116
    if (mycandidate) {
117
        mycandidate->s->lbstatus -= total_factor;
118
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01208)
119
                     "proxy: byrequests selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d",
120
                     mycandidate->s->name, mycandidate->s->busy, mycandidate->s->lbstatus);
121
    }
122
123
    return mycandidate;
124
}
91
}
125
92
126
/* assumed to be mutex protected by caller */
93
/* assumed to be mutex protected by caller */
(-)a/modules/proxy/balancers/mod_lbmethod_bytraffic.c (-46 / +16 lines)
Lines 22-29 Link Here
22
22
23
module AP_MODULE_DECLARE_DATA lbmethod_bytraffic_module;
23
module AP_MODULE_DECLARE_DATA lbmethod_bytraffic_module;
24
24
25
static int (*ap_proxy_retry_worker_fn)(const char *proxy_function,
25
static int is_best_bytraffic(proxy_worker *current, proxy_worker *prev_best, void *baton)
26
        proxy_worker *worker, server_rec *s) = NULL;
26
{
27
    apr_off_t *min_traffic = (apr_off_t *)baton;
28
    apr_off_t traffic = (current->s->transferred / current->s->lbfactor)
29
                        + (current->s->read / current->s->lbfactor);
30
31
    if (!prev_best || (traffic < *min_traffic)) {
32
        *min_traffic = traffic;
33
34
        return TRUE;
35
    }
36
37
    return FALSE;
38
}
27
39
28
/*
40
/*
29
 * The idea behind the find_best_bytraffic scheduler is the following:
41
 * The idea behind the find_best_bytraffic scheduler is the following:
Lines 45-95 Link Here
45
static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
57
static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
46
                                         request_rec *r)
58
                                         request_rec *r)
47
{
59
{
48
    int i;
60
    apr_off_t min_traffic = 0;
49
    apr_off_t mytraffic = 0;
50
    apr_off_t curmin = 0;
51
    apr_array_header_t *workers;
52
    proxy_worker **worker;
53
    proxy_worker *mycandidate = NULL;
54
    apr_pool_t *wpool;
55
56
    if (!ap_proxy_retry_worker_fn) {
57
        ap_proxy_retry_worker_fn =
58
                APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker);
59
        if (!ap_proxy_retry_worker_fn) {
60
            /* can only happen if mod_proxy isn't loaded */
61
            return NULL;
62
        }
63
    }
64
65
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01209)
66
                 "proxy: Entering bytraffic for BALANCER (%s)",
67
                 balancer->s->name);
68
61
69
    apr_pool_create(&wpool, r->pool);
62
    return ap_proxy_balancer_get_best_worker(balancer, r, is_best_bytraffic, &min_traffic);
70
71
    workers = ap_proxy_balancer_usable_workers(balancer, r, wpool);
72
73
    for (i = 0; i < workers->nelts; i++) {
74
        worker = &APR_ARRAY_IDX(workers, i, proxy_worker *);
75
        mytraffic = (*worker)->s->transferred/(*worker)->s->lbfactor
76
                    + (*worker)->s->read/(*worker)->s->lbfactor;
77
78
        if (!mycandidate || (mytraffic < curmin)) {
79
            mycandidate = *worker;
80
            curmin = mytraffic;
81
        }
82
    }
83
84
    apr_pool_destroy(wpool);
85
86
    if (mycandidate) {
87
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01210)
88
                     "proxy: bytraffic selected worker \"%s\" : busy %" APR_SIZE_T_FMT,
89
                     mycandidate->s->name, mycandidate->s->busy);
90
    }
91
92
    return mycandidate;
93
}
63
}
94
64
95
/* assumed to be mutex protected by caller */
65
/* assumed to be mutex protected by caller */
(-)a/modules/proxy/mod_proxy.h (-7 / +13 lines)
Lines 860-875 Link Here
860
                                                         server_rec *s,
860
                                                         server_rec *s,
861
                                                         apr_pool_t *p);
861
                                                         apr_pool_t *p);
862
862
863
typedef int (proxy_is_best_callback_fn_t)(proxy_worker *current, proxy_worker *prev_best, void *baton);
864
863
/**
865
/**
864
 * Retrieve a list of usable workers for the balancer
866
 * Retrieve the best worker in a balancer for the current request
865
 * @param balancer balancer for which usable workers should be retrieved
867
 * @param balancer balancer for which to find the best worker
866
 * @param r        current request record
868
 * @param r        current request record
867
 * @param p        memory pool used for array
869
 * @param is_best  a callback function provide by the lbmethod
868
 * @return         APR array of usable workers
870
 *                 that determines if the current worker is best
871
 * @param baton    an lbmethod-specific context pointer (baton)
872
 *                 passed to the is_best callback
873
 * @return         the best worker to be used for the request
869
 */
874
 */
870
PROXY_DECLARE(apr_array_header_t *) ap_proxy_balancer_usable_workers(proxy_balancer *balancer,
875
PROXY_DECLARE(proxy_worker *) ap_proxy_balancer_get_best_worker(proxy_balancer *balancer,
871
                                                                     request_rec *r,
876
                                                                request_rec *r,
872
                                                                     apr_pool_t *p);
877
                                                                proxy_is_best_callback_fn_t *is_best,
878
                                                                void *baton);
873
879
874
/**
880
/**
875
 * Find the shm of the worker as needed
881
 * Find the shm of the worker as needed
(-)a/modules/proxy/proxy_util.c (-42 / +68 lines)
Lines 40-47 Link Here
40
#include "apr_support.h"        /* for apr_wait_for_io_or_timeout() */
40
#include "apr_support.h"        /* for apr_wait_for_io_or_timeout() */
41
#endif
41
#endif
42
42
43
static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worker, server_rec *s);
44
45
APLOG_USE_MODULE(proxy);
43
APLOG_USE_MODULE(proxy);
46
44
47
/*
45
/*
Lines 68-73 Link Here
68
static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
66
static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
69
static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
67
static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
70
static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
68
static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
69
static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worker, server_rec *s);
71
70
72
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
71
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(proxy, PROXY, int, create_req,
73
                                   (request_rec *r, request_rec *pr), (r, pr),
72
                                   (request_rec *r, request_rec *pr), (r, pr),
Lines 1293-1339 Link Here
1293
    return APR_SUCCESS;
1292
    return APR_SUCCESS;
1294
}
1293
}
1295
1294
1296
PROXY_DECLARE(apr_array_header_t *) ap_proxy_balancer_usable_workers(proxy_balancer *balancer,
1295
PROXY_DECLARE(proxy_worker *) ap_proxy_balancer_get_best_worker(proxy_balancer *balancer,
1297
                                                                     request_rec *r,
1296
                                                                request_rec *r,
1298
                                                                     apr_pool_t *p)
1297
                                                                proxy_is_best_callback_fn_t *is_best,
1298
                                                                void *baton)
1299
{
1299
{
1300
    int i = 0;
1300
    int i = 0;
1301
    int cur_lbset = 0;
1301
    int cur_lbset = 0;
1302
    int max_lbset = 0;
1302
    int max_lbset = 0;
1303
    int unusable_workers = 0;
1303
    int unusable_workers = 0;
1304
    apr_array_header_t *workers;
1304
    apr_pool_t *tpool = NULL;
1305
    apr_array_header_t *spares;
1305
    apr_array_header_t *spares = NULL;
1306
    apr_array_header_t *standbys;
1306
    apr_array_header_t *standbys = NULL;
1307
    proxy_worker **worker;
1307
    proxy_worker *worker = NULL;
1308
    proxy_worker *best_worker = NULL;
1308
1309
1309
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(10033)
1310
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(10033)
1310
                 "proxy: Entering %s for BALANCER (%s)",
1311
                 "proxy: Entering %s for BALANCER (%s)",
1311
                 balancer->lbmethod->name, balancer->s->name);
1312
                 balancer->lbmethod->name, balancer->s->name);
1312
1313
1313
    workers = apr_array_make(p, balancer->workers->nelts, sizeof(proxy_worker*));
1314
    apr_pool_create(&tpool, r->pool);
1314
    spares = apr_array_make(p, 1, sizeof(proxy_worker*));
1315
1315
    standbys = apr_array_make(p, 1, sizeof(proxy_worker*));
1316
    spares = apr_array_make(tpool, 1, sizeof(proxy_worker*));
1317
    standbys = apr_array_make(tpool, 1, sizeof(proxy_worker*));
1316
1318
1317
    /* Process lbsets in order, only replacing unusable workers in a given lbset
1319
    /* Process lbsets in order, only replacing unusable workers in a given lbset
1318
     * with available spares from the same lbset. Hot standbys will be used as a
1320
     * with available spares from the same lbset. Hot standbys will be used as a
1319
     * last resort when all other workers and spares are unavailable.
1321
     * last resort when all other workers and spares are unavailable.
1320
     */
1322
     */
1321
    for (cur_lbset = 0; (workers->nelts == 0) && (cur_lbset <= max_lbset); cur_lbset++) {
1323
    for (cur_lbset = 0; !best_worker && (cur_lbset <= max_lbset); cur_lbset++) {
1322
        unusable_workers = 0;
1324
        unusable_workers = 0;
1323
        apr_array_clear(spares);
1325
        apr_array_clear(spares);
1324
        apr_array_clear(standbys);
1326
        apr_array_clear(standbys);
1325
1327
1326
        for (i = 0; i < balancer->workers->nelts; i++, worker++) {
1328
        for (i = 0; i < balancer->workers->nelts; i++) {
1327
            worker = &APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
1329
            worker = APR_ARRAY_IDX(balancer->workers, i, proxy_worker *);
1328
1330
1329
            if ((*worker)->s->lbset > max_lbset) {
1331
            if (worker->s->lbset > max_lbset) {
1330
                max_lbset = (*worker)->s->lbset;
1332
                max_lbset = worker->s->lbset;
1331
            }
1333
            }
1332
1334
1333
            if (
1335
            if (worker->s->lbset != cur_lbset) {
1334
                ((*worker)->s->lbset != cur_lbset)
1336
                continue;
1335
                || PROXY_WORKER_IS_DRAINING(*worker)
1337
            }
1336
            ) {
1338
1339
            /* A draining worker that is neither a spare nor a standby should be
1340
             * considered unusable to be replaced by spares.
1341
             */
1342
            if (PROXY_WORKER_IS_DRAINING(worker)) {
1343
                if (!PROXY_WORKER_IS_SPARE(worker) && !PROXY_WORKER_IS_STANDBY(worker)) {
1344
                    unusable_workers++;
1345
                }
1346
1337
                continue;
1347
                continue;
1338
            }
1348
            }
1339
1349
Lines 1341-1384 Link Here
1341
             * be marked as operational if the retry timeout is elapsed.  The
1351
             * be marked as operational if the retry timeout is elapsed.  The
1342
             * worker might still be unusable, but we try anyway.
1352
             * worker might still be unusable, but we try anyway.
1343
             */
1353
             */
1344
            if (!PROXY_WORKER_IS_USABLE(*worker)) {
1354
            if (!PROXY_WORKER_IS_USABLE(worker)) {
1345
                ap_proxy_retry_worker("BALANCER", *worker, r->server);
1355
                ap_proxy_retry_worker("BALANCER", worker, r->server);
1346
            }
1356
            }
1347
1357
1348
            if (PROXY_WORKER_IS_SPARE(*worker)) {
1358
            if (PROXY_WORKER_IS_SPARE(worker)) {
1349
                if (PROXY_WORKER_IS_USABLE(*worker)) {
1359
                if (PROXY_WORKER_IS_USABLE(worker)) {
1350
                    APR_ARRAY_PUSH(spares, proxy_worker *) = *worker;
1360
                    APR_ARRAY_PUSH(spares, proxy_worker *) = worker;
1351
                }
1361
                }
1352
            }
1362
            }
1353
            else if (PROXY_WORKER_IS_STANDBY(*worker)) {
1363
            else if (PROXY_WORKER_IS_STANDBY(worker)) {
1354
                if (PROXY_WORKER_IS_USABLE(*worker)) {
1364
                if (PROXY_WORKER_IS_USABLE(worker)) {
1355
                    APR_ARRAY_PUSH(standbys, proxy_worker *) = *worker;
1365
                    APR_ARRAY_PUSH(standbys, proxy_worker *) = worker;
1356
                }
1366
                }
1357
            }
1367
            }
1358
            else if (PROXY_WORKER_IS_USABLE(*worker)) {
1368
            else if (PROXY_WORKER_IS_USABLE(worker)) {
1359
                APR_ARRAY_PUSH(workers, proxy_worker *) = *worker;
1369
              if (is_best(worker, best_worker, baton)) {
1370
                best_worker = worker;
1371
              }
1360
            }
1372
            }
1361
            else {
1373
            else {
1362
                unusable_workers++;
1374
                unusable_workers++;
1363
            }
1375
            }
1364
        }
1376
        }
1365
1377
1366
        /* Replace any unusable workers with any available spares. */
1378
        /* Check if any spares are best. */
1367
        if (spares->nelts > 0) {
1379
        for (i = 0; (i < spares->nelts) && (i < unusable_workers); i++) {
1368
            if (spares->nelts > unusable_workers) {
1380
          worker = APR_ARRAY_IDX(spares, i, proxy_worker *);
1369
                spares->nelts = unusable_workers;
1381
1370
            }
1382
          if (is_best(worker, best_worker, baton)) {
1371
1383
            best_worker = worker;
1372
            apr_array_cat(workers, spares);
1384
          }
1373
        }
1385
        }
1374
1386
1375
        /* If no workers are available, use the standbys. */
1387
        /* If no workers are available, use the standbys. */
1376
        if ((workers->nelts == 0) && (standbys->nelts > 0)) {
1388
        if (!best_worker) {
1377
            apr_array_cat(workers, standbys);
1389
            for (i = 0; i < standbys->nelts; i++) {
1390
              worker = APR_ARRAY_IDX(standbys, i, proxy_worker *);
1391
1392
              if (is_best(worker, best_worker, baton)) {
1393
                best_worker = worker;
1394
              }
1395
            }
1378
        }
1396
        }
1379
    }
1397
    }
1380
1398
1381
    return workers;
1399
    apr_pool_destroy(tpool);
1400
1401
    if (best_worker) {
1402
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(10034)
1403
                     "proxy: %s selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d",
1404
                     balancer->lbmethod->name, best_worker->s->name, best_worker->s->busy, best_worker->s->lbstatus);
1405
    }
1406
1407
    return best_worker;
1382
}
1408
}
1383
1409
1384
/*
1410
/*

Return to bug 61140