]> granicus.if.org Git - apache/blob - modules/proxy/balancers/mod_lbmethod_bybusyness.c
2b3124e25c830bc5ca5fcc4b4a6b7040ae6d7e78
[apache] / modules / proxy / balancers / mod_lbmethod_bybusyness.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "mod_proxy.h"
18 #include "scoreboard.h"
19 #include "ap_mpm.h"
20 #include "apr_version.h"
21 #include "ap_hooks.h"
22
23 module AP_MODULE_DECLARE_DATA lbmethod_bybusyness_module;
24
25 static int (*ap_proxy_retry_worker_fn)(const char *proxy_function,
26         proxy_worker *worker, server_rec *s) = NULL;
27
28 static proxy_worker *find_best_bybusyness(proxy_balancer *balancer,
29                                 request_rec *r)
30 {
31
32     int i;
33     proxy_worker **worker;
34     proxy_worker *mycandidate = NULL;
35     int cur_lbset = 0;
36     int max_lbset = 0;
37     int checking_standby;
38     int checked_standby;
39
40     int total_factor = 0;
41
42     if (!ap_proxy_retry_worker_fn) {
43         ap_proxy_retry_worker_fn =
44                 APR_RETRIEVE_OPTIONAL_FN(ap_proxy_retry_worker);
45         if (!ap_proxy_retry_worker_fn) {
46             /* can only happen if mod_proxy isn't loaded */
47             return NULL;
48         }
49     }
50
51     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
52                  "proxy: Entering bybusyness for BALANCER (%s)",
53                  balancer->s->name);
54
55     /* First try to see if we have available candidate */
56     do {
57
58         checking_standby = checked_standby = 0;
59         while (!mycandidate && !checked_standby) {
60
61             worker = (proxy_worker **)balancer->workers->elts;
62             for (i = 0; i < balancer->workers->nelts; i++, worker++) {
63                 if  (!checking_standby) {    /* first time through */
64                     if ((*worker)->s->lbset > max_lbset)
65                         max_lbset = (*worker)->s->lbset;
66                 }
67                 if (
68                     ((*worker)->s->lbset != cur_lbset) ||
69                     (checking_standby ? !PROXY_WORKER_IS_STANDBY(*worker) : PROXY_WORKER_IS_STANDBY(*worker)) ||
70                     (PROXY_WORKER_IS_DRAINING(*worker))
71                     ) {
72                     continue;
73                 }
74
75                 /* If the worker is in error state run
76                  * retry on that worker. It will be marked as
77                  * operational if the retry timeout is elapsed.
78                  * The worker might still be unusable, but we try
79                  * anyway.
80                  */
81                 if (!PROXY_WORKER_IS_USABLE(*worker)) {
82                     ap_proxy_retry_worker_fn("BALANCER", *worker, r->server);
83                 }
84
85                 /* Take into calculation only the workers that are
86                  * not in error state or not disabled.
87                  */
88                 if (PROXY_WORKER_IS_USABLE(*worker)) {
89
90                     (*worker)->s->lbstatus += (*worker)->s->lbfactor;
91                     total_factor += (*worker)->s->lbfactor;
92
93                     if (!mycandidate
94                         || (*worker)->s->busy < mycandidate->s->busy
95                         || ((*worker)->s->busy == mycandidate->s->busy && (*worker)->s->lbstatus > mycandidate->s->lbstatus))
96                         mycandidate = *worker;
97
98                 }
99
100             }
101
102             checked_standby = checking_standby++;
103
104         }
105
106         cur_lbset++;
107
108     } while (cur_lbset <= max_lbset && !mycandidate);
109
110     if (mycandidate) {
111         mycandidate->s->lbstatus -= total_factor;
112         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
113                      "proxy: bybusyness selected worker \"%s\" : busy %" APR_SIZE_T_FMT " : lbstatus %d",
114                      mycandidate->s->name, mycandidate->s->busy, mycandidate->s->lbstatus);
115
116     }
117
118     return mycandidate;
119
120 }
121
122 /* assumed to be mutex protected by caller */
123 static apr_status_t reset(proxy_balancer *balancer, server_rec *s) {
124     int i;
125     proxy_worker **worker;
126     worker = (proxy_worker **)balancer->workers->elts;
127     for (i = 0; i < balancer->workers->nelts; i++, worker++) {
128         (*worker)->s->lbstatus = 0;
129         (*worker)->s->busy = 0;
130     }
131     return APR_SUCCESS;
132 }
133
134 static apr_status_t age(proxy_balancer *balancer, server_rec *s) {
135         return APR_SUCCESS;
136 }
137
138 static const proxy_balancer_method bybusyness =
139 {
140     "bybusyness",
141     &find_best_bybusyness,
142     NULL,
143     &reset,
144     &age
145 };
146
147
148 static void register_hook(apr_pool_t *p)
149 {
150     ap_register_provider(p, PROXY_LBMETHOD, "bybusyness", "0", &bybusyness);
151 }
152
153 AP_DECLARE_MODULE(lbmethod_bybusyness) = {
154     STANDARD20_MODULE_STUFF,
155     NULL,       /* create per-directory config structure */
156     NULL,       /* merge per-directory config structures */
157     NULL,       /* create per-server config structure */
158     NULL,       /* merge per-server config structures */
159     NULL,       /* command apr_table_t */
160     register_hook /* register hooks */
161 };