Transfer objects in session scope and reiniting application

0 views
Skip to first unread message

Brian G

unread,
May 6, 2008, 2:36:43 PM5/6/08
to transfer-dev
In my previous apps, I would regularly create a component and put it
into session scope and then use that while the user was logged in.
These were stand alone objects that did their own thing.

In my new app, almost all objects are Transfer objects and I'm using
the decorator to make them more capable based on discussions here and
elsewhere. In doing so, the transfer object is sometimes injected
with a reference to a service object. For example, the club object
gets a reference to ClubService so it can do things
like .findMembers().

Based on errors we're seeing when we reinit the application, it seems
like the application-scoped service (managed by coldspring) is
recreated and thus the reference in the session-scoped transfer object
goes away leading to "foo not defined in variables" type errors. While
I didn't consider this originally, it makes sense if that's the case
but I don't know much about how coldspring does its thing internally.
If true, I take it this is not a very safe approach to using the
session scope?

I have always put the objects in the session scope for performance
reasons but with Transfer in the mix, would I be better off to put an
ID in the session and instead ask Transfer for the object on every
single request so it will manage the caching instead of my session
scope? It seems like this approach may add the overhead of asking
Transfer to look in the cache on each request (not sure what that
really adds) but would allow the session objects to be gracefully
recreated after a server reinit/cache clear and for users to maintain
their state.

I'm tangentially wondering if this might reduce the memory footprint
of my app which has been wedging itself every few hours since
launching Saturday (although is running suspiciously ok this morning).

Thoughts?


Brian

James Allen

unread,
May 6, 2008, 2:44:43 PM5/6/08
to transf...@googlegroups.com
I am taking the approach you mention of just storing the ID of already
persisted transfer objects, then letting Transfer grab them from the cache
as required. You have to do this anyway if using Transfer caching otherwise
you get major cache sync issues as I found when storing the transfer object
in session *and* using transfer caching. I believe transfer utilises some
pretty clever caching so you probably wouldn't get any real performance
issues I wouldn't think.

As Transfer intelligently handles object caching and destroying as memory
changes this is probably better for your system than just throwing objects
into Session without any memory management. I was originally concerned about
putting too many rich objects into session in case it impacted on memory
usage and overall system stability.

Brian G

unread,
May 6, 2008, 2:46:05 PM5/6/08
to transfer-dev

On May 6, 11:36 am, Brian G <brian-goo...@vfive.com> wrote:
> Based on errors we're seeing when we reinit the application, it seems
> like the application-scoped service (managed by coldspring) is

I should show how I'm reiniting my application... perhaps this is the
source of my problems?

<cfset structClear(application) />
<cfset structDelete(session, "scope", false) />
<cfset application.cs = createObject("component",
"coldspring.beans.DefaultXmlBeanFactory").init() />
<cfset application.cs.loadBeansFromXmlFile("config/coldspring.xml",
true) />

This is what I call my "full restart" for when I need to clear the
service layer due to code changes. I also have the normal restart
using the reload key in the coldspring.xml, but that doesn't seem to
clear objects already in the Transfer cache.

I suppose an alternative is to use one of the transfer.discard()
methods but I have not looked into that yet.

As I write this message, I realize that this code is carry-over from
my previous version and that it may be the cause of my problems.

Hopefully this inspires some advice on the best way to handle
application reinits for a variety of circumstances.

Thanks,


Brian

Paul Marcotte

unread,
May 6, 2008, 3:20:52 PM5/6/08
to transf...@googlegroups.com
I agree with James completely on this one.  Let transfer handle the caching of you objects and use methods in your service api like getCurrentUser() which will return something like (short form) transfer.get("user",session.userid).  Placing business objects is session scope has two big drawbacks in my  mind.

1. Memory use - if you start a session for every visitor, a bot can bring down your system in a hurry
2. External edits to the object's data.  Where an administrator updates information in a user account, those changes cannot be represented in the user object until the session is "restarted".  So if transfer handles access to the object for both public facing and secure apps, you not only benefit from consistent data in your object, you benefit from the superior memory management that is a by-product of the transfer cache.

Of course, I might just be talking out my a** on the memory benefit, but that's the way I'd roll it.

Paul
--
Paul Marcotte
Fancy Bread - in the heart or in the head?
http://www.fancybread.com

Brian Kotek

unread,
May 6, 2008, 3:20:57 PM5/6/08
to transf...@googlegroups.com
I just re-run onApplicationStart() (using proper locking of course).

Brian G

unread,
May 6, 2008, 3:44:06 PM5/6/08
to transfer-dev

On May 6, 12:20 pm, "Brian Kotek" <brian...@gmail.com> wrote:
> I just re-run onApplicationStart() (using proper locking of course).
>

Do you have the application.cs creation in your onApplicationStart()?
I shortened my onRequestStart code slightly which actually looks like:

