Forum OpenACS Development: Re: Usage of XoTCL objects vs. database queries
I'm afraid but I get the impression that you confuse some matters here ...
tread-safety vs. resource sharing in concurrency modes
my assumption was that the XoTCL Objects are thread safe within AOLserver.
XOTcl _as C extension_ is perfectly thread-safe in the sense of being deployed in thread-enabled tcl interpreters. What you refer to is the ability of sharing XOTcl objects as resources under concurrency, e.g. between several threads. And this is not possible, though this is more related to underlying Tcl than XOTcl. in the context of the tclthread extension, there is resource sharing under certain limitations (shared thread vars + shared channels, for instance). The issue here is that you cannot share commands and procs, as far as I know due to the current setup of 1-interpreter-per-thread. This also applies to XOTcl objects which certainly built upon the same low-level infrastructure as Tcl procs and commands. Currently, there is no BLACKBOARD kind of architecture in a scripted multi-threaded tcl applications realisable. Zoran, however, also discusses a BLACKBOARD-like architecture based on naviserver over at naviserver-devel (can't find the link right now).
Future Tcl will come with with another concurrency technique called coroutines that will allow concurrency programming based on a model that is not that strict in terms of resource sharing.
I hoped there was an easy way to share an object among all threads and all clusters and that an object
as far as i know, you experimented with streaming/ serialising objects into ns_cache (another thread-shared space), didn't you?
I knew about the methods needing to reside in the interpreter-per-thread, what I was unsure about is if the XoTCL methods are loaded into the interpreter separately from the object, but thinking about the ability to mixin objects and overlay object methods, that might not be going to work.
As you pointed out, the serializing of an object works very nice for caching purposes. But this does not allow me to access the object in multiple threads except through the single point of entry (in my example "get_instance_from_db"). So yes, if I want to instantiate an object from the DB and prohibit me going to the DB all the time, ns_cache works like a charm as I can instantiate the object in the current thread through "get_instance_from_db" from the one stored in the ns_cache instead of the db. But it's not the same as using the same object copy in memory, as each thread has it's own copy of the ns_cache object and I can manipulate each of them independently.
So, it is a TCL issue with not having a place to store variables and methods in a global, thread independent place, yet access it in each thread with the option to overlay it in each thread. Would ttrace help here (http://wiki.tcl.tk/2770) ? Probably not, because it still requires me to make the object known to the thread and creating a resource copy in that thread.
Thanks again for you answers, I understand the issue now much better and stay happy that I have the persistent "cross threads" tool called database to use .
Would ttrace help here (http://wiki.tcl.tk/2770) ? Probably not, because it still requires me to make the object known to the thread and creating a resource copy in that thread.
You already hinted it, ttrace addresses a different issue. ttrace does not realise sharing of commands, procs (and objects), it solves the problem of the eager initialisation of interpreters. Based on Tcl's unknown mechanism, it sources procs on demand. This helps to address the issue of AOLServer/ Naviservers extensive blueprinting need ... unfortunately, it provides challenges to tcl's (and xotcl's) introspection mechanism which assume an entirely initialised surrounding ...
But it's not the same as using the same object copy in memory, as each thread has it's own copy of the ns_cache object and I can manipulate each of them independently.
Indeed, you don't have a shared state, compartimentalised into objects, available. If you try to achieve that, you may choose a different strategy: Realise object representations by ns_set et al. ... XOTcl slots provide an elegant way of introducing such an representation strategy, instead of accessing per-object state (in the strict sense), the slot-provided accessor/mutator methods write to and read from ns_sets ... Well, this implies other remedies and might not be scalabale open-end, but may be a valid optimisation strategy ... Objects residing in each thread are then mere PROXIES to a single shared state, under a single, db-provided identity.
tsv::lock makes it easy to atomically perform multiple tsv commands, which might be ideal for implementing that sort of safe transparent multi-threaded object access in XOTcl.
Malte, of course Tcl has such a place, it's called "nsv" (in AOLserver; in the Tcl Threads Extension the same thing is called "tsv").
Of course, nsv/tsv supports only base Tcl types, strings and in some cases more complicated values like lists (with Zoran's clever perforamance hacks to avoid type shimmering). Can all the XOTcl objects you care about be serialized to from nsv/tsv? Efficiently? Between the two of them, Gustaf and Zoran should be able to tell you for sure.
Another option is to dedicate one single thread (and its associated Tcl interpretor) as your "XOTcl db" thread. Then have other threads send it messages with requests to read/write data. Everything will be serialized through that single "db" thread of course. In theory that could be much less scalable than the hash bucketized multi-threaded design of nsv/tsv, but in practice it might be simpler and faster, especially if the XOTcl objects are large but the read/write requests are small.
Can all the XOTcl objects you care about be serialized to from nsv/tsv?Sure, the serialization of an XOTcl object is a string, such strings can be saved in nsvs, one can use the ttrace mechanism, etc. By serializing and deserializing objects, one creates a copy of the object. So, changing one instance variable in one object does not affect the other. So, serializing to nsv is in this respect the same as ns_cache.
However, it is as well possible to store the instance variables of XOTcl objects in nsvs, so value changes of instance variables effect the values in other threads immediately. I have implemented such an interface a few years ago as an experiment, but so far, i have not seen valuable usage of this. In general, one needs locking and sometime rollbacks, clustering over multiple instances is expensive. In my experience the basic approach via ns_cache is much simpler and is quite fast.
Concerning the "single thread" idea: Yes, having one (or a few) thread(s) dedicated for "object pools", which provide for certain classes an interface to the db is certainly an option, especially together with thread::send and the libthread's event loop. A connection thread can query the object pool and get e.g. the serialized object back. This approach could work similar to ttrace, but provide as well a write interface. Note that one can have multiple such thread for e.g. different classes. Note however, that this does not address the additional need for locking and transactions. Direct database manipulations (inserts, writes, deletes) bypassing the object interface are certainly as well a problem (especially for OpenACS, where this is often the common practice).
... ns_set ...I am not sure, how ns_set could help here.
However, I don't see any direct mention of this sort of stuff in the XOTcl docs nor its slots tutorial. Is there better info or examples somewhere on using XOTcl slots in this way?The XOTcl docs do not address aolserver specific interfaces. Slots provide a way to provide accessor methods for instance variables, and more general, manage their state. Some basic introduction is in
http://alice.wu-wien.ac.at:8000/s5-xotcl-core-tutorial/slides (not going more into details than the xotcl docs), examples are certainly in the source code (xotcl-core/tcl/05-db-procs.tcl).