From: Zoran V. <zv...@ar...> - 2006-08-26 08:02:07
|
On 25.08.2006, at 19:09, Rick Cobb wrote: > Here's what we ran into when we did something similar; just cautionary > information, not trying to shoot anything down here. Actually this gave me another idea... (BTW... The reason why I'm still not letting loose on this point: althogh I like the idea of tool-based config, it has one strong drawback. How am I going to make this persistent? Per module? This is just plain unpracticable as it would result in a "config-file" per module adding to complexity if I would like to pull to config data from some other source(s)). > > Our approach was to create a separate repository / heirarchy of > configuration variables that is *not* module oriented, Which is also what I'm after... > but > administrative task oriented. So, for example, we have a section > called > "ServiceNetwork" with a variable called "HTTPInterface". That > variable > gets one or more IP addresses. Only these variables are dynamic. To > get a dynamic update for one of these variables, any piece of C/C++ > code > registers a callback based on the variable name. .. but what I'd do is make this "callback" entirely transparent to the caller. Instead, I'd split the config repository in 2 contexts: shared and thread-private. The shared gets loaded, updated and the thread-private is a partial copy of the shared, build-up during the config lookup, dynamically. Each "reader" of the config will first go ask its private context and then shared context for a value. If found in private: ok. If found in shared: ok. Otherwise it updtes its both private and shared context with the default value. The locking would be minimized so that during the normal operation only two threads (the reader and writer) would content for a mutex, which is, given the majority of reads and tiny fractions of writes, neglectable. Now you'd ask: where is the callback? Simple: the reader therad, not founding the value in its private context will set it (under lock) in the shared and register itself automatically for having "interest" in this section. Any writer thereafter, which updates any of the keys of that section will walk the list of interested threads and update their own *private* context after updating the shared one. This way, the locking is minimized to absolute minimum. You will see that when I'm ready with the code. The task of the writer will not be cheap as it will neeed to update not one but N places (depeding on howmany threads expressed "interest" in particular section) but this way the readers are cheap and fast as they will mostly find what they're looking for in their own private cache. > > This repository is read at startup, before the normal > ns_section/ns_param file. OK. But I'd opt to give the startup option to read it before or after the ns_section/ns_param file. This way there is more flexibility what overrides what. > > The declarations for these variables state whether changes to the > variable require a server restart to take effect, or not. > This is a good idea. Although I will not enforce a declaration of the variable (it will be as dynamic as the current config) I will add one qualifier: scope. This will be either startup or runtime depicting wether the thing is read/set only at startup only or not. The scope can be selected during the lookup-falure followed by the shared config update automatically. > Our management console works entirely in terms of this repository; YES. This is the other benefit of having it centralized as you need NOT know in advance what modules you have out there. All is in one place and can be saved, restored, uniformly controlled etc. > > The nsd.tcl-equivalent, which is still written in terms of > ns_section/ns_param, then has access to those variables as TCL global > variables (just a convenience, not necessarily my best design > idea). If > more than one module needs access to a configuration variable, they > just > use it in this section. That lets us use normal AOLServer modules > out-of-the-box, yet coordinate their tuning by writing complicated > TCL. This is where I'm still not sure what to do. I can easily attach a (x)dbm hash underneath which would be perfectly OK. But with a drawback of not being human-readable. I will have to think more here... > > The positive implications have been: > * People configuring our system rarely have to copy the same parameter > to different sections. > * People configuring our system never have to write TCL. > * No changes to existing modules are required > * Our modules, or our own edits to AOLServer modules, get dynamic > capabilities > * All configuration changes can be made over HTTP > * All of our modules have dynamic debug capability; in fact, for > almost > all of them, it's possible to adjust their debug settings over > HTTP, so > you can almost get to the point where you can debug a specific HTTP > request (of course, with lots of traffic, that doesn't work). > > The negative implications have been: > * Our nsd.tcl-equivalent is *very* long and complicated (~3000 lines), > and is gradually becoming dominated by TCL control statements > (if/for/etc), not sections & params. > * If a variable requires calculation to become an internal > configuration > state, the calculation is often repeated in both TCL (nsd.tcl) and C. > * Startup time is slowed by all this processing, but it's not a big > deal > because we also recover a database during our startups, which > dominates > the startup time. > * It is very hard to see all the coupling for a specific variable. > * Any module that uses a dynamic variable has to code for it three > times, in three different areas: once for its use for > ns_section/ns_param, once for the global configuration area, and > once in > the callback. > > We could mitigate some of these with better generators or code > conventions, but haven't. Reading the above, I see no mention about how you do the locking? If a writer chages a variable, he'd have to propagate this change to readers, or? Now, readers, accessing the same variable must access it under lock as some writer can call their registered callback which updates the value at the same time, right? In my (still) "vapourware", this is/must-be so, but the locking is actually very cheap while most of the time reader will just lock its private context, lookup and unlock. There will be no lock contenton on that mutex. Only when one of the writers (which is a rare event) goes and updates reader's private context (this being a very short operation anyway) a short contention may happen. I believe this can be entirely neglected. The cost of locking a mutex is low, if there is nobody else I have to fight with. Actually, I'm sure this will work excellent. Anyway, I will have to write this one in the next few days as we already have plans for expading our product. We cannot tolerate shutdowns of the server just to flip a bit any more. This is now pressing us for some time and we've come to a point where this must be done. Thanks for the valuable information. I will make (our) nsconf or nsregistry module public and we can then all see if this is usable for others or not. Cheers, Zoran |
From: Bernd E. <eid...@we...> - 2006-08-26 10:30:47
|
> This is where I'm still not sure what to do. I can easily attach > a (x)dbm hash underneath which would be perfectly OK. But with a > drawback of not being human-readable. I will have to think more > here... You could use something as storage you are most familiar with and what fits the purpose, be it (x)dbm. Would it then be a lot of work to provide a transformation command that makes it human readable? Maybe this is sufficient. Bernd. |
From: Zoran V. <zv...@ar...> - 2006-08-26 10:48:58
|
On 26.08.2006, at 12:30, Bernd Eidenschink wrote: > Would it then be a lot of work to provide a > transformation command that makes it human readable? Piece of cake. As the matter of fact I may invent a command like ns_confctl save ?-decode? channel ns_confctl load ?-encode? channel and this will read/write the config to some channel optionally encoding/decoding to/from human readble form. This is all opened for later polish. The first thing for us now is to have a good proof of concept. And the concept is to provide reasonably fast read/write configuration storage module with C and Tcl API with minimal locking requirements. Lets see... Cheers Zoran |
From: Stephen D. <sd...@gm...> - 2006-08-29 20:29:28
|
On 8/25/06, Zoran Vasiljevic <zv...@ar...> wrote: > > On 24.08.2006, at 21:36, Stephen Deasey wrote: > > > > > So I think you can't get away from specialisation, unfortunately. > > > > What I still cannot (easily) accept is that we can't > do a config module as repository for the server and > other module's configuration options. > Think of it as the Windows registry (not that I'm > a fan of Microsoft, I'm not, but this "centralized" > approach also has benefits). > > What I could imagine is: > > We can have the config file as is now. But it would > form just a part of the configuration. Over the runtime > of the server, new configuration could be added or > existing changed. This is non-volatile, means at the > next restart, the changes are still there. > At the startup, one can decide wether the config file > (as now) is the applied first or after loading the, > lets call it registry for now, file. This way you can > decide wether the changes to the values from the config > file are overriden by the registry or not. New stuff > which is only in the registry is of course loaded. > But during the startup you can even discard them completely. > We can have a web-page which handles registry maintenance > in the server. So with one management interface you can > tune various knobs mostly w/o restarting the server. > > The persistency can be implemented by a simple > dbm hash-file (ndbm, gdbm). > > I mean, nobody can tell me that this is impossible > or not practicable: there are at lest 60.000.000 proofs > of concept out there... > > I would need to hear 1 good reason against this. > As you see, I'm not letting loose... > > As the matter of fact, I=10 will write this for us internally > as a module. Lets call it "nsregistry" module. It will have > a library to link with so other modules can use it from the > C-level. It will have a Tcl and C API similar to what we have > now, with a small difference: values are obtained by *copy* > and not by reference. It will be properly locked so it can > be used from many threads at the same time. =10I will of course > not repeat the silly case-insensitivity junk: the thing will > be case sensitive. It will have the same section/parameter > approach as the current config. The idea of this module would > be to provide centralized and persistent storage for all kinds > of various configuration parameters one can imagine, for the > server itself and for the modules. From Tcl and from C-modules. > Actually, that what the current config does but w/o aiming to > replace it because of all possible concerns about locking of > speed (or whatever). And it will be persistent. > It would be more flexible to create ns_*ctl commands and put them *lower* in the stack, and then build a dynamic configuration tool on top of this, than to bake a dynamic configuration mechanism into the server, and have code depend on that. For example, if you went with the callback approach that Rick mentioned (seems easiest), the callback would run the ns_*ctl command when a config value is updated. You keep your options open. If you go the other way, you have to start thinking about: do we create an interface that allows people to plug in different persistence mechanism for the back end, etc...? |
From: Zoran V. <zv...@ar...> - 2006-08-29 20:43:25
|
On 29.08.2006, at 22:29, Stephen Deasey wrote: > It would be more flexible to create ns_*ctl commands and put them > *lower* in the stack, and then build a dynamic configuration tool on > top of this, than to bake a dynamic configuration mechanism into the > server, and have code depend on that. Yet, if module A changes value B, how would that look like if I'd need to have it arround the next boot time? IOW, how would you handle persistence with that? |
From: Vlad S. <vl...@cr...> - 2006-08-22 15:10:09
|
What is the requirement for changing config array, did i miss it? Can you dump all config tree at startup into ns_cache and then work with it instead of ns_config later? Zoran Vasiljevic wrote: > On 22.08.2006, at 16:46, Rick Cobb wrote: > >> Uh, and I may be missing something about how you're thinking of doing >> this, but how would you handle open configuration sets like the >> environment variables for the CGI module, or the map of mime-type/file >> extensions? > > ?? ( == do not understand) > > What do you mean by "open configuration sets" ?? > Using ns_config, nothing is "open". It is just > a query into a in-memory data structure. > > The fact that this query now uses no locks, and is thus > "cheap", modifying it to use locks is one issue > (and you need locks at that place because somebody > could read and other could modify the same structure). > Another issue is: some module already "consumed" > the parameter at startup and will never ask for it > again: what is the point in changing that particular > parameter? > Also, should this all be allowed anyway (security issue)? > > This is what I see as things to take in account. > > For the locking issue: I believe this is not that > important as it can be easily "fixed" by storing the > value got from config in a private variable and then > reusing this for the time being. > > For the security issue: well, there might be a > config option to allow this, either as runtime > or compile-time option (the latter will solve > any locking issues implicitly) > > For the sense of changing a once-read config value? > Well, there isn't (sense). But that has nothing to > do with the implementation. > > Cheers > Zoran > > > > > ------------------------------------------------------------------------- > Using Tomcat but need to do more? Need to support web services, security? > Get stuff done quickly with pre-integrated technology to make your job easier > Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo > http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 > _______________________________________________ > naviserver-devel mailing list > nav...@li... > https://lists.sourceforge.net/lists/listinfo/naviserver-devel > -- Vlad Seryakov 571 262-8608 office vl...@cr... http://www.crystalballinc.com/vlad/ |
From: Zoran V. <zv...@ar...> - 2006-08-22 15:16:11
|
On 22.08.2006, at 17:11, Vlad Seryakov wrote: > What is the requirement for changing config array, did i miss it? > > Can you dump all config tree at startup into ns_cache and then work > with > it instead of ns_config later? I can't. The very important aspect is: C *and* Tcl API existence. Numerous C modules we have, peek into the config. Tcl modules as well. I would like to allow them to poke there as well. Cheers Zoran |
From: Bernd E. <b.e...@ki...> - 2006-08-22 15:16:08
|
Ok Zoran, the important part first: > I'm thinking about allowing *changes* to/of this repository > during the runtime. This way one could override a ns_param > value assigned at startup or create entirely new ns_section > and stuff it with bunch of ns_param so others may call > [ns_config] to get it. I'm all for it if it is possible. It saves us server restarts for dumb issues like increasing maximum post sizes etc. Problems: I can change stacksize to "0". I can tell fastpath to use 1 byte of memory instead 5 megs. Is memory freed? I guess it comes down to "You are able to change everything - but be sure you now what you are doing". The other part: It would be nice to have the dictionary of config sections and options along with their defaults that is created when you set logmaxlevel to "6" (dev) or "5" (debug) in section ns/parameters... ----------------------------------------------------------------- [...] Debug: config section: ns/server/default Debug: config: ns/server/default:realm value="(null)" default="default" (string) Debug: config: ns/server/default:checkmodifiedsince value=(null) default=true (bool) Debug: config: ns/server/default:flushcontent value=false default=false (bool) Debug: config: ns/server/default:noticedetail value=(null) default=true (bool) Debug: config: ns/server/default:errorminsize value=(null) min=-2147483648 max=2147483647 default=514 (int) Debug: config: ns/server/default:headercase value="(null)" default="preserve" (string) Debug: config: ns/server/default:outputCharset value=(null) (string) Debug: config: ns/server/default:HackContentType value=(null) (bool) Debug: config: ns/server/default:urlCharset value=(null) (string) [...] ----------------------------------------------------------------- ...available as TCL command like ns_configsections. For the sake of the argument, e.g. "ns_startupconfigsections". It must be the list created at server startup that DOES NOT CONTAIN entries like ns_section milly/vanilly ns_param fate 1 As far as I can tell this is possible because simply because a value was not requested by Ns_Config* (Int/Range whatever) commands means it is irrelevant for the server. At least in a sense of "get things right for startup". Default values are set by these commands. I think the listing above does also only list those and would not list milly/vanilly section and options. Maybe it's already there. Only then I am able to utilize TCL to diff and compare and return results like "milly/vanilly" section may be bogus or a typo. Or that parameter "stacksize" does not belong to section "fastpath". And, as a bonus, I can create a table of options, their defaults, types and minimum or maximum value. Bernd. |
From: Zoran V. <zv...@ar...> - 2006-08-22 15:54:37
|
On 22.08.2006, at 17:19, Bernd Eidenschink wrote: > > Ok Zoran, the important part first: > >> I'm thinking about allowing *changes* to/of this repository >> during the runtime. This way one could override a ns_param >> value assigned at startup or create entirely new ns_section >> and stuff it with bunch of ns_param so others may call >> [ns_config] to get it. > > I'm all for it if it is possible. It saves us server restarts for > dumb issues > like increasing maximum post sizes etc. Right. This is very good and trivial example. > > Problems: I can change stacksize to "0". I can tell fastpath to use > 1 byte of > memory instead 5 megs. Is memory freed? I guess it comes down to > "You are > able to change everything - but be sure you now what you are doing". As said: if the module has already consumed the value, changing it has no real sense. If the fastpath module already got that 5 MB and allocated the cache, it will most definitely not ask for the size again, unless it is programmed to do so. But, since no modules so far assumed that config values can be changed after startup, there will be no problems. So, you *could* change it to 0 bytes but it will mean nothing. > > > > > The other part: It would be nice to have the dictionary of config > sections and > options along with their defaults that is created when you set > logmaxlevel > to "6" (dev) or "5" (debug) in section ns/parameters... > > ----------------------------------------------------------------- > > [...] > Debug: config section: ns/server/default > Debug: config: ns/server/default:realm value="(null)" > default="default" > (string) > Debug: config: ns/server/default:checkmodifiedsince value=(null) > default=true > (bool) > Debug: config: ns/server/default:flushcontent value=false > default=false (bool) > Debug: config: ns/server/default:noticedetail value=(null) > default=true (bool) > Debug: config: ns/server/default:errorminsize value=(null) > min=-2147483648 > max=2147483647 default=514 (int) > Debug: config: ns/server/default:headercase value="(null)" > default="preserve" > (string) > Debug: config: ns/server/default:outputCharset value=(null) (string) > Debug: config: ns/server/default:HackContentType value=(null) (bool) > Debug: config: ns/server/default:urlCharset value=(null) (string) > [...] > > ----------------------------------------------------------------- > > ...available as TCL command like ns_configsections. > For the sake of the argument, e.g. "ns_startupconfigsections". > > It must be the list created at server startup that DOES NOT CONTAIN > entries > like > ns_section milly/vanilly > ns_param fate 1 > > As far as I can tell this is possible because simply because a > value was not > requested by Ns_Config* (Int/Range whatever) commands means it is > irrelevant > for the server. At least in a sense of "get things right for startup". > Default values are set by these commands. HE! This is the stumbling point! The fact that something is requested by Ns_Config is not of any importance! It could have been also requested by the "ns_config" out of (your own) Tcl startup file! There is no such thing as "server" configuration and the "rest" of the configuraton. There is one configuration parameters store. Everybody can (and does) use it during the startup. Your Tcl modules, your C- modules core-server modules etc. pp. > > I think the listing above does also only list those and would not list > milly/vanilly section and options. Maybe it's already there. > > Only then I am able to utilize TCL to diff and compare and return > results > like "milly/vanilly" section may be bogus or a typo. Or that > parameter "stacksize" does not belong to section "fastpath". You CANNOT know if a section/parameter is a typo! If the section (or parameter) is not found and a paramter value is *assigned*, then the section (and the parameter) is/are created! Point. This is the way how all this stuff works. Otherwise, some central authority must declare *upfront* all possible sections and parameter values. We do not have this "authority". Every module declares its own. I believe we are still not in consensus :-( Give me an example what you mean. This is perhaps easier. Cheers Zoran |
From: Bernd E. <eid...@we...> - 2006-08-22 16:30:10
|
> There is no such thing as "server" configuration and the "rest" of the > configuraton. There is one configuration parameters store. Everybody > can (and does) use it during the startup. Your Tcl modules, your C- > modules > core-server modules etc. pp. Yes, this is the point. I will have to agree that it only "works" if I assume the first call (with the "first default") to be "authoritative" - and this is probably crap. But it also means that the resulting list in the logs (the excerpt in my mail) is just a snapshot of the last Ns_Config* call? Example (4 calls in 4 different parts during startup in this order): nsconf.shutdowntimeout = Ns_ConfigIntRange(path, "shutdowntimeout", 20, 0, 40); nsconf.shutdowntimeout = Ns_ConfigIntRange(path, "shutdowntimeout", 21, 1, 41; nsconf.shutdowntimeout = Ns_ConfigIntRange(path, "shutdowntimeout", 22, 2, 42); nsconf.shutdowntimeout = Ns_ConfigIntRange(path, "shutdowntimeout", 23, 3, INT_MAX); Then the logs show the 23,3,INT_MAX call as result??? > I believe we are still not in consensus :-( We are. Except for one thing, but I have to leave the office now ;-) Bernd. |