Skip to content

Ehcache Redux

Ok, I promised I would write more about ehcache earlier this month, so here it is.
Ehcache is one of several caching options for hibernate. But is the only OS one, I believe. And it’s the default caching option for Hibernate, and it’s what I’m using for the current project. This is how I configured it:

Ehcache is configured via an xml file, at it’s minimum, you need something like this:

<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <diskStore path="./cache"/>

    <!--Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required for defaultCache:

        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires.
                            i.e. The maximum amount of time between accesses before an element expires
                            Is only used if the element is not eternal.
                            Optional attribute. A value of 0 means that an Element can idle for infinity
        timeToLiveSeconds - Sets the time to live for an element before it expires.
                            i.e. The maximum time between creation time and when an element expires.
                            Is only used if the element is not eternal.
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->
	<defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

   <!-- Cache named BucketOfGoodies
        This cache contains a maximum in memory of 1000 elements, it does not
        expire the elements

        If there are more than 1000 elements it will overflow to the
        disk cache, which in this configuration will go to wherever ./cache is
        defined on your system.
        -->
    <cache name="BucketOfGoodies"
        maxElementsInMemory="1000"
        eternal="true"
        overflowToDisk="true"
        />

</ehcache>

If you disregard the large note section, there’s not much too it. There is a reference to a directory where ehcache stores temp files, there is a default cache that is used if nothing is specified, and there is a custom cache element I’ve specified and will return to in my hibernate hbm files.

What I did first was create an entity relationship model diagram for the DAOs used by my application. That helped me easily identify the areas I needed to cache.

Ehcache allows several types of caching. I mostly used 2, caching of classes and caching of collections. You can also cache queries, which I did a couple of times but the other two were much more effective.

A basic *.hbm.xml file might look something like this:

<hibernate-mapping>
...
	<class name="com.something.ProviderInfo" table="provider_lookup" >
		<cache usage="read-only" region="BucketOfGoodies"/>
		<id name="providerId" column="provider_code">
			<generator class="assigned" />
		</id>
		<property name="someProp" column="is_flag_evaluation" type="yes_no"/>
	</class>

</hibernate-mapping>

Here the class and the collection were assigned different cache regions (defined in the xml file), they could just as well be assigned to the same region.

That really does pretty much take care of the configuration, but sometimes the cache will require tweaking. The cache will store as much information in memory as you allow within the configuration. When memory is full it reads and writes to the defined temporary dir. It takes a lot longer for the app to read from the disk than it does from memory. A good indicator of whether you’ve allocated enough memory space is the hit to miss ratio.

Within a Spring context, it’s easy to log this data to see where you’re at:

          logger.debug("Second level cache hit count: "
                  + Long.toString(sessionFactory.getStatistics().getSecondLevelCacheHitCount()));
          logger.debug("Second level cache miss count: "
                  + Long.toString(sessionFactory.getStatistics().getSecondLevelCacheMissCount()));
          logger.debug("Second level cache put count: "
                  + Long.toString(sessionFactory.getStatistics().getSecondLevelCachePutCount()));
          logger.debug("Successful Transaction count: "
                  + Long.toString(sessionFactory.getStatistics().getSuccessfulTransactionCount()));

The output from my batch process of 1000 rows produced a log output like this:

[2006-08-24 00:01:28,720] **DEBUG** Second level cache hit count: 12306
[2006-08-24 00:01:28,720] **DEBUG** Second level cache miss count: 972
[2006-08-24 00:01:28,720] **DEBUG** Second level cache put count: 4997
[2006-08-24 00:01:28,720] **DEBUG** Successful Transaction count: 1

And I figured I was in pretty good shape.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*