costin 02/05/14 10:12:45 Modified: jk/native2/common jk_config.c Log: Implement config reloading. IMORTANT: when the config file is reloaded we do process _only_ components with a 'ver' attribute that is newer than what we have. We will call all setters for that component - but that is not guaranteed to have any effect, as only few attributes are supported at runtime. We should be very conservative in what we allow reconfiguration for - it's dangerous to modify a running server, and adding sync can kill performance. In particular enabling/disabling workers is save, adding workers should be safe too. Adding uris at runtime is also possible. Changin lb_factors and other properties is possible. Revision Changes Path 1.16 +242 -81 jakarta-tomcat-connectors/jk/native2/common/jk_config.c Index: jk_config.c =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jk/native2/common/jk_config.c,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- jk_config.c 9 May 2002 21:00:53 -0000 1.15 +++ jk_config.c 14 May 2002 17:12:45 -0000 1.16 @@ -58,7 +58,7 @@ /*************************************************************************** * Description: General purpose config object * * Author: Gal Shachor <[EMAIL PROTECTED]> * - * Version: $Revision: 1.15 $ * + * Version: $Revision: 1.16 $ * ***************************************************************************/ #include "jk_global.h" @@ -69,9 +69,15 @@ #define CAPACITY_INC_SIZE (50) #define LENGTH_OF_LINE (1024) +int jk2_config_read(struct jk_env *env, struct jk_config *cfg, + struct jk_map *map); static void jk2_trim_prp_comment(char *prp); static int jk2_trim(char *s); +static int JK_METHOD jk2_config_readFile(jk_env_t *env, + jk_config_t *cfg, + int *didReload, int firstTime); + /* ==================== ==================== */ /* Set the config file, read it. The property will also be @@ -84,45 +90,13 @@ { struct stat statbuf; int err; - jk_map_t *props; + jk_map_t *cfgData; int i; + int j; - if (stat(workerFile, &statbuf) == -1) { - env->l->jkLog(env, env->l, JK_LOG_ERROR, - "config.setConfig(): Can't find config file %s", workerFile ); - return JK_ERR; - } - cfg->file=workerFile; - - /** Read worker files - */ - env->l->jkLog(env, env->l, JK_LOG_INFO, "config.setConfig(): Reading config %s %d\n", - workerFile, cfg->map->size(env, cfg->map) ); - - jk2_map_default_create(env, &props, wEnv->pool); - - err=jk2_config_read(env, cfg, props, workerFile ); - - if( err==JK_OK ) { - env->l->jkLog(env, env->l, JK_LOG_INFO, - "config.setConfig(): Reading properties %s %d\n", - workerFile, props->size( env, props ) ); - } else { - env->l->jkLog(env, env->l, JK_LOG_ERROR, - "config.setConfig(): Error reading properties %s\n", - workerFile ); - return JK_ERR; - } - for( i=0; i<props->size( env, props); i++ ) { - char *name=props->nameAt(env, props, i); - char *val=props->valueAt(env, props, i); - - cfg->setPropertyString( env, cfg, name, val ); - } - - return JK_OK; + return jk2_config_readFile( env, cfg, NULL, JK_TRUE ); } /* Experimental. Dangerous. The file param will go away, for security @@ -247,9 +221,12 @@ jk_bean_t *mbean, char *name, char *val) { char *pname; + int multiValue=JK_FALSE; + if( mbean == cfg->mbean ) { pname=name; } else { + /* Make substitution work for ${OBJ_NAME.PROP} */ pname=cfg->pool->calloc( env, cfg->pool, strlen( name ) + strlen( mbean->name ) + 4 ); strcpy( pname, mbean->name ); @@ -257,14 +234,32 @@ strcat( pname, name ); } - /* fprintf( stderr, "config.setProperty %s %s %s \n", mbean->name, name, val ); */ - + name= cfg->pool->pstrdup( env, cfg->pool, name ); + val= cfg->pool->pstrdup( env, cfg->pool, val ); + /** Save it on the config. XXX no support for deleting yet */ /* The _original_ value. Will be saved with $() in it */ if( mbean->settings == NULL ) jk2_map_default_create(env, &mbean->settings, cfg->pool); - mbean->settings->add( env, mbean->settings, name, val ); + if( mbean->multiValueInfo != NULL ) { + int i; + for( i=0; i<64; i++ ) { + if(mbean->multiValueInfo[i]== NULL) + break; + if( strcmp( name, mbean->multiValueInfo[i])==0 ) { + multiValue=JK_TRUE; + break; + } + } + } + + if( multiValue ) { + mbean->settings->add( env, mbean->settings, name, val ); + fprintf( stderr, "config.setProperty MULTI %s %s %s \n", mbean->name, name, val ); + } else { + mbean->settings->put( env, mbean->settings, name, val, NULL ); + } /* Call the 'active' setter */ @@ -274,7 +269,11 @@ /** Used for future replacements */ - cfg->map->add( env, cfg->map, pname, val ); + if( multiValue ) { + cfg->map->add( env, cfg->map, pname, val ); + } else { + cfg->map->put( env, cfg->map, pname, val, NULL ); + } /* env->l->jkLog( env, env->l, JK_LOG_INFO, "config: set %s / %s / %s=%s\n", */ /* mbean->name, name, pname, val); */ @@ -345,10 +344,6 @@ return status; } - if( strncmp( objName, "disabled:", 9) == 0 ) { - return JK_OK; - } - /** Replace properties in the object name */ objName = jk2_config_replaceProperties(env, cfg->map, cfg->map->pool, objName); @@ -372,11 +367,13 @@ /* ==================== */ -/* Reading / parsing */ +/* Reading / parsing. + */ int jk2_config_parseProperty(jk_env_t *env, jk_config_t *cfg, jk_map_t *m, char *prp ) { int rc = JK_ERR; char *v; + jk_map_t *prefNode=NULL; jk2_trim_prp_comment(prp); @@ -391,12 +388,12 @@ *v='\0'; jk2_trim( v ); prp++; - cfg->section=cfg->pool->pstrdup(env, cfg->pool, prp); - /* Add a dummy property, so the object will be created */ - dummyProp=cfg->pool->calloc( env, cfg->pool, strlen( prp ) + 7 ); - strcpy(dummyProp, prp ); - strcat( dummyProp, ".name"); - m->add( env, m, dummyProp, cfg->section); + + cfg->section=cfg->pool->pstrdup(env, m->pool, prp); + + jk2_map_default_create( env, &prefNode, m->pool ); + + m->add( env, m, cfg->section, prefNode); return JK_OK; } @@ -407,33 +404,18 @@ *v = '\0'; v++; - + if(strlen(v)==0 || strlen(prp)==0) return JK_OK; - /* [ ] Shortcut */ - if( cfg->section != NULL ) { - char *newN=cfg->pool->calloc( env, cfg->pool, strlen( prp ) + strlen( cfg->section ) + 4 ); - strcpy( newN, cfg->section ); - strcat( newN, "." ); - strcat( newN, prp ); - prp=newN; - } - + prefNode=m->get( env, m, cfg->section); - /* Don't replace now - the caller may want to - save the file, and it'll replace them anyway for runtime changes - v = jk2_config_replaceProperties(env, cfg->map, cfg->pool, v); */ - - /* We don't contatenate the values - but use multi-value - fields. This eliminates the ugly hack where readProperties - tried to 'guess' the separator, and the code is much - cleaner. If we have multi-valued props, it's better - to deal with that instead of forcing a single-valued - model. - */ - m->add( env, m, cfg->pool->pstrdup(env, cfg->pool, prp), - cfg->pool->pstrdup(env, cfg->pool, v)); + if( prefNode==NULL ) + return JK_ERR; + + /* fprintf(stderr, "Adding [%s] %s=%s\n", cfg->section, prp, v ); */ + prefNode->add( env, prefNode, m->pool->pstrdup(env, m->pool, prp), + m->pool->pstrdup(env, m->pool, v)); return JK_OK; } @@ -466,13 +448,15 @@ } return JK_OK; } - -int jk2_config_read(jk_env_t *env, jk_config_t *cfg, jk_map_t *m, const char *f) + +/** Read the config file + */ +int jk2_config_read(jk_env_t *env, jk_config_t *cfg, jk_map_t *m) { FILE *fp; char buf[LENGTH_OF_LINE + 1]; char *prp; -// char *v; + char *f=cfg->file; if(m==NULL || f==NULL ) return JK_ERR; @@ -504,7 +488,7 @@ char *rc; char *env_start; int rec = 0; - + int didReplace=JK_FALSE; rc = value; env_start = value; @@ -525,8 +509,9 @@ if(env_value != NULL ) { int offset=0; - char *new_value = resultPool->calloc(env, resultPool, - (strlen(rc) + strlen(env_value))); + /* tmp allocations in tmpPool */ + char *new_value = env->tmpPool->calloc(env, env->tmpPool, + (strlen(rc) + strlen(env_value))); if(!new_value) { break; } @@ -542,7 +527,8 @@ offset= env_start - rc + strlen( env_value ); rc = new_value; /* Avoid recursive subst */ - env_start = rc + offset; + env_start = rc + offset; + didReplace=JK_TRUE; } else { env_start = env_end; } @@ -550,11 +536,174 @@ break; } } + + if( didReplace && resultPool!=NULL && resultPool != env->tmpPool ) { + /* Make sure the result is allocated in the right mempool. + tmpPool will be reset for each request. + */ + rc=resultPool->pstrdup( env, resultPool, rc ); + } + + return rc; +} + +/* -------------------- Reconfiguration -------------------- */ + +/** cfgData has component names as keys and a map of attributes as value. + * We'll create the beans and call the setters. + * If this is not firstTime, we create new componens and modify those + * with a lower 'ver'. + * + * Note that _no_ object can be ever destroyed. You can 'disable' them, + * but _never_ remove/destroy it. We work in a multithreaded environment, + * and any removal may have disastrous consequences. Using critical + * sections would drastically affect the performance. + */ +static int jk2_config_processConfigData(jk_env_t *env, jk_config_t *cfg, + jk_map_t *cfgData, int firstTime ) +{ + int rc; + int i; + int j; + + for( i=0; i<cfgData->size( env, cfgData ); i++ ) { + char *name=cfgData->nameAt(env, cfgData, i); + jk_map_t *prefNode=cfgData->valueAt(env, cfgData, i); + jk_bean_t *bean; + int ver; + char *verString; + + bean=env->getBean( env, name ); + if( bean==NULL ) { + if( cfg->mbean->debug > 0 ) { + env->l->jkLog(env, env->l, JK_LOG_INFO, + "config.setConfig(): Creating %s\n", name ); + } + bean=env->createBean( env, cfg->pool, name ); + } + + if( bean == NULL ) { + /* Can't create it, save the value in our map */ + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "config.update(): Can't create %s\n", name ); + continue; + } + + verString= prefNode->get( env, prefNode, "ver" ); + if( !firstTime ) { + if( verString == NULL ) continue; + + ver=atoi( verString ); + + if( ver <= bean->ver) { + /* Object didn't change + */ + continue; + } + } + + if( !firstTime ) + env->l->jkLog(env, env->l, JK_LOG_INFO, + "config.update(): Updating %s\n", name ); + + /* XXX Maybe we shoud destroy/init ? */ + + for( j=0; j<prefNode->size( env, prefNode ); j++ ) { + char *pname=prefNode->nameAt(env, prefNode, j); + char *pvalue=prefNode->valueAt(env, prefNode, j); + + cfg->setProperty( env, cfg, bean, pname, pvalue ); + } + } + + return JK_OK; +} + +static int jk2_config_readFile(jk_env_t *env, + jk_config_t *cfg, + int *didReload, int firstTime) +{ + int rc; + struct stat statbuf; + time_t mtime; + jk_map_t *cfgData; + + if( didReload!=NULL ) + *didReload=JK_FALSE; + + if( cfg->file==NULL ) + return JK_ERR; + + rc=stat(cfg->file, &statbuf); + if (rc == -1) { + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "config.update(): Can't find config file %s", cfg->file ); + return JK_ERR; + } + + if( statbuf.st_mtime < cfg->mtime ) + return JK_OK; + + JK_ENTER_CS(&cfg->cs, rc); + + if(rc !=JK_TRUE) { + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "cfg.update() Can't enter critical section\n"); + return JK_ERR; + } + /* Check if another thread has updated the config */ + + rc=stat(cfg->file, &statbuf); + if (rc == -1) { + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "config.update(): Can't find config file %s", cfg->file ); + JK_LEAVE_CS(&cfg->cs, rc); + return JK_ERR; + } + + if( statbuf.st_mtime <= cfg->mtime ) { + JK_LEAVE_CS(&cfg->cs, rc); + return JK_OK; + } + + env->l->jkLog(env, env->l, JK_LOG_INFO, + "cfg.update() Updating config %s %d %d\n", + cfg->file, cfg->mtime, statbuf.st_mtime); + + jk2_map_default_create(env, &cfgData, env->tmpPool); + + rc=jk2_config_read(env, cfg, cfgData ); + + if( rc==JK_OK ) { + env->l->jkLog(env, env->l, JK_LOG_INFO, + "config.setConfig(): Reading properties %s %d\n", + cfg->file, cfgData->size( env, cfgData ) ); + } else { + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "config.setConfig(): Error reading properties %s\n", + cfg->file ); + JK_LEAVE_CS(&cfg->cs, rc); + return JK_ERR; + } + + rc=jk2_config_processConfigData( env, cfg, cfgData, firstTime ); + + if( didReload!=NULL ) + *didReload=JK_TRUE; + cfg->mtime= statbuf.st_mtime; + + JK_LEAVE_CS(&cfg->cs, rc); return rc; } +static int JK_METHOD jk2_config_update(jk_env_t *env, + jk_config_t *cfg, int *didReload) +{ + jk2_config_readFile( env, cfg, didReload, JK_FALSE ); +} + /** Set a property for this config object */ static int JK_METHOD jk2_config_setAttribute( struct jk_env *env, struct jk_bean *mbean, @@ -611,6 +760,7 @@ const char *type, const char *name) { jk_config_t *_this; + int i; _this=(jk_config_t *)pool->alloc(env, pool, sizeof(jk_config_t)); if( _this == NULL ) @@ -618,12 +768,23 @@ _this->pool = pool; _this->setPropertyString=jk2_config_setPropertyString; + _this->update=jk2_config_update; _this->setProperty=jk2_config_setProperty; _this->save=jk2_config_saveConfig; _this->mbean=result; + _this->ver=0; + result->object=_this; result->setAttribute=jk2_config_setAttribute; + JK_INIT_CS(&(_this->cs), i); + if (!i) { + env->l->jkLog(env, env->l, JK_LOG_ERROR, + "config.factory(): Can't init CS\n"); + return JK_ERR; + } + + return JK_OK; }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>