Working with sessions

Hide Navigation Pane

Working with sessions

Previous topic Next topic No directory for this topic  

Working with sessions

Previous topic Next topic Topic directory requires JavaScript JavaScript is required for the print function Mail us feedback on this topic!  

A Session object represents a user session running a Persistate Package.  This includes the Persistate package running the Generator and Configurator applications.  Sessions belong to a Principal object, which represents the users of the Persistate package.  A session can run in two modes.

A Stand-Alone mode session is started by running the executable created from the StartUp module of the package.  In this mode, the user interface and the controller run in the same process in the same computer.
A Viewer-Server mode session is started by running the Persistate Viewer application on a client workstation, connecting to a Persistate Server, and running a package.  One Viewer process can run an arbitrary number of sessions for the same or different packages.

Developing sessions for View-Server mode

This discussion assumes that you are up to speed with the general way in which Persistate applications are coded, as described in the Accessing persistent objects and Manipulating persistent objects sections.  In particular, you should understand the way that the session cache works as explained in The session cache.

There is one important consideration you must take into account when you want your application to run in Viewer-Server mode, which is as follows:

The sessions in a Persistate Server which are running the same package all run in the same application domain, and share the same session cache.

This was a deliberate decision made during the development of the Server product.  The reasoning behind it is that doing it this way results in much more frugal use or resources per session.  The obvious downside is that you will have any number of sessions and threads within those sessions all accessing the same cached object tree in memory, and you must provide appropriate synchronisation when accessing these objects.

Future Enhancement

The current version of Persistate is an early beta, and this decision is by no means written in stone.  There are other ways of running multiple sessions, for example each in their own AppDomain, or all in the same AppDomain, but with separate session caches.  Perhaps providing a choice may be the way to go.  All feedback welcomed on this point!

Persistate does lend a hand with synchronisation.  If you examine generated code, you will see that all de-references of scalar objects are locked by the locker object which is a protected member of all Persistent objects.  Fetches of collections of several objects from persistent storage are also similarly protected, as are the creation of the collection objects for many and selected collections.  The fetching methods for these latter collections are not covered, however, so you must do this yourself if need be.  The main collection class IndexedList<T> is also thread safe, except for the CallTree and GetEnumerator methods.

The shared session cache is not necessarily as problematic as it might at first appear.  Remember that the session cache contains only a subset of objects - those in the Stable and Configurative class categories (see Class Category Definition).  These objects tend not to change much.  In general, the objects that a package will work on will be either objects in a section of the tree dedicated to the session user, or be Transitory, and therefore not held in the cache.  Note that this is an issue in the Server only.  In the Viewer, each session runs in it own AppDomain.

There is one particular problem that the shared cache throws up.  For collections of several objects, all the objects are in the collection in memory, so all sessions see the same collection.  However, for collections of many or selected objects, this is not the case.  Now, very often these are collections of transitory objects, and not held in the cache, but this does not help in the case where their parent object is not transitory and is held in the cache.  If the situation was left like this, all sessions would see the same collection, and whatever subset had been retrieved most recently by whatever session.  Clearly not good!

This problem is resolved by the use of the SessionSpecific<T> class.  The backing fields holding collections of many or selected  objects use this class to hold the collections, so for example the backing field for a collection of Author objects would be held in a SessionSpecific<IndexedList<Author>> object.  The property that you use to access the collection is the same class as it would be for a collection of several objects, in the above case, IndexedList<Author>.  Examine the generated code for a many collection in The Library class, to see how this works.

Using multiple threads

The method described above of providing session specific backing fields for collections relies on being able to determine what the current session is in any given thread.  Persistate uses a ThreadStatic object to store the active session, and sets this appropriately whenever your application code is given control.  However, you must ensure that any threads that you start yourself has the active session set appropriately.  Persistate provides the following property and methods in Session to assist in this

ActiveSession { get; }.  This property gets you the active session for the current thread.
CallConcurrent<T, U>(Work<T, U> work, T parameter1, U parameter2).  This calls a method in a Work<T, U> delegate on a thread pool thread.  It ensures that the ActiveSession property will return the same Session as the thread calling the CallConcurrent method.  There are also overloads of this method using single and zero parameter delegates.
CallPeriodic<T, U>(Work<T, U> work, T parameter1, U parameter2, int initialDelay, int subsequentDelay).  This method starts a Timer to call the method in a Work<T, U> delegate on a thread pool thread at regular intervals.  It ensures that the ActiveSession property will return the same Session as the thread calling the CallPeriodic method.  There are also overloads of this method using single and zero parameter delegates.

The Operation class also offers a method to execute an Operation concurrently.  See the API documentation for Operation.ExecuteConcurrent.