[Logo] Terracotta Discussion Forums
  [Search] Search   [Recent Topics] Recent Topics   [Members]  Member Listing   [Groups] Back to home page 
[Register] Register / 
[Login] Login 
[Expert]
Terracotta Creates the Second Singleton  XML
Forum Index -> Terracotta Platform
Author Message
chen

neo

Joined: 01/25/2008 09:09:42
Messages: 3
Offline

If I were to start the Terracotta server with the Code:
server-data
removed (I am running in active/passive/permanent-store mode), everything works as expected. My singleton object gets created by the very first Code:
getInstance()
call, and the private constructor calls the Code:
initTransient()
method to initialize the transient fields. Because the singleton object is a required object, it is not initialized lazily but statically.

Now I bring my server down with its DSO preserved on Terracotta server. I then bring my server back up, and I’ve noticed Code:
initTransient()
was called twice. The first call was from the normal private construction, which should not happen. The second call was from the Terracotta Code:
on-load
directive, while Terracotta injects my DSO from the previous session. I also saw that they were two different objects, and the Terracotta constructed object was the one that was used for the singleton reference.

My question is, why is Terracotta allowing my program to create the singleton object and then trying to recreate the object again? Normally, it might not be too bad to create a new object and throw it away. However, my Code:
initTransient()
has the side effect of creating a daemon thread. Two daemon threads is one too many in my application. The program works fine without DSO.


Ray
tgautier

seraphim

Joined: 06/05/2006 12:19:26
Messages: 1781
Offline

Ray,

If I am correct, you are observing the behavior of root initialization. Suppose I have singleton class Foo:

Code:
 public class Foo
 {
    private static Foo singleton = new Foo();
 
    private Foo()
    {
     ...
    }
 
    public static Foo getInstance() { return singleton; }
 }
 


In regular Java, in every new JVM (actually, classloader), the first access of the Foo class will initialize the singleton variable, causing the new operation to be called which creates a new instance of Foo and calls the constructor and assigns that instance to the singleton variable in Foo.

With Terracotta, this process is slightly modified. Everything described above happens as before, including the new call which calls the constructor. However, if the singleton variable has been configured as a Terracotta root, an additional step happens. Terracotta checks to see if there is already a cluster wide instance of Foo for the singleton variable. If there is, Terracotta discards the instance of Foo that was created in the new call, and instead assigns the singleton variable the cluster wide instance. If the cluster wide instance didn't exist yet in the local heap, Terracotta will fault that instance in, and you then see the on-load method fire - on-load always fires when a new instance is faulted in from the Terracotta server.

Alex Miller blogged about this behavior with some simple code examples: http://tech.puredanger.com/2007/08/08/hello-terracotta/
[WWW]
chen

neo

Joined: 01/25/2008 09:09:42
Messages: 3
Offline

tgautier wrote:
Terracotta checks to see if there is already a cluster wide instance of Foo for the singleton variable. If there is, Terracotta discards the instance of Foo that was created in the new call, and instead assigns the singleton variable the cluster wide instance. If the cluster wide instance didn't exist yet in the local heap, Terracotta will fault that instance in, and you then see the on-load method fire - on-load always fires when a new instance is faulted in from the Terracotta server.
 


That is a perfect assessment, Taylor. I guess my follow up question is, as the best practice, where should I create the session sweeping thread, assume the root object singleton contains the session pool?


Ray
tgautier

seraphim

Joined: 06/05/2006 12:19:26
Messages: 1781
Offline

chen wrote:

That is a perfect assessment, Taylor. I guess my follow up question is, as the best practice, where should I create the session sweeping thread, assume the root object singleton contains the session pool?
 


Ray, I don't follow this question - could you provide more details?
[WWW]
chen

neo

Joined: 01/25/2008 09:09:42
Messages: 3
Offline

tgautier wrote:

chen wrote:

That is a perfect assessment, Taylor. I guess my follow up question is, as the best practice, where should I create the session sweeping thread, assume the root object singleton contains the session pool?
 


Ray, I don't follow this question - could you provide more details? 


The sole purpose of the daemon thread is to sweep the expired session objects, which are contained within a collection in the DSO. Currently, the sweeper is implemented as the run() method within the singleton, and it accesses some private data of the singleton such as the sweep frequency. Although it works fine without DSO, should I keep doing it this way in the Terracotta world? I have patched the sweeper thread to deal with the two singletons problem, so it now knows how to die if it is not sweeping the singleton. Having said that, this does not seem right, and I was wonder that is the best way to implement sessions and the corresponding sweeper in general. Thanks a lot for the attention, BTW.

Ray
tgautier

seraphim

Joined: 06/05/2006 12:19:26
Messages: 1781
Offline

Well, a sweeper thread across the entire data set could be a bad idea, if your data is load-balanced in such a way as to take advantage of Terracotta's implicit ability to leverage locality of reference.

I don't know what you have in your Sessions, but let me assume it is a User. Let me further assume that your application will be load balanced such that Users 1-10 are in Node 1, and 11-20 are in Node 2.

If there is a singleton sweeper thread, based on how I think you have written your response, I think you actually have "singletons" only in a single node, but actually, for each node you will have one "singleton" so each Node would have a singleton sweeper.

The consequence of doing so is that the sweeper thread on Node 1 would sweep the entire data set, and thus pull in Users 1-10 and 11-20 (and similarly for Node 2). This breaks locality of reference and could impact performance.

I am not the expert here, but I am fairly certain for example that our Sessions product is careful not to sweep the entire data set, only the data local to the node, and so is our cache evictor for EHCache.

If these concerns don't apply to you, you might consider not implementing the sweeper thread as a singleton, but as single resource pattern that I wrote about here:

http://www.terracotta.org/confluence/display/howto/Recipe?recipe=singleresource

In this case, the single resource is a thread. Using this pattern, if a node dies, another node acquires the lock and starts a thread, so there is always someone in the cluster that is responsible for the duties (in this case the sweeping thread).
[WWW]
 
Forum Index -> Terracotta Platform
Go to:   
Powered by JForum 2.1.7 © JForum Team