<cflock scope="application" type="exclusive" timeout="10">
<cfset structClear(application) />
<cfset structDelete(session, "scope", false) />
<cfset onApplicationStart() />
</cflock>

I am running 3 MG sub-apps with the one bean factory.


Brian

Sean Corfield

unread,
May 10, 2008, 2:59:02 AM5/10/08
to transf...@googlegroups.com
On Tue, May 6, 2008 at 11:36 AM, Brian G <brian-...@vfive.com> wrote:
> I have always put the objects in the session scope for performance
> reasons but with Transfer in the mix, would I be better off to put an
> ID in the session and instead ask Transfer for the object on every
> single request so it will manage the caching instead of my session
> scope?

Yes. It's very, very bad to put Transfer objects in session scope if
Transfer is also caching them. This has cropped up in discussion on
this list a few times.

> I'm tangentially wondering if this might reduce the memory footprint
> of my app which has been wedging itself every few hours since
> launching Saturday (although is running suspiciously ok this morning).

Update to the very latest Transfer from SVN. Mark has made a number of
improvements over the last week as Broadchoice has been load testing
and analyzing our Transfer-based app (or rather, the excellent folks
at Alagad have been doing this for us).
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood

Mark Mandel

unread,
May 10, 2008, 3:37:24 AM5/10/08
to transf...@googlegroups.com
Indeed!

Once things start to settle with the load testing at Broadchoice, I'll
do a RC 2 release of the Transfer 1.0 for people to play with.

Mark

--
E: mark....@gmail.com
W: www.compoundtheory.com

Brian Kotek

unread,
May 10, 2008, 9:55:55 PM5/10/08
to transf...@googlegroups.com
I'm trying to figure out a workaround for this, since I do have a User object that I want to keep in the session scope. The basic solution of just keeping the ID and calling Transfer.get() each time isn't a good choice for me, since I have other instance data that is built up and kept in the User object that would be lost if the object falls out of cache and Transfer.get() actually returns a new instance. To be honest, I'm still not clear at all on how a session-scoped TO could fall out of cache anyway...isn't the fact that it is in the session scope creating a continuous strong reference to that object? Is this some kind of bug in CF's session handling?

In any event, my solution so far has just been to ensure that when the User object is updated that I also update the reference in the session scope. Do you see any problem with this that I might be missing? Is the answer to just not allow User objects to be cached by Transfer?

Bob Silverberg

unread,
May 10, 2008, 10:08:25 PM5/10/08
to transf...@googlegroups.com
On Sat, May 10, 2008 at 9:55 PM, Brian Kotek <bria...@gmail.com> wrote:
> I'm trying to figure out a workaround for this, since I do have a User
> object that I want to keep in the session scope. The basic solution of just
> keeping the ID and calling Transfer.get() each time isn't a good choice for
> me, since I have other instance data that is built up and kept in the User
> object that would be lost if the object falls out of cache and
> Transfer.get() actually returns a new instance.

I have the same issue, but I addressed it by creating a CurrentUser
object of my own, which I do store in the session scope. The
CurrentUser keeps a record of the UserId for the Transfer based User
TO in its instance data and whenever I need something from the
Transfer based User TO I get it via a Transfer.get() inside
CurrentUser. There may be issues with this design decision, which
I'd be happy to hear about, but it definitely works.

Bob

Sean Corfield

unread,
May 11, 2008, 12:22:26 PM5/11/08
to transf...@googlegroups.com
On Sat, May 10, 2008 at 6:55 PM, Brian Kotek <bria...@gmail.com> wrote:
> I'm trying to figure out a workaround for this, since I do have a User
> object that I want to keep in the session scope. The basic solution of just
> keeping the ID and calling Transfer.get() each time isn't a good choice for
> me, since I have other instance data that is built up and kept in the User
> object that would be lost if the object falls out of cache and
> Transfer.get() actually returns a new instance.

Are you saying you add information to the User object but don't commit
it? That sounds like a poor design to me. Transfer objects are meant
to be persistent objects - if you modify the User object in memory, it
will affect *all* uses of that object (by other threads) since there
is only one cached object (by default). If I understand correctly what
you're doing, you're just setting yourself up for data corruption and
all sorts of hard-to-debug problems.

> To be honest, I'm still not
> clear at all on how a session-scoped TO could fall out of cache
> anyway...isn't the fact that it is in the session scope creating a
> continuous strong reference to that object? Is this some kind of bug in CF's
> session handling?

How would Transfer know where you stored the reference? If Transfer
needs to reap its cache and that User object is a candidates based on
its usage pattern, out it goes. Your session scope reference is
completely independent of what Transfer knows about.

Sean Corfield

unread,
May 11, 2008, 12:24:31 PM5/11/08
to transf...@googlegroups.com
On Sat, May 10, 2008 at 7:08 PM, Bob Silverberg
<bob.sil...@gmail.com> wrote:
> I have the same issue, but I addressed it by creating a CurrentUser
> object of my own, which I do store in the session scope. The
> CurrentUser keeps a record of the UserId for the Transfer based User
> TO in its instance data and whenever I need something from the
> Transfer based User TO I get it via a Transfer.get() inside
> CurrentUser. There may be issues with this design decision, which
> I'd be happy to hear about, but it definitely works.

