Recently I posted a bounty of $800 and Transfer community members matched me with another $1000 to pay ORM creator Mark Mandel to update the caching system in Transfer. Mark has a branch in subversion with the code and I’ll give you here a quick run through on how to configure and use it. Remember, this is beta code, which successfully passes unit tests, but should be tested in your own environment too.
Get the code
First checkout or export the code from the Subversion branch and replace your current version of Transfer. I’m not going to discuss how to get started with Transfer but rather how to migrate from a working, caching Transfer setup to one that uses EHCache behind the scenes. Pull the code from:
In transfer.xml, you’re going to replace your existing <objectCache> stanza with something like this:
<objectCache> <defaultcache provider="transfer.com.cache.provider.EHCacheProvider"> <setting name="config" value="transfer/ehcache.xml" /> </defaultcache> </objectCache>
The config value is a relative path that gets passed through expandPath() from wherever you instantiate Transfer. In my case, that’s in the root directory so this refers to a file at /transfer/ehcache.xml.
Now create a new file ehcache.xml that will define the caching settings. Whereas this used to live in transfer.xml, it now lives in a separate file (specific to the particular caching implementation, of which EHCache is the first and default):
<?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="900" overflowToDisk="false" /> </ehcache>
That’s a good starting point. Up to 1,000 objects will go into one bucket with a 2-minute idle timeout and a 15-minute max time to live. Converting from transfer.xml, timeToIdleSeconds replaces accessedminutestimeout and timeToLiveSeconds replaces maxminutespersisted. If you specify eternal=true, then the timeouts are ignored and the only thing that will cause an object to be discarded from the cache is running into the 1,000 object limit.
Delete all of your *.transfer files from your generated folder and restart your application. You should see it come back up, just like it always has. The difference? No more leaky SoftReferences!
Ok, you’re memory-leak free, but so what! You’re demanding! You want whiz-bang! Here’s two things you can explore:
Unique per-class cache settings
In transfer.xml, you could define class-specific settings by simply saying:
<cache class="object.class" maxminutespersisted="1440" />
Now, you’ll instead define them in ehcache.xml:
<cache name="event.event" maxElementsInMemory="2000" eternal="true" overflowToDisk="false" /> <cache name="event.venue" maxElementsInMemory="500" eternal="true" overflowToDisk="false" />
So long as the name is a case-sensitive match, then the EHCacheProvider will use those specific settings for that specific class.
Use different providers for different caches
In addition to the default cache we created above, we could also stipulate another (as yet unwritten) caching provider or disable caching altogether for a certain class like this example Mark provided in the google group:
<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>
You could imagine another provider, maybe one that uses the new virtual file system in ColdFusion 9, to be used for a specific class. Now that caching is pluggable, the limitations are in your hands! I expect to see a Coldbox cache provider straight away.
There’s one big deal to watch out for with this new approach. The whole idea of SoftReferences is that they will get garbage collected if they need to, like when you’re running out of memory. This default cache has no such provision. So, if you stipulate the cache can hold 10,000 objects but you only have RAM for 5,000 objects, your server is going to grind to a halt as it runs out of memory and either starts going to disk or throws java.lang.OutOfMemory errors. Either way, not good!
Start small and conservative, see how it performs, and grow from there. Mark is putting the finishing touches on the statistics collector so you’ll be able to generate the same graphs for the cache on usage, hit rate and so forth. Plus, this is beta code! Until then, get this into your development environment and test!
Even if things are working fine in your current Transfer environment, this is a worthwhile upgrade. It streamlines a LOT of internal code and leverages a very mature caching system with greater flexibility.
And finally, THANK YOU to the people who matched my contribution. Now we’re all better off as a result!