bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / tomcat-connectors-1.2.32-src / native / common / jk_worker.c
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 /***************************************************************************
19  * Description: Workers controller                                         *
20  * Author:      Gal Shachor <shachor@il.ibm.com>                           *
21  * Author:      Henri Gomez <hgomez@apache.org>                            *
22  * Version:     $Revision: 708019 $                                          *
23  ***************************************************************************/
24
25 #define _PLACE_WORKER_LIST_HERE
26 #include "jk_worker_list.h"
27 #include "jk_worker.h"
28 #include "jk_util.h"
29 #include "jk_mt.h"
30
31 static void close_workers(jk_logger_t *l);
32
33 static worker_factory get_factory_for(const char *type);
34
35 static int build_worker_map(jk_map_t *init_data,
36                             char **worker_list,
37                             unsigned num_of_workers,
38                             jk_worker_env_t *we, jk_logger_t *l);
39
40 /* Global worker list */
41 static jk_map_t *worker_map;
42 #if _MT_CODE
43 static JK_CRIT_SEC worker_lock;
44 #endif
45 static int worker_maintain_time = 0;
46
47 int wc_open(jk_map_t *init_data, jk_worker_env_t *we, jk_logger_t *l)
48 {
49     int rc;
50     JK_TRACE_ENTER(l);
51
52     if (!jk_map_alloc(&worker_map)) {
53         JK_TRACE_EXIT(l);
54         return JK_FALSE;
55     }
56     JK_INIT_CS(&worker_lock, rc);
57     if (rc == JK_FALSE) {
58         jk_log(l, JK_LOG_ERROR,
59                 "creating thread lock (errno=%d)",
60                 errno);
61         JK_TRACE_EXIT(l);
62         return JK_FALSE;
63     }
64
65     jk_map_dump(init_data, l);
66     we->init_data = init_data;
67     if (!jk_get_worker_list(init_data, &(we->worker_list),
68                             &we->num_of_workers)) {
69         JK_TRACE_EXIT(l);
70         we->num_of_workers = 0;
71         we->worker_list = NULL;
72         return JK_FALSE;
73     }
74
75     worker_maintain_time = jk_get_worker_maintain_time(init_data);
76     if(worker_maintain_time < 0)
77         worker_maintain_time = 0;
78
79     if (!build_worker_map(init_data, we->worker_list,
80                           we->num_of_workers, we, l)) {
81         close_workers(l);
82         we->num_of_workers = 0;
83         we->worker_list = NULL;
84         JK_TRACE_EXIT(l);
85         return JK_FALSE;
86     }
87
88     JK_TRACE_EXIT(l);
89     return JK_TRUE;
90 }
91
92
93 void wc_close(jk_logger_t *l)
94 {
95     int rc;
96     JK_TRACE_ENTER(l);
97     JK_DELETE_CS(&worker_lock, rc);
98     close_workers(l);
99     JK_TRACE_EXIT(l);
100 }
101
102 jk_worker_t *wc_get_worker_for_name(const char *name, jk_logger_t *l)
103 {
104     jk_worker_t *rc;
105
106     JK_TRACE_ENTER(l);
107     if (!name) {
108         JK_LOG_NULL_PARAMS(l);
109         JK_TRACE_EXIT(l);
110         return NULL;
111     }
112
113     rc = jk_map_get(worker_map, name, NULL);
114
115     if (JK_IS_DEBUG_LEVEL(l))
116         jk_log(l, JK_LOG_DEBUG, "%s a worker %s",
117                rc ? "found" : "did not find", name);
118     JK_TRACE_EXIT(l);
119     return rc;
120 }
121
122 int wc_create_worker(const char *name, int use_map,
123                      jk_map_t *init_data,
124                      jk_worker_t **rc, jk_worker_env_t *we, jk_logger_t *l)
125 {
126     JK_TRACE_ENTER(l);
127
128     if (rc) {
129         const char *type = jk_get_worker_type(init_data, name);
130         worker_factory fac = get_factory_for(type);
131         jk_worker_t *w = NULL;
132         unsigned int i, num_of_maps;
133         char **map_names;
134         int wtype;
135
136         *rc = NULL;
137
138         if (!fac) {
139             jk_log(l, JK_LOG_ERROR, "Unknown worker type %s for worker %s",
140                    type, name);
141             JK_TRACE_EXIT(l);
142             return JK_FALSE;
143         }
144
145         if (JK_IS_DEBUG_LEVEL(l))
146             jk_log(l, JK_LOG_DEBUG,
147                    "about to create instance %s of %s", name,
148                    type);
149
150         if (((wtype = fac(&w, name, l)) == 0) || !w) {
151             jk_log(l, JK_LOG_ERROR,
152                    "factory for %s failed for %s", type,
153                    name);
154             JK_TRACE_EXIT(l);
155             return JK_FALSE;
156         }
157
158         if (JK_IS_DEBUG_LEVEL(l))
159             jk_log(l, JK_LOG_DEBUG,
160                    "about to validate and init %s", name);
161         if (!w->validate(w, init_data, we, l)) {
162             w->destroy(&w, l);
163             jk_log(l, JK_LOG_ERROR,
164                    "validate failed for %s", name);
165             JK_TRACE_EXIT(l);
166             return JK_FALSE;
167         }
168
169         if (!w->init(w, init_data, we, l)) {
170             w->destroy(&w, l);
171             jk_log(l, JK_LOG_ERROR, "init failed for %s",
172                    name);
173             JK_TRACE_EXIT(l);
174             return JK_FALSE;
175         }
176         if (use_map &&
177             jk_get_worker_mount_list(init_data, name,
178                                      &map_names,
179                                      &num_of_maps) && num_of_maps) {
180             for (i = 0; i < num_of_maps; i++) {
181                 if (JK_IS_DEBUG_LEVEL(l))
182                     jk_log(l, JK_LOG_DEBUG,
183                             "mounting %s to worker %s",
184                             map_names[i], name);
185                 if (uri_worker_map_add(we->uri_to_worker, map_names[i],
186                                        name, SOURCE_TYPE_WORKERDEF, l) == JK_FALSE) {
187                     w->destroy(&w, l);
188                     jk_log(l, JK_LOG_ERROR,
189                            "mounting %s failed for %s",
190                            map_names[i], name);
191                     JK_TRACE_EXIT(l);
192                     return JK_FALSE;
193                 }
194             }
195         }
196         w->type = wtype;
197         *rc = w;
198         JK_TRACE_EXIT(l);
199         return JK_TRUE;
200     }
201
202     JK_LOG_NULL_PARAMS(l);
203     return JK_FALSE;
204 }
205
206 static void close_workers(jk_logger_t *l)
207 {
208     int sz = jk_map_size(worker_map);
209
210     JK_TRACE_ENTER(l);
211
212     if (sz > 0) {
213         int i;
214         for (i = 0; i < sz; i++) {
215             jk_worker_t *w = jk_map_value_at(worker_map, i);
216             if (w) {
217                 if (JK_IS_DEBUG_LEVEL(l))
218                     jk_log(l, JK_LOG_DEBUG,
219                            "close_workers will destroy worker %s",
220                            jk_map_name_at(worker_map, i));
221                 w->destroy(&w, l);
222             }
223         }
224     }
225     jk_map_free(&worker_map);
226     JK_TRACE_EXIT(l);
227 }
228
229 static int build_worker_map(jk_map_t *init_data,
230                             char **worker_list,
231                             unsigned num_of_workers,
232                             jk_worker_env_t *we, jk_logger_t *l)
233 {
234     unsigned i;
235
236     JK_TRACE_ENTER(l);
237
238     for (i = 0; i < num_of_workers; i++) {
239         jk_worker_t *w = NULL;
240
241         if (JK_IS_DEBUG_LEVEL(l))
242             jk_log(l, JK_LOG_DEBUG,
243                    "creating worker %s", worker_list[i]);
244
245         if (wc_create_worker(worker_list[i], 1, init_data, &w, we, l)) {
246             jk_worker_t *oldw = NULL;
247             if (!jk_map_put(worker_map, worker_list[i], w, (void *)&oldw)) {
248                 w->destroy(&w, l);
249                 JK_TRACE_EXIT(l);
250                 return JK_FALSE;
251             }
252
253             if (oldw) {
254                 if (JK_IS_DEBUG_LEVEL(l))
255                     jk_log(l, JK_LOG_DEBUG,
256                            "removing old %s worker",
257                            worker_list[i]);
258                 oldw->destroy(&oldw, l);
259             }
260         }
261         else {
262             jk_log(l, JK_LOG_ERROR,
263                    "failed to create worker %s",
264                    worker_list[i]);
265             JK_TRACE_EXIT(l);
266             return JK_FALSE;
267         }
268     }
269
270     JK_TRACE_EXIT(l);
271     return JK_TRUE;
272 }
273
274 static worker_factory get_factory_for(const char *type)
275 {
276     worker_factory_record_t *factory = &worker_factories[0];
277     while (factory->name) {
278         if (0 == strcmp(factory->name, type)) {
279             return factory->fac;
280         }
281
282         factory++;
283     }
284
285     return NULL;
286 }
287
288 const char *wc_get_name_for_type(int type, jk_logger_t *l)
289 {
290     worker_factory_record_t *factory = &worker_factories[0];
291     while (factory->name) {
292         if (type == factory->type) {
293             jk_log(l, JK_LOG_DEBUG,
294                    "Found worker type '%s'",
295                    factory->name);
296             return factory->name;
297         }
298
299         factory++;
300     }
301
302     return NULL;
303 }
304
305 void wc_maintain(jk_logger_t *l)
306 {
307     static time_t last_maintain = 0;
308     static int    running_maintain = 0;
309     int sz = jk_map_size(worker_map);
310
311     JK_TRACE_ENTER(l);
312
313     /* Only proceed if all of the below hold true:
314      * - there are workers
315      * - maintenance wasn't disabled by configuration
316      * - time since last maintenance is big enough
317      */
318     if (sz > 0 && worker_maintain_time > 0 &&
319         difftime(time(NULL), last_maintain) >= worker_maintain_time) {
320         int i;
321         JK_ENTER_CS(&worker_lock, i);
322         if (running_maintain ||
323             difftime(time(NULL), last_maintain) < worker_maintain_time) {
324             /* Already in maintain */
325             JK_LEAVE_CS(&worker_lock, i);
326             JK_TRACE_EXIT(l);
327             return;
328         }
329         /* Set the maintain run flag so other threads skip
330          * the maintain until we are finished.
331          */
332         running_maintain = 1;
333         JK_LEAVE_CS(&worker_lock, i);
334
335         for (i = 0; i < sz; i++) {
336             jk_worker_t *w = jk_map_value_at(worker_map, i);
337             if (w && w->maintain) {
338                 if (JK_IS_DEBUG_LEVEL(l))
339                     jk_log(l, JK_LOG_DEBUG,
340                            "Maintaining worker %s",
341                            jk_map_name_at(worker_map, i));
342                 w->maintain(w, time(NULL), l);
343             }
344         }
345         JK_ENTER_CS(&worker_lock, i);
346         last_maintain = time(NULL);
347         running_maintain = 0;
348         JK_LEAVE_CS(&worker_lock, i);
349     }
350     JK_TRACE_EXIT(l);
351 }