m i k e b r e v o o r t

life technology cycling etc

m i k e  b r e v o o r t header image 2

Part 2: Terracotta: 1, Grails Searchable Plugin+Me: 1

January 29th, 2008 · 5 Comments

Round Two of my quest to cluster the Grails Searchable Plugin index with Terracotta! In my first post I outlined my intent to use Terracotta to cluster the Grails Searchable Plugin (Lucene + Compass) using the Lucene RAMDirectory approach. Incidentally, my first attempt failed miserably.

As a quick confidence booster before setting out again, I successfully clustered the Grails Searchable Plugin using a JDBCDirectory store for the index. Since my last attempt I received some guidance from the guys at Terracotta and learned that Shay Banon is working with Terrocotta to develop a Compass module for Terracotta. Good stuff… check out the details of that here.

The first hurdle I needed to overcome was the classloader error:

Classloader name not set, instances defined from this
loader not supported in Terracotta
(loader: org.codehaus.groovy.grails.cli.support.GrailsRootLoader)

Before an object can be shared by Terracotta, the ClassLoader that loaded the object’s class has to be known to Terracotta. For core java and supported frameworks/container Terracotta takes care of registering relevant classloaders. For the GrailsRootLoader I can do this one of two ways:

  1. hack the grails source where the class loader is instantiated, registering it with Terracotta
  2. this can be converted into a config module that will inject the proper byte code at runtime so as to avoid any code tweaking.

The guys at Terracotta offered to help with #2 if I could get #1 working.

So I checked out the Grail trunk from SVN, and added these lines after the GrailsRootLoader is created:

 // create loader and execute main class
GrailsRootLoader loader = new GrailsRootLoader(lc);
((com.tc.object.loaders.NamedClassLoader) loader).__tc_setClassLoaderName("Grail Classloader");
com.tc.object.bytecode.hook.impl.ClassProcessorHelper.registerGlobalLoader((com.tc.object.loaders.NamedClassLoader) loader);

I built the Grails jars and replaced them in my grails-1.0-final-SNAPSHOT/dist directory. That resolved my classloader error! Next I went through about 100 iterations of root and lock configuration for my tc-config.xml as I dug and spun my way around the Compass source. I finally ended up with this for my tc-config.xml (keep in mind this can surely be optimized and is pretty brute force):

<?xml version="1.0" encoding="UTF-8" ?>

<tc:tc-config xmlns:tc="http://www.terracotta.org/config">
  <system>
    <configuration-model>development</configuration-model>
  </system>

  <servers>
    <server name="localhost" />
  </servers>

  <clients>
    <logs>%d/client-logs-%h</logs>
    <dso>

       <debugging>
        <runtime-logging>
          <lock-debug>true</lock-debug>
        </runtime-logging>
        <runtime-output-options>
          <full-stack>true</full-stack>
        </runtime-output-options>
      </debugging>

    </dso>
    <modules>
      <module name="clustered-lucene-2.0.0" version="2.5.0"/>
    </modules>
  </clients>

  <application>
    <dso>
      <instrumented-classes>
        <include>
          <class-expression>org.compass.core.lucene.engine..*</class-expression>
        </include>
        <include>
          <class-expression>org.apache.lucene..*</class-expression>
        </include>
      </instrumented-classes>
      <roots>
        <root>
          <field-name>org.compass.core.lucene.engine.store.RAMLuceneSearchEngineStore.ramIndexes</field-name>
        </root>
      </roots>
      <locks>
	<named-lock>
          <method-expression>* org.compass.core.lucene.engine.manager.DefaultLuceneSearchEngineIndexManager.*(..)</method-expression>
          <lock-level>write</lock-level>
          <lock-name>theLockName</lock-name>
        </named-lock>
        </locks>
     </dso>
  </application>
</tc:tc-config>

It worked! I was able to test with the Terracotta server running, and two Grails apps running in separate JVMs that all of the Domain class data that the first JVM indexed, could be searched by the second JVM and they both returned identical results. I also verified the existence of the objects under the root in the Terracotta Admin GUI. And finally, I shut both Grails app JVMs down and brought them back up and my index was still available.

What’s next? Work to get a config module for Terracotta and optimize my root and locking configuration. I’m very interested in what will come of the promised Compass/Terracotta integration. Also Clustering Grails is a much taller mountain. I was told that past attempts to cluster Groovy with Terracotta had not been too successful. For now I’m happy just to have climbed my little hill…

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Technorati
  • Furl
  • DZone

Tags: Grails · Technology · code

5 responses so far ↓

  • 1 Taylor Gautier // Jan 29, 2008 at 10:36 pm

    Hey Mike. That’s awesome to see!!

    More likely than not you can replace the named lock with “auto-synchronized” locks to get a little bit better lock granularity.

    As far as Groovy goes, as a proof of concept, actually, I did cluster Groovy, but that wasn’t so much clustering Groovy as it was using Groovy to instantiate native Java objects that as you already know Terracotta supports natively.

  • 2 Graeme Rocher // Jan 30, 2008 at 3:48 am

    Hey Mike, nice work. But couldn’t you do it without hacking Grails? At what point does the class loader have to be registered with Terracotta?

    If it can happen later maybe you could do it a plugin with

    def classLoader = ApplicationHolder.application.classLoader

  • 3 Orion Letizi // Jan 30, 2008 at 7:49 am

    Mike, this is great news. I’m glad you met with some success. This is very exciting stuff.

    –Orion

  • 4 Mike // Jan 30, 2008 at 8:54 am

    Graeme,

    The classloader needs to be registered with Terracotta before any of the the classes you tell Terracotta about get loaded so I suppose it depends. Is there anyway to specify a precedence in how the plugins get loaded?

    I think the best approach though is the Terracotta config module which would make it really easy to include/exclude Terracotta in the equation.

    -Mike

  • 5 Groovy on Grails : Terracotta Meets Grails with the Terracotta for Grails Plugin (Graeme Rocher) // Sep 2, 2008 at 11:24 am

    [...] that adds support for the Terracotta data grid. It was always possible to do this with a bit of manual configuration, but now the plugin automates things nicely using a few new Grails command line [...]

Leave a Comment