blob: 2ce9a54bec4077cc8ff810e0ce69b823d6944394 [file] [log] [blame]
/*
* 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);
}