| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * 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. |
| */ |
| |
| /*************************************************************************** |
| * Description: Workers controller * |
| * Author: Gal Shachor <shachor@il.ibm.com> * |
| * Author: Henri Gomez <hgomez@apache.org> * |
| * Version: $Revision$ * |
| ***************************************************************************/ |
| |
| #define _PLACE_WORKER_LIST_HERE |
| #include "jk_worker_list.h" |
| #include "jk_worker.h" |
| #include "jk_util.h" |
| #include "jk_mt.h" |
| |
| static void close_workers(jk_logger_t *l); |
| |
| static worker_factory get_factory_for(const char *type); |
| |
| static int build_worker_map(jk_map_t *init_data, |
| char **worker_list, |
| unsigned num_of_workers, |
| jk_worker_env_t *we, jk_logger_t *l); |
| |
| /* Global worker list */ |
| static jk_map_t *worker_map; |
| #if _MT_CODE |
| static JK_CRIT_SEC worker_lock; |
| #endif |
| static int worker_maintain_time = 0; |
| |
| int wc_open(jk_map_t *init_data, jk_worker_env_t *we, jk_logger_t *l) |
| { |
| int rc; |
| JK_TRACE_ENTER(l); |
| |
| if (!jk_map_alloc(&worker_map)) { |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| JK_INIT_CS(&worker_lock, rc); |
| if (rc == JK_FALSE) { |
| jk_log(l, JK_LOG_ERROR, |
| "creating thread lock (errno=%d)", |
| errno); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| jk_map_dump(init_data, l); |
| we->init_data = init_data; |
| if (!jk_get_worker_list(init_data, &(we->worker_list), |
| &we->num_of_workers)) { |
| JK_TRACE_EXIT(l); |
| we->num_of_workers = 0; |
| we->worker_list = NULL; |
| return JK_FALSE; |
| } |
| |
| worker_maintain_time = jk_get_worker_maintain_time(init_data); |
| if(worker_maintain_time < 0) |
| worker_maintain_time = 0; |
| |
| if (!build_worker_map(init_data, we->worker_list, |
| we->num_of_workers, we, l)) { |
| close_workers(l); |
| we->num_of_workers = 0; |
| we->worker_list = NULL; |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| |
| void wc_close(jk_logger_t *l) |
| { |
| int rc; |
| JK_TRACE_ENTER(l); |
| JK_DELETE_CS(&worker_lock, rc); |
| close_workers(l); |
| JK_TRACE_EXIT(l); |
| } |
| |
| jk_worker_t *wc_get_worker_for_name(const char *name, jk_logger_t *l) |
| { |
| jk_worker_t *rc; |
| |
| JK_TRACE_ENTER(l); |
| if (!name) { |
| JK_LOG_NULL_PARAMS(l); |
| JK_TRACE_EXIT(l); |
| return NULL; |
| } |
| |
| rc = jk_map_get(worker_map, name, NULL); |
| |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, "%s a worker %s", |
| rc ? "found" : "did not find", name); |
| JK_TRACE_EXIT(l); |
| return rc; |
| } |
| |
| int wc_create_worker(const char *name, int use_map, |
| jk_map_t *init_data, |
| jk_worker_t **rc, jk_worker_env_t *we, jk_logger_t *l) |
| { |
| JK_TRACE_ENTER(l); |
| |
| if (rc) { |
| const char *type = jk_get_worker_type(init_data, name); |
| worker_factory fac = get_factory_for(type); |
| jk_worker_t *w = NULL; |
| unsigned int i, num_of_maps; |
| char **map_names; |
| int wtype; |
| |
| *rc = NULL; |
| |
| if (!fac) { |
| jk_log(l, JK_LOG_ERROR, "Unknown worker type %s for worker %s", |
| type, name); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, |
| "about to create instance %s of %s", name, |
| type); |
| |
| if (((wtype = fac(&w, name, l)) == 0) || !w) { |
| jk_log(l, JK_LOG_ERROR, |
| "factory for %s failed for %s", type, |
| name); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, |
| "about to validate and init %s", name); |
| if (!w->validate(w, init_data, we, l)) { |
| w->destroy(&w, l); |
| jk_log(l, JK_LOG_ERROR, |
| "validate failed for %s", name); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| if (!w->init(w, init_data, we, l)) { |
| w->destroy(&w, l); |
| jk_log(l, JK_LOG_ERROR, "init failed for %s", |
| name); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| if (use_map && |
| jk_get_worker_mount_list(init_data, name, |
| &map_names, |
| &num_of_maps) && num_of_maps) { |
| for (i = 0; i < num_of_maps; i++) { |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, |
| "mounting %s to worker %s", |
| map_names[i], name); |
| if (uri_worker_map_add(we->uri_to_worker, map_names[i], |
| name, SOURCE_TYPE_WORKERDEF, l) == JK_FALSE) { |
| w->destroy(&w, l); |
| jk_log(l, JK_LOG_ERROR, |
| "mounting %s failed for %s", |
| map_names[i], name); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| } |
| } |
| w->type = wtype; |
| *rc = w; |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| JK_LOG_NULL_PARAMS(l); |
| return JK_FALSE; |
| } |
| |
| static void close_workers(jk_logger_t *l) |
| { |
| int sz = jk_map_size(worker_map); |
| |
| JK_TRACE_ENTER(l); |
| |
| if (sz > 0) { |
| int i; |
| for (i = 0; i < sz; i++) { |
| jk_worker_t *w = jk_map_value_at(worker_map, i); |
| if (w) { |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, |
| "close_workers will destroy worker %s", |
| jk_map_name_at(worker_map, i)); |
| w->destroy(&w, l); |
| } |
| } |
| } |
| jk_map_free(&worker_map); |
| JK_TRACE_EXIT(l); |
| } |
| |
| static int build_worker_map(jk_map_t *init_data, |
| char **worker_list, |
| unsigned num_of_workers, |
| jk_worker_env_t *we, jk_logger_t *l) |
| { |
| unsigned i; |
| |
| JK_TRACE_ENTER(l); |
| |
| for (i = 0; i < num_of_workers; i++) { |
| jk_worker_t *w = NULL; |
| |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, |
| "creating worker %s", worker_list[i]); |
| |
| if (wc_create_worker(worker_list[i], 1, init_data, &w, we, l)) { |
| jk_worker_t *oldw = NULL; |
| if (!jk_map_put(worker_map, worker_list[i], w, (void *)&oldw)) { |
| w->destroy(&w, l); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| |
| if (oldw) { |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, |
| "removing old %s worker", |
| worker_list[i]); |
| oldw->destroy(&oldw, l); |
| } |
| } |
| else { |
| jk_log(l, JK_LOG_ERROR, |
| "failed to create worker %s", |
| worker_list[i]); |
| JK_TRACE_EXIT(l); |
| return JK_FALSE; |
| } |
| } |
| |
| JK_TRACE_EXIT(l); |
| return JK_TRUE; |
| } |
| |
| static worker_factory get_factory_for(const char *type) |
| { |
| worker_factory_record_t *factory = &worker_factories[0]; |
| while (factory->name) { |
| if (0 == strcmp(factory->name, type)) { |
| return factory->fac; |
| } |
| |
| factory++; |
| } |
| |
| return NULL; |
| } |
| |
| const char *wc_get_name_for_type(int type, jk_logger_t *l) |
| { |
| worker_factory_record_t *factory = &worker_factories[0]; |
| while (factory->name) { |
| if (type == factory->type) { |
| jk_log(l, JK_LOG_DEBUG, |
| "Found worker type '%s'", |
| factory->name); |
| return factory->name; |
| } |
| |
| factory++; |
| } |
| |
| return NULL; |
| } |
| |
| void wc_maintain(jk_logger_t *l) |
| { |
| static time_t last_maintain = 0; |
| int sz = jk_map_size(worker_map); |
| |
| JK_TRACE_ENTER(l); |
| |
| if (sz > 0 && worker_maintain_time > 0) { |
| int i; |
| time_t now; |
| JK_ENTER_CS(&worker_lock, i); |
| now = time(NULL); |
| if (difftime(now, last_maintain) >= worker_maintain_time) { |
| last_maintain = now; |
| JK_LEAVE_CS(&worker_lock, i); |
| for (i = 0; i < sz; i++) { |
| jk_worker_t *w = jk_map_value_at(worker_map, i); |
| if (w && w->maintain) { |
| if (JK_IS_DEBUG_LEVEL(l)) |
| jk_log(l, JK_LOG_DEBUG, |
| "Maintaining worker %s", |
| jk_map_name_at(worker_map, i)); |
| w->maintain(w, now, l); |
| } |
| } |
| } |
| else { |
| JK_LEAVE_CS(&worker_lock, i); |
| } |
| } |
| JK_TRACE_EXIT(l); |
| } |