Sneak Peak: Transfer’s new Plug-able Cache

If you've kept and eye on the transfer-dev mailing list, or possibly on Brian Ghidinelli's blog
you may well have already seen this, but its an interesting development
with the next version of Transfer, so I figured it could use some
discussion.

If you have a look in the Transfer SVN repository, you will see there is a new branch:
http://svn.riaforge.org/transfer/transfer/branches/pluggable_cache/

So the aim of Transfer's plug-able cache is to replace the cache that
Transfer uses with a extensible plug-in architecture.  By default,
Transfer will ship with a EHCache
implementation (which has some deployment limitations of CF8+ only, and
won't work on some shared hosts, depending on settings), and also a
ColdBox Cache implementation (once ColdBox Cache is released), for
wider compatibility.  We are also looking at a CacheBox implementation
as well.

That being said, the sky is the limit – because the cache is now
plug-able and extensible, you can write your own cache providers for
Transfer, which can hook into almost anything you desire.

The reason behind this change is twofold. (1) The cache implementation
as it currently stood was not very flexible, and it meant that there
could only be limited extension to what was possible with that cache
and (2) there were certain implementation details within the cache that
could have been written a lot better (including a very random, rare,
and really hard to reproduce memory leak that only seems to show up
sometimes).  So all in all, it simply made a lot of sense to move to an
already proven cache implementation, and take the burden off Transfer's
shoulders, while opening up caching to the developer community at the
same time.

Unfortunately, this means that if you had cache settings set up before,
you will now need to rewrite them with the configuration of choice of
the cache provider that is selected (or provided by default), which is
irritating, however the power provided by this new functionality is
worth it.

If you didn't have cache setting set up by default, then Transfer will
use EHCache as the default cache provider, with some basic settings
configured for you, and no changes will be necessary.

For example, now, a cache configuration will look something like this:


<objectCache>
    <defaultcache provider="transfer.com.cache.provider.EHCacheProvider">
       <setting name="config" value="/test/resources/ehcache.xml"/>
    </defaultcache>
    <cache class="none.Basic" provider="transfer.com.cache.provider.NoCacheProvider"/>
    <cache class="none.Child" provider="transfer.com.cache.provider.NoCacheProvider"/>
</objectCache>


This sets up the default cache provider, as being the EHCache Provider,
and passes it a relative path to the ehcache.xml file that will
configure the EHCache.

You can also see that there are 2 class definitions for none.Basic and
none.Child, that use the NoCacheProvider, which, as you have probably
guessed, does no caching at all.

From there, we can configure our ehCache.xml file, which is quite straight forward.


<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

    <defaultCache
        maxElementsInMemory="1000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="600"
        overflowToDisk="false"
        />
    
    <cache name="AutoGenerate"
            eternal="false"
            maxElementsInMemory="10" overflowToDisk="false">
    </cache>
    
</ehcache>

Here you can see that I've set up a defaultCache for all of the objects
being used by Transfer, such that it can have 1000 elements in memory,
objects can be idle in the cache for 120 seconds, but will be discarded
after 600 seconds.

I have also setup a cache specific to my class 'AutoGenerate', which
only allows 10 items to exist in memory at any given point in time.

There are many other options available for EHCache configuration, all which are covered in the documentation.

If you are at all interested in writing your own Cache Providers, you will need to extend the AbstractBaseProvider.cfc and implement all the virtual / abstract methods on there.  It is actually pretty straight forward API.

There is something new that is required when bootstrapping Transfer now, which is the 'shutdown()' method.

A lot of cache implementation have 'shutdown()' methods, as they may
have to close connections to files, shut down threads, or let go of
certain resources before they can be garbage collected properly.

Therefore, for example, if you have Transfer in your application scope,
it is important to shut it down when the application ends:


<cffunction name="onApplicationEnd" returnType="void">

   <cfargument name="applicationScope" required=true/>

<cfscript>

    arguments.applicationScope.transferFactory.shutdown();

</cfscript>

</cffunction>

This will call shutdown() on all the cache providers Transfer is
using.  In the case of EHCache, this is very important, as without it a
native thread will keep running, stopping EHCache from being garbage
collected.

If you need more control over your cache's you can access the native cache as it is exposed by the Provider, through the Cache Monitor (whose API has changes slightly from before) methods 'getDefaultCache()' and 'getCache(className)' methods.Please have a play, and let me know how it goes on the transfer-dev
list.  I'm waiting on the other ColdFusion caches to become available
so everyone has a cache they can work with, before releasing this in a
1.2 release.

Leave a Comment