From: Stephen D. <sd...@gm...> - 2006-09-18 18:55:39
|
The API for nsproxy looks like a bit of an accident to me. The module is based on the external db driver interface, hence the name 'proxy' and the explicit handle management. But 'proxy' really doesn't apply here, and the worst part of the nsdb module has always been the handle management... Also, the module presents an async API but doesn't follow the lead of the existing ns_job (very similar aims) or ns_http. For comparison, here's ns_proxy, ns_job, ns_http and some threading commands: *** Proxy Pools *** ns_proxy get pool ?-opt val ...? (get proxy handle from pool) ns_proxy put handle (return proxy handle to pool) ns_proxy release handle (identical to put) ns_proxy ping handle (is slave responding?) ns_proxy cleanup (release all handles for interp) ns_proxy eval handle script (send script, wait for and recv result) ns_proxy send handle script (send script to slave) ns_proxy wait handle ?timeout? (wait for result from salve) ns_proxy recv handle (get the result from slave) ns_proxy pools (list all pools for all servers) ns_proxy configure pool ?opt val ...? (create new / cfg existing pool) ns_proxy free pool (list free slaves in pool) ns_proxy active pool (list busy slaves in pool) ns_proxy handles (list allocated handles for interp) ns_proxy clear pool ?handle? (close all slaves in all pools/pool) ns_proxy stop pool ?handle? (close running slaves in all pools/pool) (NB: 'pools', 'clear' and 'stop' sub-commands not virtual-server safe) *** Job Queues *** ns_job create ?-desc d? queueId ?maxT? (create new q) ns_job delete queueId (delete q when jobs complete) ns_job queues (list of all queues) ns_job queuelist (list of all q's w/q-info) ns_job jobs queueId (list of jobIds for q) ns_job joblist queueId (list of jobIds w/job-info for q) ns_job threadlist (return min/max threads info) ns_job queue ?-detached? queueId script (send script to queue, ret jobid) ns_job wait ?-timeout t? queueId jobId (fech job result) ns_job waitany ?-timeout t? queueId (fetch next result from q) ns_job cancel queueId jobId (discard pending result) ns_job genid (generate a unique q name) (q names are not virtual-server safe) *** Async http requests *** ns_http queue ?qflags? url (open conn to server, send task to io thread) ns_http wait ?wflags? hId (wait for http opp result from io thread) ns_http run ?qflags? url (queue and wait) ns_http cancel hId (abort given http opp) ns_http cleanup (abort all opps in current interp) *** Threads *** ns_thread begin script (run script) ns_thread begindetached script (run script, discard result, exit thread) ns_thread wait tId (get result of non-detached thread) The ns_job command isn't great -- it shares the same brokenness with ns_proxy in that job queue names are global, like proxy pool names. There's some ideas though: - 'queue' initiates an action, returns an opaque handle which can be waited upon for the result. - 'wait' waits for the result of a queued action. - 'cancel' discards the result of a pending action. - 'detached' actions can not be waited upon -- they do not have any result (or the result is discarded) I was thinking that as ns_job and ns_proxy were so similar they could be merged, but there is a significant difference: the 'eval' command makes sense for ns_proxy but not for ns_job. Naming is easy -- it's the explicit handle management that's making things different. Low level C APIs just don't map directly into C. For example, you never expect a C programmer to grab a handle then leave it dangling, that's just broken code. But with Tcl this sort of thing is expected. You have to clean up, take extra precautions with locking, and so on. As far as I can see, the handles aren't needed. How about something like this: API: result ns_exec_eval ?-pool p? ?-timeout t? script Id ns_exec_queue ?-detached? ?-pool p? ?-timeout t? script ns_exec_wait ?-timeout t? Id ?Id ...? ns_exec_cancel ns_exec_set ?-opt val ...? pool ns_exec_stats pool Example: set result [ns_exec_eval { set x y exec /bin/blah $x }] Notes: Create pool 'default' on startup. Reuse identical processes (same binary, ulimits, etc.) among pools, in the same way that threads are shared globally among ns_job queues. 'maxexecs' parameter, after which processes exit and are respawned. As well as not being very descriptive, the name 'proxy' also clashes with genuine HTTP proxy functions such as ns_register_proxy. The proxy functionality that Vlad's been adding recently obviously should be in a a module called nsproxy... Some things are definitely version 2, ulimits for example. It would be a pain to get stuck with an awkward API though. What do you think? I noticed a couple of things while looking through the code: nsproxymod.c: SrvMod structure is statically allocated, one per process, but is assigned to each time the module is loaded, potentially x times per virtual server. nsproxylib.c, ProxyPop(): Extra call to Ns_CondBroadcast() without lock being held. if (err != ENone) { while ((proxyPtr = firstPtr) != NULL) { firstPtr = proxyPtr->nextPtr; PushProxy(proxyPtr); } Ns_CondBroadcast(&poolPtr->cond); return TCL_ERROR; } nsproxylib.c, ProxyPush(): Ns_CondBroadcast() called whether proxy is returned to pool or not. Ns_MutexLock(&poolPtr->lock); poolPtr->nused--; poolPtr->nfree++; if ((poolPtr->nused + poolPtr->nfree) <= poolPtr->max) { proxyPtr->nextPtr = poolPtr->firstPtr; poolPtr->firstPtr = proxyPtr; if (proxyPtr->procPtr) { SetExpire(proxyPtr->procPtr, proxyPtr->timers.tidle); } proxyPtr->timers = poolPtr->timers; proxyPtr = NULL; } else { poolPtr->nfree--; } Ns_CondBroadcast(&poolPtr->cond); Ns_MutexUnlock(&poolPtr->lock); GetPool(): Proxy pool is created if name pool name does not already exist. What about typos? This is error prone. Alternative: always create a pool 'default' on start up and make specifying pool names optional? The term 'procPtr' is confusing when used to mean pointer to Proxy Slave. In the rest of the code base, procPtr means pointer to C function, i.e. a callback. |
From: Zoran V. <zv...@ar...> - 2006-09-18 20:22:20
|
On 18.09.2006, at 20:55, Stephen Deasey wrote: > > Naming is easy -- it's the explicit handle management that's making > things different. Low level C APIs just don't map directly into C. > For example, you never expect a C programmer to grab a handle then > leave it dangling, that's just broken code. But with Tcl this sort of > thing is expected. You have to clean up, take extra precautions with > locking, and so on. > > As far as I can see, the handles aren't needed. How about > something like this: > > > API: > > result ns_exec_eval ?-pool p? ?-timeout t? script > > Id ns_exec_queue ?-detached? ?-pool p? ?-timeout t? script > ns_exec_wait ?-timeout t? Id ?Id ...? > ns_exec_cancel > > ns_exec_set ?-opt val ...? pool > ns_exec_stats pool > > Example: > > set result [ns_exec_eval { > set x y > exec /bin/blah $x > }] > > Notes: > > Create pool 'default' on startup. > > Reuse identical processes (same binary, ulimits, etc.) among > pools, in > the same way that threads are shared globally among ns_job > queues. > > 'maxexecs' parameter, after which processes exit and are > respawned. > > > > As well as not being very descriptive, the name 'proxy' also clashes > with genuine HTTP proxy functions such as ns_register_proxy. The > proxy functionality that Vlad's been adding recently obviously should > be in a a module called nsproxy... > > Some things are definitely version 2, ulimits for example. It would > be a pain to get stuck with an awkward API though. > > What do you think? All kinds of good ideas... I will comment on that tomorrow when I'm back to work. > > > I noticed a couple of things while looking through the code: > > > > nsproxymod.c: SrvMod structure is statically allocated, one per > process, but is assigned to each time the module is loaded, > potentially x times per virtual server. Yes. Incorrect. Must fix that. There is no harm except memory leaking... but this is bad enough. > > > nsproxylib.c, ProxyPop(): Extra call to Ns_CondBroadcast() without > lock being held. > > > if (err != ENone) { > while ((proxyPtr = firstPtr) != NULL) { > firstPtr = proxyPtr->nextPtr; > PushProxy(proxyPtr); > } > Ns_CondBroadcast(&poolPtr->cond); > return TCL_ERROR; > } ?? You need not necessarily hold a locked mutex to broadcast the condition varible. In this case the PushProxy is making necessary locks. The Ns_CB is called here to release waiters at line 2067 or 2070 after we have retuned pop'ed proxies back to the pool in case of error. > > > nsproxylib.c, ProxyPush(): Ns_CondBroadcast() called whether proxy is > returned to pool or not. OK. This is true. Actually, we only need this one. The other Ns_CB (above) can be removed. Will make necessary modifications. > > Ns_MutexLock(&poolPtr->lock); > poolPtr->nused--; > poolPtr->nfree++; > if ((poolPtr->nused + poolPtr->nfree) <= poolPtr->max) { > proxyPtr->nextPtr = poolPtr->firstPtr; > poolPtr->firstPtr = proxyPtr; > if (proxyPtr->procPtr) { > SetExpire(proxyPtr->procPtr, proxyPtr->timers.tidle); > } > proxyPtr->timers = poolPtr->timers; > proxyPtr = NULL; > } else { > poolPtr->nfree--; > } > Ns_CondBroadcast(&poolPtr->cond); > Ns_MutexUnlock(&poolPtr->lock); > > > GetPool(): Proxy pool is created if name pool name does not already > exist. What about typos? This is error prone. Alternative: always > create a pool 'default' on start up and make specifying pool names > optional? This was the original code I just took as-is and made "usable" and working. Of yourse, if you change this then all other options are open.... But more on that tomorrow. > > The term 'procPtr' is confusing when used to mean pointer to Proxy > Slave. In the rest of the code base, procPtr means pointer to C > function, i.e. a callback. How about slavePtr? Cheers Zoran |
From: Zoran V. <zv...@ar...> - 2006-09-18 20:54:30
|
On 18.09.2006, at 20:55, Stephen Deasey wrote: > it's the explicit handle management that's making > things different. Low level C APIs just don't map directly into C. What C API's ?? Ns_ProxyGet Ns_ProxyPut Ns_ProxyEval are the only API's that C programmer might use. They are perfectly symetric and most simple. You Ns_ProxyGet a proxy, then you Ns_ProxyEval something in it (possibly many times) and then you Ns_ProxyPut it back. No locking. What could be simpler than that? |
From: Stephen D. <sd...@gm...> - 2006-09-18 21:03:36
|
On 9/18/06, Zoran Vasiljevic <zv...@ar...> wrote: > > On 18.09.2006, at 20:55, Stephen Deasey wrote: > > > it's the explicit handle management that's making > > things different. Low level C APIs just don't map directly into C. > > What C API's ?? > > Ns_ProxyGet > Ns_ProxyPut > Ns_ProxyEval > > are the only API's that C programmer might use. > They are perfectly symetric and most simple. > You Ns_ProxyGet a proxy, then you Ns_ProxyEval > something in it (possibly many times) and then > you Ns_ProxyPut it back. No locking. What could > be simpler than that? I mean that Ns_ProxyGet() might be appropriate for C programmers, but that doesn't mean that ns_proxy get is for Tcl programmers. It's not just about level of difficulty either. Mapping the low level C APIs directly seems to add a lot of difficulty, because you have to take account of the Tcl environment and all the crazy things that you just don't allow in the C API. |
From: Zoran V. <zv...@ar...> - 2006-09-18 21:26:15
|
On 18.09.2006, at 23:03, Stephen Deasey wrote: > > I mean that > > Ns_ProxyGet() > > might be appropriate for C programmers, but that doesn't mean that > > ns_proxy get > > is for Tcl programmers. It's not just about level of difficulty > either. Mapping the low level C APIs directly seems to add a lot of > difficulty, because you have to take account of the Tcl environment > and all the crazy things that you just don't allow in the C API. Aha. Well, in that particular case, the [ns_proxy get] is not bad at all! You get the handle of "something" that you use to do all kinds of things. Later on, when you're done with it, you [ns_proxy put] itback, allowing others to use the same "something" How would you make this in a "Tcl way"? After all, you [open] the channel, then you [puts] to it and then [close] it. What is not OK here? I think I know where are you heading and I can understand the idea but this particular example may not be optimal. I believe you are thinking about something like this: ns_mutex lock $lock do bla bla bla ns_mutex unlock $lock The "optimal" way to do that would really be: ns_mutex lock $lock { do bla bla bla } as it will save you the trouble if "do bla bla" throws error. In the latter case you must ugly things like ns_mutex lock $lock if {[catch {do bla bla} err]} { ns_mutex unlock $lock error $err } ns_mutex unlock $lock which is just plain rubbish (because of which we had to invent our own do/catch/finally command)... I will take more time to answer on your nsproxy email as this two are really comming close... |
From: Stephen D. <sd...@gm...> - 2006-10-04 04:41:36
|
On 9/18/06, Zoran Vasiljevic <zv...@ar...> wrote: > > On 18.09.2006, at 23:03, Stephen Deasey wrote: > > > > > I mean that > > > > Ns_ProxyGet() > > > > might be appropriate for C programmers, but that doesn't mean that > > > > ns_proxy get > > > > is for Tcl programmers. It's not just about level of difficulty > > either. Mapping the low level C APIs directly seems to add a lot of > > difficulty, because you have to take account of the Tcl environment > > and all the crazy things that you just don't allow in the C API. > > Aha. Well, in that particular case, the [ns_proxy get] is not bad at > all! > You get the handle of "something" that you use to do all kinds of > things. > Later on, when you're done with it, you [ns_proxy put] itback, allowing > others to use the same "something" > > How would you make this in a "Tcl way"? > > After all, you [open] the channel, then you [puts] to it and then > [close] it. What is not OK here? > > I think I know where are you heading and I can understand the idea > but this particular example may not be optimal. > > I believe you are thinking about something like this: > > ns_mutex lock $lock > do bla bla bla > ns_mutex unlock $lock > > The "optimal" way to do that would really be: > > ns_mutex lock $lock { > do bla bla bla > } > > as it will save you the trouble if "do bla bla" throws error. > In the latter case you must ugly things like > > ns_mutex lock $lock > if {[catch {do bla bla} err]} { > ns_mutex unlock $lock > error $err > } > ns_mutex unlock $lock > > which is just plain rubbish (because of which we had to invent > our own do/catch/finally command)... > It's not just the cleanup-up after error. Why does the Tcl programmer need to get and return resources? It's kind of awkward. For example: ns_serialize { # whatever } is better than the mutex example above because you also don't have to mess around with the mutex handle and nsv arrays. The Tcl code in the code block serves as a key into a hash table of locks, created on demand. We can let the code block shimmer to an object which contains both a byte code script and a mutex pointer. It will run as fast as possible the second time round. More complicated syntax for a more complicated operation: ns_serialize -lock mylock { # whatever } Now you could run two different code blocks using the same lock. But you still don't have to allocate mutex objects, pass around their names in nsv arrays, and so on. I don't think the above is dumbed-down. It's a much nicer way to work with Tcl, and you just wouldn't do this kind of thing from C. Anyway, back to nsproxy. Thinking about it further, it looks like the explicit handles are actually there to allow a particular kind of Tcl programming, not necessarily because explicit handle management is needed. i.e.: set x [create ... $x method ... Which is perhaps not a bad way to manage the handles if you absolutely need them. But if you can instead do: ns_proxy eval { # whatever } which in the case of a default pool and a single evaluation, you can, it's got to be better than the explicit handle management, right? This is basically identical to the db module. People hate manging db handles, which is why the ACS style db_* API is so popular. I was also wondering about the ns_proxy send/wait/receive. Why are wait and receive separate commands? Also, does there need to be so many timeouts? The waittimeout is 100 msec. That means if all else goes well, but the wait time takes 101 msec, the evaluation will not be successful. But looking at the other defaults, the script evaluator was prepared to wait (gettimeout 5000 + evaltimeout infinite + sendtimeout 1000 + recvtimeout 1000), or between six seconds and forever... Wouldn't a single timeout do? It would also be great if the timeout error code began with the NS_TIMEOUT symbol, which if not caught will automatically trigger a Server Busy error page. |
From: Zoran V. <zv...@ar...> - 2006-10-04 08:51:52
|
On 03.10.2006, at 01:01, Stephen Deasey wrote: > > It's not just the cleanup-up after error. Why does the Tcl programmer > need to get and return resources? It's kind of awkward. Not necessarily... Think of a handle as a "reservation". I take the handle and I "own" the resource for some time. In case of nsproxy, I can run two or more "things" one after another, possibly sharing the common state in the proxy slave. > > For example: > > ns_serialize { > # whatever > } > > is better than the mutex example above because you also don't have to > mess around with the mutex handle and nsv arrays. The Tcl code in the > code block serves as a key into a hash table of locks, created on > demand. We can let the code block shimmer to an object which contains > both a byte code script and a mutex pointer. It will run as fast as > possible the second time round. > > More complicated syntax for a more complicated operation: > > ns_serialize -lock mylock { > # whatever > } > > Now you could run two different code blocks using the same lock. But > you still don't have to allocate mutex objects, pass around their > names in nsv arrays, and so on. > > I don't think the above is dumbed-down. It's a much nicer way to work > with Tcl, and you just wouldn't do this kind of thing from C. Guess what... exactly this I have done in the Tcl threading extension for the thread::eval command: thread::eval ?-lock mutex? arg ?arg ...? (this is perhaps a misnomer as script is evaluated in the _current_ and not in some other thread) Which means: I completely understand what you say. Just in some cases it is feasible (like in example for the mutex) to avoid fiddling with handles and in some cases (nsproxy) it opens new posibilities. > > > Anyway, back to nsproxy. Thinking about it further, it looks like the > explicit handles are actually there to allow a particular kind of Tcl > programming, not necessarily because explicit handle management is > needed. i.e.: > > set x [create ... > $x method ... > > Which is perhaps not a bad way to manage the handles if you absolutely > need them. But if you can instead do: > > ns_proxy eval { > # whatever > } > > which in the case of a default pool and a single evaluation, you can, > it's got to be better than the explicit handle management, right? As said, in this special case: yes. But otherwise: no. What I CAN do with explicit handle managment is: set proxy [ns_proxy get thepool] $proxy "set a 1" $proxy "puts $a" This is not possible w/o explicit handle. It is also the reservation aspect that is important when using the handle. This aspect is of course nil for mutex, condvar or other "things". > This is basically identical to the db module. People hate manging db > handles, which is why the ACS style db_* API is so popular. It is all the matter of the programming case. In some cases it is absolutely stupid to use handles, I agree. In some cases it opens new possibilities. > > > I was also wondering about the ns_proxy send/wait/receive. Why are > wait and receive separate commands? Because you can wait, get the timeout, do something and then go repeat waiting. It makes sense. You can't achieve this with a longer wait timeout OR with a timed [ns_proxy eval]. Allright, you can argue: one can [ns_proxy receive proxy ?timeout?] in which case you have the same behaviour. Correct. But what difference would it make, really? > > Also, does there need to be so many timeouts? The waittimeout is 100 > msec. That means if all else goes well, but the wait time takes 101 > msec, the evaluation will not be successful. But looking at the other > defaults, the script evaluator was prepared to wait (gettimeout 5000 + > evaltimeout infinite + sendtimeout 1000 + recvtimeout 1000), or > between six seconds and forever... Wouldn't a single timeout do? There are lots of "places" something can go "wrong" at the communication path. Hence so many timeouts. At every place you send something or receive something, there is a timeout. Timeout to send chunk of data to proxy isn't the same as the timeout to wait for the proxy to respond after feeding it some command to execute. Basically, one can hardwire "sane" values for those communication timeouts (and there are sane values set there as defaults) but somebody may come into the need of adjusting them during runtime. You however do not need to do that, as sane defaults are provided everywhere. > > It would also be great if the timeout error code began with the > NS_TIMEOUT symbol, which if not caught will automatically trigger a > Server Busy error page. This is not a problem. |
From: Stephen D. <sd...@gm...> - 2006-10-06 21:12:52
|
On 10/4/06, Zoran Vasiljevic <zv...@ar...> wrote: > > On 03.10.2006, at 01:01, Stephen Deasey wrote: > > > > > > I was also wondering about the ns_proxy send/wait/receive. Why are > > wait and receive separate commands? > > Because you can wait, get the timeout, do something and then go repeat > waiting. It makes sense. You can't achieve this with a longer wait > timeout OR with a timed [ns_proxy eval]. > Allright, you can argue: one can [ns_proxy receive proxy ?timeout?] > in which case you have the same behaviour. Correct. But what difference > would it make, really? Two commands make it twice as hard to use. All that's needed is a timeout switch: set result [ns_proxy wait -timeout 10 $handle] > > Also, does there need to be so many timeouts? The waittimeout is 100 > > msec. That means if all else goes well, but the wait time takes 101 > > msec, the evaluation will not be successful. But looking at the other > > defaults, the script evaluator was prepared to wait (gettimeout 5000 + > > evaltimeout infinite + sendtimeout 1000 + recvtimeout 1000), or > > between six seconds and forever... Wouldn't a single timeout do? > > There are lots of "places" something can go "wrong" at the communication > path. Hence so many timeouts. At every place you send something or > receive something, there is a timeout. Timeout to send chunk of > data to proxy isn't the same as the timeout to wait for the proxy to > respond after feeding it some command to execute. Basically, one can > hardwire "sane" values for those communication timeouts (and there are > sane values set there as defaults) but somebody may come into the need > of adjusting them during runtime. You however do not need to do that, > as sane defaults are provided everywhere. The caller has a time budget. That's the total amount of time they're prepared to wait for a result. The underlying implementation may break the process down into sub tasks, but the caller doesn't really care, or know about this. If you look at the sub-tasks you might be able to say what a reasonable timeout might be. But note: this is an optimisation. A single time budget works for all the different sub-tasks, a special timeout for some sub-task only allows that task to *fail* quicker. It's not free though. You get the odd effect of failing with a timeout when there's plenty of time left in the budget. The error handling is also weird. As it's currently implemented, there's a different error code for each kind of timeout failure. The caller is forced to deal with all the different ways a timeout might occur. With a generic NS_TIMEOUT errorCode this can be skipped, but now you're loosing information. I think it needs to keep stats on the different failures, with a ns_proxy_stats command to track it. This is the data you will use to help you size the pool according to load and server ability. It's interesting to note that an individual error may not actually be an error. The goal is to size the pool according to resources available for maximum performance. If a caller times out because there are no handles, well maybe the system is doing it's job? On the other hand, if 80% of the callers are failing dues to timeout, well then you have a problem. Maybe your pool is undersized, or maybe your server is overloaded. It's the percentage of failures which determine whether there's a problem with the system. A single concept of timeout with statistics kept on failures would be easier to implement and describe, would prevent spurious timeouts, and would allow administrators to size the proxy pools. |
From: Zoran V. <zv...@ar...> - 2006-10-06 21:52:58
|
On 06.10.2006, at 23:12, Stephen Deasey wrote: > On 10/4/06, Zoran Vasiljevic <zv...@ar...> wrote: >> >> On 03.10.2006, at 01:01, Stephen Deasey wrote: >>> >>> >>> I was also wondering about the ns_proxy send/wait/receive. Why are >>> wait and receive separate commands? >> >> Because you can wait, get the timeout, do something and then go >> repeat >> waiting. It makes sense. You can't achieve this with a longer wait >> timeout OR with a timed [ns_proxy eval]. >> Allright, you can argue: one can [ns_proxy receive proxy ?timeout?] >> in which case you have the same behaviour. Correct. But what >> difference >> would it make, really? > > > Two commands make it twice as hard to use. All that's needed is a > timeout switch: > > set result [ns_proxy wait -timeout 10 $handle] > Either way is OK. send/wait/recv is straight foward and simpler if you usually HAVE to wait, whereas send/wait_with_receive is more optimal if you mainly don't need to wait (i.e. you tolerate indefinite block). Don't forget: options are OPTIONS. Options should be used optionally not regularily. Or? > > The caller has a time budget. That's the total amount of time they're > prepared to wait for a result. Yes. This is the -evaltimeout limit. > > The underlying implementation may break the process down into sub > tasks, but the caller doesn't really care, or know about this. If you > look at the sub-tasks you might be able to say what a reasonable > timeout might be. But note: this is an optimisation. A single time > budget works for all the different sub-tasks, a special timeout for > some sub-task only allows that task to *fail* quicker. Yes. This is the intention. If you set -recvtimeout to 1000 and -evaltimeout to 10000 then you will wait for _something_ to come over up to 10000 msecs BUT if after 1000 msec you GET first byte of response you are prepared to wait max 1000 to get all bytes. This is very fine-grained. Because if you do not get all bytes within 1000 msesc, you might not trust the comm-channel (it may got severed). So what is the point of waiting longer? In the current implementation this is of course ridiculous: the comm channel is a pipe. But if we ever get this done over sockets, ite becomes quite important. > > It's not free though. You get the odd effect of failing with a timeout > when there's plenty of time left in the budget. Right! Because part of the communication link might be severed. Although your budged allows you to wait more, what good would that be? See the above example. > > The error handling is also weird. As it's currently implemented, > there's a different error code for each kind of timeout failure. This way the programmer knows EXACTLY what happened. > The > caller is forced to deal with all the different ways a timeout might > occur. With a generic NS_TIMEOUT errorCode this can be skipped, but > now you're loosing information. Yes. You are loosing the valuable info about the source of the error. > > I think it needs to keep stats on the different failures, with a > ns_proxy_stats command to track it. This is the data you will use to > help you size the pool according to load and server ability. This is a good idea. Such "counters" are mostly usable in tuning and optimizing. I agree to that fully. > > It's interesting to note that an individual error may not actually be > an error. The goal is to size the pool according to resources > available for maximum performance. If a caller times out because there > are no handles, well maybe the system is doing it's job? > > On the other hand, if 80% of the callers are failing dues to timeout, > well then you have a problem. Maybe your pool is undersized, or maybe > your server is overloaded. It's the percentage of failures which > determine whether there's a problem with the system. Yes. The statistics are most needed for corrrect tuning. > > > A single concept of timeout with statistics kept on failures would be > easier to implement and describe, would prevent spurious timeouts, and > would allow administrators to size the proxy pools. I would leave all those timeouts for fine-grained tuning and I would add statisctic counters for analisys and monitoring. |
From: Stephen D. <sd...@gm...> - 2006-10-06 22:39:06
|
On 10/6/06, Zoran Vasiljevic <zv...@ar...> wrote: > > On 06.10.2006, at 23:12, Stephen Deasey wrote: > > > On 10/4/06, Zoran Vasiljevic <zv...@ar...> wrote: > >> > >> On 03.10.2006, at 01:01, Stephen Deasey wrote: > >>> > >>> > >>> I was also wondering about the ns_proxy send/wait/receive. Why are > >>> wait and receive separate commands? > >> > >> Because you can wait, get the timeout, do something and then go > >> repeat > >> waiting. It makes sense. You can't achieve this with a longer wait > >> timeout OR with a timed [ns_proxy eval]. > >> Allright, you can argue: one can [ns_proxy receive proxy ?timeout?] > >> in which case you have the same behaviour. Correct. But what > >> difference > >> would it make, really? > > > > > > Two commands make it twice as hard to use. All that's needed is a > > timeout switch: > > > > set result [ns_proxy wait -timeout 10 $handle] > > > > Either way is OK. send/wait/recv is straight foward > and simpler if you usually HAVE to wait, whereas > send/wait_with_receive is more optimal if you mainly > don't need to wait (i.e. you tolerate indefinite block). > Don't forget: options are OPTIONS. Options should be > used optionally not regularily. Or? I would say the -timeout option would rarely be given. The situation will be similar to the cache command: in the common case a user calling the command will have the timeout set by the connection's timeout limit; for other callers, scheduled threads and so on, the default timeout for the pool will be used. If the timeout gets embedded at the call site it makes it difficult to admin the system as a whole. > > > > The caller has a time budget. That's the total amount of time they're > > prepared to wait for a result. > > Yes. This is the -evaltimeout limit. But the call may take longer than the caller budgeted for, due to all the hidden timeouts, which are additive. So the callers time budget is 5 seconds, and that's what they pass to -evaltimeout. But by default both the sendtimeout and recvtimeout are 5 seconds. So the total time spent on a successful call to ns_proxy eval could be over 15 seconds, which is 3x the time budget. The time budget is a single target value. In the future, for the majority of users, this is going to be set per URL. For /checkout you may allow up to 60 seconds to serve the page before deciding you're overloaded. For /ads you may give up much sooner. Your server is busy and you need to shed load, so you shed the least important traffic. For a single page with some time budget, which depends on the URL, some of it may be used up in a call to ns_cache_eval before there is a change to call ns_proxy eval. i.e. the time budget is pretty dynamic. I don't see how the multiple fine-grained settings of ns_proxy can be used effectively in the simple case of a web page with a time budget which runs multiple commands with timeouts. > > It's not free though. You get the odd effect of failing with a timeout > > when there's plenty of time left in the budget. > > Right! Because part of the communication link might be severed. > Although your budged allows you to wait more, what good would that > be? See the above example. Isn't a severed link a detectable error condition? The reaper will be notified of the child death, or a hypothetical socket implementation will have it's socket closed..? > > The error handling is also weird. As it's currently implemented, > > there's a different error code for each kind of timeout failure. > > This way the programmer knows EXACTLY what happened. Right. But what is the programmer going to differently when he gets a ESend vs. ERecv vs. EEval? Log it and continue. Maybe I'm not being imaginative enough...? I'm not saying you absolutely can't pass this back -- the error code could be the Tcl list {NS_TIMEOUT ESend}. I just can't see the use of it. Better not to bug the programmer, log the fault for statistical analysis, and move on. Or, how about this. If it's agreed that these are fine tunings, could they perhaps default to -1, and in that case the single timeout (which is currently the eval timeout?) is used for everything until it runs out? |
From: Zoran V. <zv...@ar...> - 2006-10-07 13:09:14
|
On 07.10.2006, at 00:39, Stephen Deasey wrote: > > But the call may take longer than the caller budgeted for, due to all > the hidden timeouts, which are additive. > True. > So the callers time budget is 5 seconds, and that's what they pass to > -evaltimeout. But by default both the sendtimeout and recvtimeout are > 5 seconds. So the total time spent on a successful call to ns_proxy > eval could be over 15 seconds, which is 3x the time budget. > > The time budget is a single target value. In the future, for the > majority of users, this is going to be set per URL. For /checkout you > may allow up to 60 seconds to serve the page before deciding you're > overloaded. For /ads you may give up much sooner. Your server is busy > and you need to shed load, so you shed the least important traffic. > > For a single page with some time budget, which depends on the URL, > some of it may be used up in a call to ns_cache_eval before there is a > change to call ns_proxy eval. i.e. the time budget is pretty dynamic. > > I don't see how the multiple fine-grained settings of ns_proxy can be > used effectively in the simple case of a web page with a time budget > which runs multiple commands with timeouts. How would you handle this issue then? Given you have 5 seconds budget to run the proxy command and the fact that running the command involves round-trips to some remote proxy on another host, how would you implement that? You have to send the data to the proxy and then you need to wait for all the data to come back. Would you break the potentially valid request because it needs 5.01 secs to get the last byte transfered back just because your total limit was set to 5 seconds? If you can give a good solution, I will implement that immediately. > > >>> It's not free though. You get the odd effect of failing with a >>> timeout >>> when there's plenty of time left in the budget. >> >> Right! Because part of the communication link might be severed. >> Although your budged allows you to wait more, what good would that >> be? See the above example. > > > Isn't a severed link a detectable error condition? The reaper will be > notified of the child death, or a hypothetical socket implementation > will have it's socket closed..? Not necessarily ( a detectable condition). If the remote proxy is on other host and somebody cuts the wire, you get no error. You need to timeout sometimes. > > >>> The error handling is also weird. As it's currently implemented, >>> there's a different error code for each kind of timeout failure. >> >> This way the programmer knows EXACTLY what happened. > > > Right. > > But what is the programmer going to differently when he gets a ESend > vs. ERecv vs. EEval? Log it and continue. Maybe I'm not being > imaginative enough...? No, you are right. There is not much he can do except to log that and move on. But the fact that he KNOWS what was the error he CAN log better. > > I'm not saying you absolutely can't pass this back -- the error code > could be the Tcl list {NS_TIMEOUT ESend}. I just can't see the use of > it. > > Better not to bug the programmer, log the fault for statistical > analysis, and move on. YES. Actually who logs it is not that important, just the fact that this should be logged is important. Seeing it from this perspective, it is really better to give a "generic" timeout and adjust statistics rather than expose _exact_ errorcode up to the script level. I can agree with you on that point. > > > Or, how about this. If it's agreed that these are fine tunings, could > they perhaps default to -1, and in that case the single timeout (which > is currently the eval timeout?) is used for everything until it runs > out? Hmhmhm.... tempting... but would be a victim of: I waited 1 minute for 100-byte result, got 99 of 100 bytes and the timeout expired. I consider the request timeouted and break. But the peer would return the last byte in perhaps 10 msec... Too bad. Lets see what you thing about this. But if we make this change, then we need no counters of errors at various places because they will make no sense. Effectively we have a budget of -evaltimeout which is divided across all possible points where we will/must wait. A timeout expiring at any of this point has no meaningfull information at all any more. Right? > > ---------------------------------------------------------------------- > --- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to > share your > opinions on IT & business topics through brief surveys -- and earn > cash > http://www.techsay.com/default.php? > page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > naviserver-devel mailing list > nav...@li... > https://lists.sourceforge.net/lists/listinfo/naviserver-devel |
From: Stephen D. <sd...@gm...> - 2006-10-07 15:23:17
|
On 10/7/06, Zoran Vasiljevic <zv...@ar...> wrote: > > On 07.10.2006, at 00:39, Stephen Deasey wrote: > > > > > But the call may take longer than the caller budgeted for, due to all > > the hidden timeouts, which are additive. > > > > True. > > > So the callers time budget is 5 seconds, and that's what they pass to > > -evaltimeout. But by default both the sendtimeout and recvtimeout are > > 5 seconds. So the total time spent on a successful call to ns_proxy > > eval could be over 15 seconds, which is 3x the time budget. > > > > The time budget is a single target value. In the future, for the > > majority of users, this is going to be set per URL. For /checkout you > > may allow up to 60 seconds to serve the page before deciding you're > > overloaded. For /ads you may give up much sooner. Your server is busy > > and you need to shed load, so you shed the least important traffic. > > > > For a single page with some time budget, which depends on the URL, > > some of it may be used up in a call to ns_cache_eval before there is a > > change to call ns_proxy eval. i.e. the time budget is pretty dynamic. > > > > I don't see how the multiple fine-grained settings of ns_proxy can be > > used effectively in the simple case of a web page with a time budget > > which runs multiple commands with timeouts. > > How would you handle this issue then? > Given you have 5 seconds budget to run the proxy command > and the fact that running the command involves round-trips > to some remote proxy on another host, how would you implement > that? You have to send the data to the proxy and then you need > to wait for all the data to come back. Would you break the > potentially valid request because it needs 5.01 secs to get the > last byte transfered back just because your total limit was set to > 5 seconds? > > If you can give a good solution, I will implement that immediately. The caller doesn't have a time budget for executing the code in the slave, they have a budget for sending the code, executing it, and receiving the result. So yes, if it takes 5.01 secs with one byte remaining, you fail. No crystal ball. Exactly the same problem arises if you have an additional timeout of 1sec for receiving the result. What if it takes 1.01 sec with one byte remaining? Where do you draw the line? The difference is that now you've implicitly stated that your time budget is 6 secs, but you're less flexible because you've partitioned it. Increasing the original time budget to 6 secs would have exactly the same effect, but avoid spurious errors due to timeouts on one counter with time remaining on the other. > But if we make this change, then we need no counters of errors at > various places because they will make no sense. Effectively > we have a budget of -evaltimeout which is divided across all > possible points where we will/must wait. A timeout expiring at > any of this point has no meaningfull information at all any more. > Right? No, you still need to count each error type. The caller of the code can't do much at the time to solve the problem, but someone needs to solve it, and to do that you need information. So for example, if the code was timing out sending code to the slave, you won't tune the code in the slave to be faster because that's not the problem. If you're timing out in the mutex wait for a slave handle, maybe the pool size needs to be increased. Perhaps the fact that *some* bytes have been received but the receive timed out can be used to distinguish the case where a slave successfully executes but the comm channel fails? The more useful info we can gather the better, I think. |
From: Zoran V. <zv...@ar...> - 2006-10-07 15:38:05
|
On 07.10.2006, at 17:23, Stephen Deasey wrote: > > The caller doesn't have a time budget for executing the code in the > slave, they have a budget for sending the code, executing it, and > receiving the result. So yes, if it takes 5.01 secs with one byte > remaining, you fail. No crystal ball. OK. > > The more useful info we can gather the better, I think. Allright. I buy this. So, trash all those timeouts, apply a general (-evaltimeout) to the whole request and bite off that time as we hop thru the processs. At any point where we had to give-up because ot the timeout, we maintain a counter of errors for that spot. That was a hard birth... but I believe we now all have the clear picture about that aspect. What remains: naming of the module API (handle vs. handle-free) > > ---------------------------------------------------------------------- > --- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to > share your > opinions on IT & business topics through brief surveys -- and earn > cash > http://www.techsay.com/default.php? > page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > naviserver-devel mailing list > nav...@li... > https://lists.sourceforge.net/lists/listinfo/naviserver-devel |
From: Vlad S. <vl...@cr...> - 2006-10-07 15:42:01
|
> What remains: > > naming of the module > API (handle vs. handle-free) > > > ns_exec or ns_slave i would keep both API, so i would decide in each particular case when to use which, i do not think they are mutual exclusive |
From: Zoran V. <zv...@ar...> - 2006-09-19 08:16:37
|
On 18.09.2006, at 20:55, Stephen Deasey wrote: > API: > > result ns_exec_eval ?-pool p? ?-timeout t? script > > Id ns_exec_queue ?-detached? ?-pool p? ?-timeout t? script > ns_exec_wait ?-timeout t? Id ?Id ...? > ns_exec_cancel > > ns_exec_set ?-opt val ...? pool > ns_exec_stats pool > > Example: > > set result [ns_exec_eval { > set x y > exec /bin/blah $x > }] > > Notes: > > Create pool 'default' on startup. > > Reuse identical processes (same binary, ulimits, etc.) among > pools, in > the same way that threads are shared globally among ns_job > queues. > > 'maxexecs' parameter, after which processes exit and are > respawned. First impression: a. I'd rather use ns_cmdtobenamed queue pool ... ns_cmdtobenamed eval pool ... Two things here: ns_exec_command I do not like. The "Tcl" way would be actually to use a namespace to encapsulate all commands but that would break the current style. The oher thing, I do not like the "default" pool. I think the pool (being the place to put common things shared across all slaves) should be given explicitly. b. If we go that far then ns_exec_xxx is also not a suitable name as we are not exec'ing anything really. But lets go two steps back... You say you wanted to get ns_job and ns_proxy together. You also say that this is not feasible because of the "eval" command. Why? The ns_job could be expanded easily to integrate the "eval" command, but it would not make much sense (i.e. practical use). OTOH, the ns_proxy eval has much sense (i.e. practical use). Given that, in my opinion, [ns_job eval] would not harm anybody, why _not_ integrating both? Instead of aueue of threads, youd create queue of processes. Most (if not all) of other ns_job commands will just be "blind" in terms of threads vs. processes. Each process would actually be the nsd itself but using alternate Ns_Main function. It would load the libnsd.so, read the same (or alternate) configuration file, etc. pp. This way the API question is solved. The work to be done is pretty clear (rewrite ns_job internals to allow handling of processes in addition to threads). Is there a very good reason why not going that way instead of maintaining the proxy module ? |
From: Stephen D. <sd...@gm...> - 2006-10-04 05:09:39
|
On 9/19/06, Zoran Vasiljevic <zv...@ar...> wrote: > > But lets go two steps back... > > You say you wanted to get ns_job and ns_proxy together. You also say > that this is not feasible because of the "eval" command. > Why? > The ns_job could be expanded easily to integrate the "eval" command, > but it would not make much sense (i.e. practical use). Well, exactly -- it doesn't make any sense. I think it would be a mistake to encourage people to do the wrong thing. There was a guy on the AOLserver list the other day, obviously experienced and smart, who 'forgot' that the proxy script ran in an external process, when that's basically the entire point, right? If we give people an ns_job eval command, they'll get confused about the purpose of job pools, too. I'm not sure how much real code sharing there would be between a combined job/proxy module. The back ends are different, processes can have more limits, the focus on parallelism versus isolation... > The oher thing, I do not like the "default" pool. I think the pool > (being the place to put common things shared across all slaves) > should be given explicitly. It would allow a simple 'set' command to configure parameters, like the limits stuff. The proxy pool 'default' already exists, and then you adjust it if you need to. With a default pool, we could alias the Tcl 'exec' command to run in a proxy pool. Although you can configure the binary to bootstrap the proxy processes, that's probably going to be rare. In fact most situations would probably be covered by a sane, default setup. If there's no default pool, then all user code which uses nsproxy will create it's own pool. With multiple pools there may be some which run out of resources while others have spare -- the pools are a hard partitioning of resources. > b. If we go that far then ns_exec_xxx is also not a suitable name as > we are not exec'ing anything really. A common reason to use the proxy module is to isolate calls to the Tcl exec command. The proxies must also execute an external process (default nsproxy). Just trying to get away from 'proxy'. Maybe something with 'ext', for 'external' in the name? |
From: Rick C. <rc...@Kn...> - 2006-10-04 05:26:47
|
Uh, maybe "ns_process"? -- ReC -----Original Message----- From: nav...@li... [mailto:nav...@li...] On Behalf Of Stephen Deasey Sent: Monday, October 02, 2006 3:06 PM To: nav...@li... Subject: Re: [naviserver-devel] nsproxy API On 9/19/06, Zoran Vasiljevic <zv...@ar...> wrote: > > But lets go two steps back... > > You say you wanted to get ns_job and ns_proxy together. You also say > that this is not feasible because of the "eval" command. > Why? > The ns_job could be expanded easily to integrate the "eval" command, > but it would not make much sense (i.e. practical use). Well, exactly -- it doesn't make any sense. I think it would be a mistake to encourage people to do the wrong thing. There was a guy on the AOLserver list the other day, obviously experienced and smart, who 'forgot' that the proxy script ran in an external process, when that's basically the entire point, right? If we give people an ns_job eval command, they'll get confused about the purpose of job pools, too. I'm not sure how much real code sharing there would be between a combined job/proxy module. The back ends are different, processes can have more limits, the focus on parallelism versus isolation... > The oher thing, I do not like the "default" pool. I think the pool > (being the place to put common things shared across all slaves) > should be given explicitly. It would allow a simple 'set' command to configure parameters, like the limits stuff. The proxy pool 'default' already exists, and then you adjust it if you need to. With a default pool, we could alias the Tcl 'exec' command to run in a proxy pool. Although you can configure the binary to bootstrap the proxy processes, that's probably going to be rare. In fact most situations would probably be covered by a sane, default setup. If there's no default pool, then all user code which uses nsproxy will create it's own pool. With multiple pools there may be some which run out of resources while others have spare -- the pools are a hard partitioning of resources. > b. If we go that far then ns_exec_xxx is also not a suitable name as > we are not exec'ing anything really. A common reason to use the proxy module is to isolate calls to the Tcl exec command. The proxies must also execute an external process (default nsproxy). Just trying to get away from 'proxy'. Maybe something with 'ext', for 'external' in the name? ------------------------------------------------------------------------ - Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=3Djoin.php&p=3Dsourceforge&CID=3D= DEVDE V _______________________________________________ naviserver-devel mailing list nav...@li... https://lists.sourceforge.net/lists/listinfo/naviserver-devel |
From: Zoran V. <zv...@ar...> - 2006-10-04 08:03:32
|
On 03.10.2006, at 00:05, Stephen Deasey wrote: > > I'm not sure how much real code sharing there would be between a > combined job/proxy module. The back ends are different, processes can > have more limits, the focus on parallelism versus isolation... Apart from the "unified" API there would be no other "benefits". Code sharing would be rather minimal. It would perhaps be easier to use since you do not need to remember just-another-api. But I'm perfectly happy with both. We would have to find a consensus on that and I'll do it. > > >> The oher thing, I do not like the "default" pool. I think >> the pool >> (being the place to put common things shared across all slaves) >> should be given explicitly. > > > It would allow a simple 'set' command to configure parameters, like > the limits stuff. The proxy pool 'default' already exists, and then > you adjust it if you need to. > Hmmm... set "what"? > With a default pool, we could alias the Tcl 'exec' command to run in a > proxy pool. This is the good reason. > > Although you can configure the binary to bootstrap the proxy > processes, that's probably going to be rare. In fact most situations > would probably be covered by a sane, default setup. True. > > If there's no default pool, then all user code which uses nsproxy will > create it's own pool. With multiple pools there may be some which run > out of resources while others have spare -- the pools are a hard > partitioning of resources. True. But pools are there because of the different: timers initialization scripts I use the nsproxy in 2 places in the code now. Both require different init scripts. One requires indefinite timer (like simple exec) and the one "can" kill the process if the computation went more than 30 seconds. It is true what you say about partitioning of resources, though... Still, when I have to choose, I'd rather opt for explicit pool rather than having a "default" pool. I'd really leave this to the programmer. The programmer can do trivial Tcl wrapper to redirect Tcl exec to the proxy if needed. > > >> b. If we go that far then ns_exec_xxx is also not a suitable >> name as >> we are not exec'ing anything really. > > > A common reason to use the proxy module is to isolate calls to the Tcl > exec command. The proxies must also execute an external process > (default nsproxy). Just trying to get away from 'proxy'. Maybe > something with 'ext', for 'external' in the name? To summarize. What you object is: a. handle management (should work without handles) b. name of the module (should not be proxy) c. invent default pool d. ? For a: I understand the syntactical need, but this is how I see that from the practical side. By having a handle, I can run "things" in the proxy (lets call it slave process from now on) one after another with a possible "state" between the runs. This might sometimes be needed. If I hide the handle, how could I force my two or three consecutive operations to be executed in the same slave? For b. I do not care how we call it. We can call it ns_cocacola if you like. The name contest is open... For c. I'd rather stick to explicit pool naming. I'd leave this "default" to the programmer. The programmer might do something like (not 100% right but serves the illustration purpose): ns_proxy config default rename ::exec tcl::exec proc ::exec args { ns_proxy eval default $args } This covers overloading of Tcl exec command. If you can convince me that there are other benefits of having the default pool I can think about them. I just do not see any at this point. |
From: Zoran V. <zv...@ar...> - 2006-10-06 17:27:06
|
On 04.10.2006, at 10:03, Zoran Vasiljevic wrote: > To summarize. What you object is: > > a. handle management (should work without handles) > b. name of the module (should not be proxy) > c. invent default pool > d. ? > > > For a: > I understand the syntactical need, but this is how I see that from > the practical side. By having a handle, I can run "things" in the > proxy (lets call it slave process from now on) one after another with > a possible "state" between the runs. This might sometimes be needed. > If I hide the handle, how could I force my two or three consecutive > operations to be executed in the same slave? > > For b. > I do not care how we call it. We can call it ns_cocacola if you like. > The name contest is open... > > For c. > I'd rather stick to explicit pool naming. I'd leave this "default" > to the programmer. The programmer might do something like > (not 100% right but serves the illustration purpose): > > ns_proxy config default > rename ::exec tcl::exec > proc ::exec args { > ns_proxy eval default $args > } > > This covers overloading of Tcl exec command. If you can convince me > that there are other benefits of having the default pool I can > think about them. I just do not see any at this point. So, how we are about to proceed on this matter? Are there any comments/ideas about naming? Handle managment? What I'd say is (in a nutshell): a. I think handles should be left as is (after all you also open a file, get the handle and then use it to write/read, or?) b. I do not like the name very much but I can't think of better. c. I would not "invent" a default pool. I would leave this to the programmer. The default pool just does not fit in and it would make the API more (instead of less) complicated. Overall, I'm more/less happy with what we have now. I could imagine adding some more config options to limit the resources in the slave (memory, number of open files, absolute execution time etc) but this can be added during regular maintenance. The most important thing now is to freeze the API. The API is now well-documented and I invite everybody to read it and suggest better one so we can vote. I have no vested interest. I will bow to the will of the majority. Cheers, Zoran |
From: Vlad S. <vl...@cr...> - 2006-10-06 17:41:20
|
I am not using it so i have nothing to add to existing API. As for the name, maybe ns_process or ns_exec ? Zoran Vasiljevic wrote: > On 04.10.2006, at 10:03, Zoran Vasiljevic wrote: > >> To summarize. What you object is: >> >> a. handle management (should work without handles) >> b. name of the module (should not be proxy) >> c. invent default pool >> d. ? >> >> >> For a: >> I understand the syntactical need, but this is how I see that from >> the practical side. By having a handle, I can run "things" in the >> proxy (lets call it slave process from now on) one after another with >> a possible "state" between the runs. This might sometimes be needed. >> If I hide the handle, how could I force my two or three consecutive >> operations to be executed in the same slave? >> >> For b. >> I do not care how we call it. We can call it ns_cocacola if you like. >> The name contest is open... >> >> For c. >> I'd rather stick to explicit pool naming. I'd leave this "default" >> to the programmer. The programmer might do something like >> (not 100% right but serves the illustration purpose): >> >> ns_proxy config default >> rename ::exec tcl::exec >> proc ::exec args { >> ns_proxy eval default $args >> } >> >> This covers overloading of Tcl exec command. If you can convince me >> that there are other benefits of having the default pool I can >> think about them. I just do not see any at this point. > > > So, how we are about to proceed on this matter? > Are there any comments/ideas about naming? Handle managment? > > What I'd say is (in a nutshell): > > a. I think handles should be left as is (after all you also open > a file, get the handle and then use it to write/read, or?) > > b. I do not like the name very much but I can't think of better. > > c. I would not "invent" a default pool. I would leave this to the > programmer. The default pool just does not fit in and it would > make the API more (instead of less) complicated. > > Overall, I'm more/less happy with what we have now. I could imagine > adding some more config options to limit the resources in the slave > (memory, number of open files, absolute execution time etc) but this > can be added during regular maintenance. The most important thing > now is to freeze the API. The API is now well-documented and I > invite everybody to read it and suggest better one so we can vote. > I have no vested interest. I will bow to the will of the majority. > > Cheers, > Zoran > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys -- and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > 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: Stephen D. <sd...@gm...> - 2006-10-06 19:25:36
|
On 10/4/06, Zoran Vasiljevic <zv...@ar...> wrote: > > To summarize. What you object is: > > a. handle management (should work without handles) > b. name of the module (should not be proxy) > c. invent default pool > d. ? > > > For a: > I understand the syntactical need, but this is how I see that from > the practical side. By having a handle, I can run "things" in the > proxy (lets call it slave process from now on) one after another with > a possible "state" between the runs. This might sometimes be needed. > If I hide the handle, how could I force my two or three consecutive > operations to be executed in the same slave? That's a good point. The same problem arises in the higher level db APIs. If handle management is transparent, how do you send multiple statement to a single db back end, such as to implement transactions or "select for update" and so on? dbi_withhandle { dbi_dml "update foo ..." dbi_dml "update bar ..." } But what I'm wondering is, why you need to do this with proxy slaves? It seems like they don't have the same state problem that a series of database statements do. It's possible to send multiple Tcl commands to a single proxy slave at the same time: ns_proxy eval { set f [do_foo ...] set b [do_bar ...] return [list $f $b] } (You can't do that with databases because they often forbid using a statement separating semicolon when using prepared statements and/or bind variables. But Tcl doesn't have that restriction.) I can imagine some kind of if-then between the two statements. When does it become impossible to do this in the proxy slave? When do you have to do this instead?: ns_proxy withhandle { set f [ns_proxy eval {do_foo ...}] ... if {$f ...} { set b [ns_proxy eval {do bar ...}] } } If it's not possible to send all the code to the proxy slave at once, then you can use something like the withhandle command to batch multiple calls to eval on the same handle. This does have some disadvantages to running both statements in a single call to 'eval'. For example, any time budget you have for the statements as a whole must be split between each. So, if you decide each call should take only 30 secs, and the first call takes 1 sec but the second takes 31 secs, you will get a timeout error with almost half your total time budget still to spend. But you would have been perfectly happy to wait 58 seconds in total, spread evenly between the two calls. Another problem might be the code you run in between the two eval calls. In the case of explicit handle management or the withhandle command, the handle is kept open even when it is not being used. If the code that runs between the two eval calls takes some time -- perhaps because it blocks on IO, which may not be apparent to the caller -- then other threads may be prevented from using a proxy slave because the pool is empty. Handles which could have been returned to the pool and used by other callers are sitting idle in threads busy doing other things. This is a (temporary, mostly) resource leak. So, apart from state (if this is needed), the withhandle command is a speed optimisation. If you know for a fact that you're going to have to make sequential calls to the proxy system, you can take the pool lock just once. Otherwise, with implicit handle management, you take and release the pool lock for each evaluation. Regardless, the withhandle command allows implicit handle management in the common case, and a nice, clear syntax for when you explicitly want to manage the handle for performance or state reasons. > For b. > I do not care how we call it. We can call it ns_cocacola if you like. > The name contest is open... It's an annoying thing to have to even bother about... But it is important. If it's not clear, people will be confused, we've seen a lot of that. Confused people take longer to get up to speed. People like new hires, which costs real money. > For c. > I'd rather stick to explicit pool naming. I'd leave this "default" > to the programmer. The programmer might do something like > (not 100% right but serves the illustration purpose): > > ns_proxy config default > rename ::exec tcl::exec > proc ::exec args { > ns_proxy eval default $args > } > > This covers overloading of Tcl exec command. If you can convince me > that there are other benefits of having the default pool I can > think about them. I just do not see any at this point. A default only makes sense if it's built in. If it isn't, no on can rely on it and all code that uses proxy pools will have to create their own. Even with a built-in default, user code can certainly still create it's own proxy pool(s). Nothing is being taken away. If it was unlikely that the default would work for much/most code, then it would be wrong to have one. That would be hiding something from programmers that they should be paying attention to. It looks to me though like a default pool would work for most code. But this is just a convenience. To manage resources efficiently you need the default pool. I can imagine 'exec' using the default pool, and 3rd party modules doing something like: ns_proxy eval -pool [ns_configvalue ... pool default] { .... } Which will just work. The site administrator can then allocate resources in a more fine grained way, if needed, according to the local situation. |
From: Vlad S. <vl...@cr...> - 2006-10-06 20:22:43
|
I vote for ns_exec and putting it into the core Zoran Vasiljevic wrote: > On 06.10.2006, at 21:25, Stephen Deasey wrote: > >> But what I'm wondering is, why you need to do this with proxy slaves? >> It seems like they don't have the same state problem that a series of >> database statements do. >> >> It's possible to send multiple Tcl commands to a single proxy slave at >> the same time: >> >> ns_proxy eval { >> set f [do_foo ...] >> set b [do_bar ...] >> return [list $f $b] >> } >> >> (You can't do that with databases because they often forbid using a >> statement separating semicolon when using prepared statements and/or >> bind variables. But Tcl doesn't have that restriction.) > > I do not need it. As, as you say, I can simply send all of them > in one script. That's trivial of course. > > I give you another reason pro-handle: I'd like to allocate > the handle in order to have it always (for a longer time) > available. I "reserve" it, so to speak. If I can't do that > than my code is less "predictive" in terms that I might wait > potentially for a long time to get the chance to do something > as all proxies might be doing something else. Understand? > >> For example, any time budget you have for the statements as a whole >> must be split between each. So, if you decide each call should take >> only 30 secs, and the first call takes 1 sec but the second takes 31 >> secs, you will get a timeout error with almost half your total time >> budget still to spend. But you would have been perfectly happy to wait >> 58 seconds in total, spread evenly between the two calls. >> >> Another problem might be the code you run in between the two eval >> calls. In the case of explicit handle management or the withhandle >> command, the handle is kept open even when it is not being used. If >> the code that runs between the two eval calls takes some time -- >> perhaps because it blocks on IO, which may not be apparent to the >> caller -- then other threads may be prevented from using a proxy slave >> because the pool is empty. Handles which could have been returned to >> the pool and used by other callers are sitting idle in threads busy >> doing other things. This is a (temporary, mostly) resource leak. >> > > Yes. This is true. And this is obviously a contra-handle as it > may lead to starvation. > >> So, apart from state (if this is needed), the withhandle command is a >> speed optimisation. If you know for a fact that you're going to have >> to make sequential calls to the proxy system, you can take the pool >> lock just once. Otherwise, with implicit handle management, you take >> and release the pool lock for each evaluation. >> >> Regardless, the withhandle command allows implicit handle management >> in the common case, and a nice, clear syntax for when you explicitly >> want to manage the handle for performance or state reasons. > > I must think this over... > >> >>> For b. >>> I do not care how we call it. We can call it ns_cocacola if you like. >>> The name contest is open... >> >> It's an annoying thing to have to even bother about... But it is >> important. If it's not clear, people will be confused, we've seen a >> lot of that. Confused people take longer to get up to speed. People >> like new hires, which costs real money. > > So, how would we call the baby? Why not just simply ns_exec? > Actually, we can build this into the core server and not as > module... The ns_exec could exec the same executable with > different command-line args that would select other main > function and not Ns_Main, for example. I'm just thinking "loud"... > >> >>> For c. >>> I'd rather stick to explicit pool naming. I'd leave this "default" >>> to the programmer. The programmer might do something like >>> (not 100% right but serves the illustration purpose): >>> >>> ns_proxy config default >>> rename ::exec tcl::exec >>> proc ::exec args { >>> ns_proxy eval default $args >>> } >>> >>> This covers overloading of Tcl exec command. If you can convince me >>> that there are other benefits of having the default pool I can >>> think about them. I just do not see any at this point. >> >> A default only makes sense if it's built in. If it isn't, no on can >> rely on it and all code that uses proxy pools will have to create >> their own. > > OK. > >> Even with a built-in default, user code can certainly still create >> it's own proxy pool(s). Nothing is being taken away. >> > > True. > >> If it was unlikely that the default would work for much/most code, >> then it would be wrong to have one. That would be hiding something >> from programmers that they should be paying attention to. It looks to >> me though like a default pool would work for most code. But this is >> just a convenience. >> >> To manage resources efficiently you need the default pool. I can >> imagine 'exec' using the default pool, and 3rd party modules doing >> something like: >> >> ns_proxy eval -pool [ns_configvalue ... pool default] { >> .... >> } >> >> Which will just work. The site administrator can then allocate >> resources in a more fine grained way, if needed, according to the >> local situation. >> > > And if we put the ns_exec into the server and make it like this: > > ns_exec eval arg ?arg...? > ns_exec eval -pool thepool arg ?arg ...? > ns_exec config thepool option ?value option value ...? > > etc ? Or ns_slave? > > ns_slave eval arg > ns_slave config thepool option ?value option value ...? > > Hm... that's not bad. What do you think? > I think ns_slave would be "opportune". The people will of course > immediately ask: where is ns_master? But I guess you can't dance > on all weddings... > > Still, I will have to think about the "handle" issue for some time > (over the weekend) as I'm still not 100% convinced... > > Would you integrate that in the core code or would you leave this > as a module? Actually, I keeep asking mylself why we still stick to > modules when some fuctionality is obviously needed all the time > (nslog or nscp for example)... > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys -- and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > 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: Vlad S. <vl...@cr...> - 2006-09-19 13:32:24
|
I like the idea of extending ns_job to handle processes, this way when i create queue i define what kind it is: threads or processes and then use it same way, no need in eval command, ns_job queue submites script to be evaluated to the next avail thread/process Zoran Vasiljevic wrote: > On 18.09.2006, at 20:55, Stephen Deasey wrote: > >> API: >> >> result ns_exec_eval ?-pool p? ?-timeout t? script >> >> Id ns_exec_queue ?-detached? ?-pool p? ?-timeout t? script >> ns_exec_wait ?-timeout t? Id ?Id ...? >> ns_exec_cancel >> >> ns_exec_set ?-opt val ...? pool >> ns_exec_stats pool >> >> Example: >> >> set result [ns_exec_eval { >> set x y >> exec /bin/blah $x >> }] >> >> Notes: >> >> Create pool 'default' on startup. >> >> Reuse identical processes (same binary, ulimits, etc.) among >> pools, in >> the same way that threads are shared globally among ns_job >> queues. >> >> 'maxexecs' parameter, after which processes exit and are >> respawned. > > First impression: > > a. I'd rather use ns_cmdtobenamed queue pool ... > ns_cmdtobenamed eval pool ... > > Two things here: ns_exec_command I do not like. The "Tcl" way > would > be actually to use a namespace to encapsulate all commands but > that > would break the current style. > The oher thing, I do not like the "default" pool. I think the pool > (being the place to put common things shared across all slaves) > should be given explicitly. > > b. If we go that far then ns_exec_xxx is also not a suitable name as > we are not exec'ing anything really. > > But lets go two steps back... > > You say you wanted to get ns_job and ns_proxy together. You also say > that this is not feasible because of the "eval" command. > Why? > The ns_job could be expanded easily to integrate the "eval" command, > but it would not make much sense (i.e. practical use). OTOH, the > ns_proxy eval has much sense (i.e. practical use). Given that, in my > opinion, [ns_job eval] would not harm anybody, why _not_ integrating > both? > Instead of aueue of threads, youd create queue of processes. Most (if > not all) of other ns_job commands will just be "blind" in terms of > threads vs. processes. Each process would actually be the nsd itself > but using alternate Ns_Main function. It would load the libnsd.so, read > the same (or alternate) configuration file, etc. pp. > > This way the API question is solved. The work to be done is pretty clear > (rewrite ns_job internals to allow handling of processes in addition to > threads). > > Is there a very good reason why not going that way instead of > maintaining the proxy module ? > > > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys -- and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > 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-09-19 13:42:26
|
On 19.09.2006, at 15:32, Vlad Seryakov wrote: > I like the idea of extending ns_job to handle processes, this way > when i > create queue i define what kind it is: threads or processes and > then use > it same way, no need in eval command, ns_job queue submites script > to be > evaluated to the next avail thread/process Yes. This what I also thought after seeing the similarities between the two. Normally you should create a thread or process queue and after that, it should be pretty generic i.e. the API would hide the rest from you. But Stephen has confused me with his last email about problems in "eval" command, which I can't see. |
From: Zoran V. <zv...@ar...> - 2006-09-19 14:59:39
|
On 19.09.2006, at 15:42, Zoran Vasiljevic wrote: > But Stephen has confused me with his last email about problems > in "eval" command, which I can't see. > Actually we do not need the "eval" at all! It is sufficient to: ns_job queue ns_job wait and whoever wants a "eval" can couple those two with a tiny Tcl procedure. Even in the current proxy, the eval is nothing but a sequence of send wait recv (it is really implemented so down below). |