That's a very reasonable approach.

My favored approach is to have a UserService that has a
getCurrentUser() method that returns
transfer.get("user.user",session.userid) but there are lots of ways to
handle this without risking data corruption...

Brian Kotek

unread,
May 11, 2008, 7:34:05 PM5/11/08
to transf...@googlegroups.com
On Sun, May 11, 2008 at 12:22 PM, Sean Corfield <seanco...@gmail.com> wrote:

Are you saying you add information to the User object but don't commit
it? That sounds like a poor design to me. Transfer objects are meant
to be persistent objects - if you modify the User object in memory, it
will affect *all* uses of that object (by other threads) since there
is only one cached object (by default). If I understand correctly what
you're doing, you're just setting yourself up for data corruption and
all sorts of hard-to-debug problems.

No you're misunderstanding what I'm saying. As an example, say I have a user that is related to an array of Permissions. I may call something like user.getPermissionList(). To avoid having to loop over all of the Roles and build the list every time this is called, I build up a list of permissions and store it as instance data. This is a simple example, but the point is that I have instance data that may be cached to allow for easier or faster access to data that the User contains, or to objects that are related to the User. There are no data corruption or debug issues with this, it's purely convenience or performance related.
 
> To be honest, I'm still not
> clear at all on how a session-scoped TO could fall out of cache
> anyway...isn't the fact that it is in the session scope creating a
> continuous strong reference to that object? Is this some kind of bug in CF's
> session handling?

How would Transfer know where you stored the reference? If Transfer
needs to reap its cache and that User object is a candidates based on
its usage pattern, out it goes. Your session scope reference is
completely independent of what Transfer knows about.

Transfer doesn't know where I've stored the reference, but the JVM clearly must know that the object has an active reference. And as I understand it, the soft reference handler should not be discarding anything that has an active reference to it, but this may be where I'm mistaken. I thought only objects that were candidates for garbage collection would be eligable for reaping. Is this not the case?
 
All that said, the caching of this instance data is automatic and happens if the method is called and the cached instance data doesn't exist, so in theory the regeneration of the cached instance data would only happen again in the event that the object falls out of cache and is recreated. So in this case it isn't really a big issue in terms of performance, as long as the object doesn't fall out of cache frequently. I'm just thinking about similar use cases, where the processing needed to build up something like this was non-trivial. Since it seems like a session-scoped object should not be a candidate for reaping by the soft reference handler, the underlying question is why it can fall out of cache in the first place. Thoughts? Is the answer simply that my understanding of how the soft reference handler reaps objects is incorrect?

Mark Mandel

unread,
May 11, 2008, 7:47:50 PM5/11/08
to transf...@googlegroups.com
> No you're misunderstanding what I'm saying. As an example, say I have a user
> that is related to an array of Permissions. I may call something like
> user.getPermissionList(). To avoid having to loop over all of the Roles and
> build the list every time this is called, I build up a list of permissions
> and store it as instance data. This is a simple example, but the point is
> that I have instance data that may be cached to allow for easier or faster
> access to data that the User contains, or to objects that are related to the
> User. There are no data corruption or debug issues with this, it's purely
> convenience or performance related.

That's a good thing to be doing in general regardless, it doesn't have
much to do with specifically storing things in session scope.

>
> Transfer doesn't know where I've stored the reference, but the JVM clearly
> must know that the object has an active reference. And as I understand it,
> the soft reference handler should not be discarding anything that has an
> active reference to it, but this may be where I'm mistaken. I thought only
> objects that were candidates for garbage collection would be eligable for
> reaping. Is this not the case?

It depends on your cache config. If you have a maxobjects or timeout,
it could definitely fall out of the cache.

That being said, I have heard about (weird) cases were objects have
fallen out of the cache, when it was just a SoftReference
configuration.

Mind you - YMMV. At the end of the day, if you're not experiencing
any issues, and everything is working as you expected, then do as you
will.

Mark

Brian G

unread,
May 13, 2008, 9:35:14 PM5/13/08
to transfer-dev

On May 11, 4:34 pm, "Brian Kotek" <brian...@gmail.com> wrote:
> Transfer doesn't know where I've stored the reference, but the JVM clearly
> must know that the object has an active reference. And as I understand it,
> the soft reference handler should not be discarding anything that has an

I don't think your object will get GC'd even if it falls out of the
Transfer cache, at least not until that session is over and the handle
is released. Aren't the two separate?

I'll try Transfer RC2 when it's ready... stability has improved
significantly since I've started pulling everything out of the
Transfer cache on every request.


Brian
Brian
Reply all
Reply to author
Forward
0 new messages