Forum OpenACS Development: Usage of XoTCL objects vs. database queries
The reason for this is that we need to run queries against the multi values on a regular basis like "show me all persons that are have the following car", where car is a multivalue (as persons can have more than one car, albeit with todays gazoline prices ....).
If we instantiate all persons from the database upon server start, how quick is XoTCL in searching for objects where a slot has a certain value, even if multivalued. Additionally the question is, if I can quickly search for objects whose slot is a specific other object (assume car was not a multiple choice value, but multivalued reference to the car class).
It works nicely just with the relational model, I was just wondering how I could do this in XoTCL without hitting the database.
There are as always various questions involved on caching and persistance layers, which are independent of XOTcl:
- do all objects fit into memory (or fit into the memory of every thread)?
- how is the cache coherency problem solved? If the objects do not change, everything is simple. If there are multiple caches (e.g. multiple connection threads, or one level higer: a cluster configuration), how is the invalidation protocol defined, in case of aolsever: how is the notification between threads implemented. the easier approach is to use nsvs (not very fast) or a thread as object pool interfacing the database. if every access to the objects data goes over a single interface, this is doable in various ways, if the object's data is changed via direct database operations, it becomes an issue to inform the affected objects.
The speed of access to the objects in memory depends certainly on your search operations. The access over the object name is very fast, sequential search is certainly slower (but often fast enough). Finally, nothing prohibits the developer to setup and maintain an index via hash a hash table (e.g. associative array or maybe a dict in tcl 8.5).
The second part of the question is (apart from speed) how to access an object from memory by looking at one of it's attribute values. Assume I have five persons as instantiated objects, how do I find the object where the first_name is "Gustaf".
But no need to dwelve in this further, I am aware now at least of some of the difficulties and therefore take the easy rode by sticking with the database 😊. Thanks again for taking the time to answer.
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).