30 November 2009 11:04 PM
0 Comments
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.





