<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>puredanger.com Blog &#187; bytecode</title>
	<atom:link href="http://puredanger.com/kablooie/index.php/category/bytecode/feed/" rel="self" type="application/rss+xml" />
	<link>http://puredanger.com/kablooie</link>
	<description>Scott Bale's technical blog</description>
	<lastBuildDate>Tue, 23 Jun 2009 15:19:57 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Revenge of Hello Terracotta</title>
		<link>http://puredanger.com/kablooie/2008/03/30/revenge-of-hello-terracotta/</link>
		<comments>http://puredanger.com/kablooie/2008/03/30/revenge-of-hello-terracotta/#comments</comments>
		<pubDate>Mon, 31 Mar 2008 04:38:27 +0000</pubDate>
		<dc:creator>Scott</dc:creator>
				<category><![CDATA[Concurrency]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Terracotta]]></category>
		<category><![CDATA[Terracotta developer]]></category>
		<category><![CDATA[bytecode]]></category>

		<guid isPermaLink="false">http://puredanger.com/kablooie/2008/03/30/revenge-of-hello-terracotta/</guid>
		<description><![CDATA[When my manager Alex first started at Terracotta, he blogged a simple Hello Terracotta example to demonstrate POJO clustering in action.  When I first started last month, he walked me through this same example and went into quite a bit more depth, decompiling some code and showing me a glimpse of how client POJO&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>When my manager <a href="http://tech.puredanger.com/">Alex</a> first started at <a href="http://www.terracotta.org">Terracotta</a>, he blogged a simple <a href="http://tech.puredanger.com/2007/08/08/hello-terracotta/">Hello Terracotta</a> example to demonstrate POJO clustering in action.  When I first started last month, he walked me through this same example and went into quite a bit more depth, decompiling some code and showing me a glimpse of how client POJO&#8217;s are instrumented by Terracotta and thus plug into our clustering framework.  Here&#8217;s what we did.</p>
<p>First, if you haven&#8217;t yet, please go and run through Alex&#8217;s <a href="http://tech.puredanger.com/2007/08/08/hello-terracotta/">Hello Terracotta</a> example.  I&#8217;ll be starting right where he left off.</p>
<p>Now, as Alex pointed out to me, I need to make a slight correction to the example POJO code he is using.  Here is the code:</p>
<textarea name="code" class="java:nocontrols:nogutter" cols="60" rows="10">
package test;
import java.util.HashSet;
import java.util.Set;
   
public class HelloTerracotta {  
    private final Set root;  
   
    public HelloTerracotta() {  
//        if (root != null) {         // Item 1  
//            System.err.println("map is already non-null, size " + root.size());  
//        }  
   
        Set newSet = new HashSet();  
        root = newSet;              // Item 2  
   
        if (root != newSet) {       // Item 3  
            System.err.println("root assignment was ignored");  
        }  
    }  
   
    private void go() throws InterruptedException {  
        for (int i = 0; i < 30; i++) {  
            synchronized (root) {       // Item 4  
                root.add(root.size());  
                System.err.println("root is now size " + root.size());  
                Thread.sleep(500);  
            }  
        }  
    }  
   
    public static void main(String[] args) throws Exception {  
        new HelloTerracotta().go();  
    }  
}  
</textarea>
<p>The correction is the commented out bit.  The compiler complains about that code, since the <code>root</code> field is <code>final</code>.  And anyway, it is not necessary &#8211; if an L1 node starts up and Terracotta sees that the clustered root already exists, Terracotta will ignore the assignment in the source code (Item 2 above) and instead set that field to the pre-existing root.  That is why, if you run this sample program twice in a row without bouncing the Terracotta server, you will see that the counter continues to increment from where it left off the first time.  Terracotta clustered objects persist.</p>
<p>To continue, today when I run this example I am adding the special super-secret <code>-Dtc.classloader.writeToDisk=true</code> flag to the vm flags when I start up the dso process.  My full command looks like this:</p>
<p><code>dso-java.sh -Dtc.config=config/tc-config.xml -Dtc.classloader.writeToDisk=true -classpath bin test.HelloTerracotta</code></p>
<p>This additional flag causes Terracotta to dump the modified classes under <code>~/adapted/</code>.  Under that folder you should find a <code>test/</code> directory containing the instrumented <code>HelloTerracotta.class</code> file.</p>
<p>At this point you can examine the raw bytecode to see what we&#8217;ve added &#8211; Terracotta uses <a href="http://asm.objectweb.org/eclipse/index.html">ASM</a> to instrument bytecode on the fly in order to cluster arbitrary client code.</p>
<p>Or, you can decompile the file like I did using <a href="http://www.kpdus.com/jad.html">Jad</a>.  This likely won&#8217;t be able to decompile everything all the way, but it&#8217;s close enough that you can see what&#8217;s going on.</p>
<p>When I decompile <code>HelloTerracotta</code> using Jad, after cleaning up the <code>go()</code> method by hand, this is what I see:</p>
<textarea name="code" class="java:nocontrols:nogutter" cols="60" rows="10">
package test;

import com.tc.object.TCObject;
import com.tc.object.bytecode.*;
import java.io.PrintStream;
import java.util.*;

public class HelloTerracotta
    implements Manageable, TransparentAccess
{

    private Set __tc_getroot()
    {
        if(root == null)
        {
            ManagerUtil.beginLock("test.HelloTerracotta.root", 2);
            try
            {
                Object obj = ManagerUtil.lookupRoot("test.HelloTerracotta.root");
                if(obj != null)
                {
                    if(!(obj instanceof Set))
                        throw new ClassCastException("The field '" + "root" + "' with root name '" + "test.HelloTerracotta.root" + "' cannot be assigned to a variable of type " + "java/util/Set" + ". This root has a type " + obj.getClass().getName() + ". " + "Perhaps you have the same root name assigned more than once to variables of different types.");
                    root = (Set)obj;
                }
            }
            finally
            {
                ManagerUtil.commitLock("test.HelloTerracotta.root");
            }
        }
        return root;
    }

    private void __tc_setroot(Set set)
    {
        if(set != null)
        {
            ManagerUtil.beginLock("test.HelloTerracotta.root", 2);
            try
            {
                Object obj = ManagerUtil.lookupOrCreateRoot("test.HelloTerracotta.root", set);
                if(!(obj instanceof Set))
                    throw new ClassCastException("The field '" + "root" + "' with root name '" + "test.HelloTerracotta.root" + "' cannot be assigned to a variable of type " + "java/util/Set" + ". This root has a type " + obj.getClass().getName() + ". " + "Perhaps you have the same root name assigned more than once to variables of different types.");
                root = (Set)obj;
            }
            finally
            {
                ManagerUtil.commitLock("test.HelloTerracotta.root");
            }
        }
    }

    public HelloTerracotta()
    {
        Set newSet = new HashSet();
        __tc_setroot(newSet);
        if(__tc_getroot() != newSet)
            System.err.println("root assignment was ignored");
    }

    private void go()
        throws InterruptedException
    {
    
	for (int i = 0; i < 30; i++) {  
		Set set = __tc_getroot();
		try{
			ManagerUtil.monitorEnterWithContextInfo(set, 2, "<autolock>\n  <method-expression>* test.HelloTerracotta.*(..)</method-expression>\n  <lock-level>write</lock-level>\n</autolock>");
			synchronized (set){
			    set.add(set.size());  
			    System.err.println("root is now size " + set.size());  
			
			    Thread.sleep(500);  
			}
		} finally {
		    ManagerUtil.monitorExit(set);
		}
	}
    }

    public static void main(String args[])
        throws Exception
    {
        (new HelloTerracotta()).go();
    }

    public void __tc_getallfields(Map map)
    {
        map.put("test.HelloTerracotta.root", root);
    }

    public void __tc_setfield(String s, Object obj)
    {
        if(s.equals("test.HelloTerracotta.root"))
            root = (Set)obj;
    }

    public Object __tc_getmanagedfield(String s)
    {
        if(s.equals("test.HelloTerracotta.root"))
            return __tc_getroot();
        else
            return null;
    }

    public void __tc_setmanagedfield(String s, Object obj)
    {
        if(s.equals("test.HelloTerracotta.root"))
            __tc_setroot((Set)obj);
    }

    public TCObject __tc_managed()
    {
        return $__tc_MANAGED;
    }

    public void __tc_managed(TCObject tcobject)
    {
        $__tc_MANAGED = tcobject;
    }

    public boolean __tc_isManaged()
    {
        return $__tc_MANAGED != null;
    }

    private Set root;
    static final long serialVersionUID = 0xdea86fadL;
    private volatile transient TCObject $__tc_MANAGED;
}

</textarea>
<p>First thing to notice, the instrumented version of the class now implements two interfaces, <code>Manageable</code> and <code>TransparentAccess</code>.  These are both in the <code>dso-l1-api</code> project if you download the Terracotta source code.  The api is our internal api for dealing with all clustered objects in the L1 nodes.</p>
<p>Next, notice that all direct reads of the <code>root</code> field have been replaced with calls to a new dynamically-generated <code>Set __tc_getroot()</code> method, and the one spot in the constructor where we were setting the <code>root</code> field directly is now replaced by a call to a new <code>__tc_setroot(Set)</code> method.  And you can see that those getter/setter methods are doing the work of ensuring any pre-existing root is set on this object, or else creating the new clustered root.</p>
<p>You can see that there are a lot of calls into <code>ManagerUtil</code> &#8211; this is a dynamically clustered object&#8217;s hook into the Terracotta runtime.  <code>ManagerUtil</code> can be thought of as a facade of static methods, encapsulating a more interesting system which I won&#8217;t go into here.</p>
<p>The go() method didn&#8217;t decompile entirely correctly, so I&#8217;ve had to tweak it by hand into what you see here.  What I find most interesting is that now, in addition to the synchronized block, there are calls (in a try-finally block) to <code>ManagerUtil</code> to acquire/release a <i>clustered</i> lock.  Remember &#8211; since the root field is actually a clustered object, modifying it requires obtaining a cluster-wide exclusive write lock.  It&#8217;s also interesting to note that a chunk of that tc-config.xml file, specifically the lock information including the method expression, is being passed to the <code>monitorEnterWithContextInfo</code> method. </p>
<p>In conclusion, this example illustrates the pattern for any POJO being clustered by Terracotta.  Terracotta dynamically instruments a class to adhere to the dso api, an api for handling all of the distributed objects and locks within Terracotta.  Of course that barely scratches the surface of all that Terracotta does, but at least you can see that conceptually what Terracotta is doing behind the scenes to cluster your code is really not all that complicated.</p>
<p>For further reading, the Terracotta website offers some very straightforward articles about how Terracotta <a href="http://www.terracotta.org/confluence/display/orgsite/How+Terracotta+Works">works</a>, and how Terracotta <a href="http://www.terracotta.org/confluence/display/orgsite/How+Terracotta+Scales">scales</a>.  Additionally, there are quite a few other Terracotta employees who blog, and their blogs are listed <a href="http://tech.puredanger.com/2007/08/15/blogging-for-jobs/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://puredanger.com/kablooie/2008/03/30/revenge-of-hello-terracotta/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.310 seconds -->

