Fix CacheManager with same name grails-cache-ehcache

[box type=”shadow”]Or: “getting parallel deployment to work when using EhCache”[/box]

Caching

During our regular Grails development work, we apply both Hibernate with second level caching and Spring method level caching. They both use EhCache by default. This seems to be the only mature implementation choice for the Grails platform.
All this used to work fine (so we thought) until we wanted to add the Tomcat parallel deployment feature to the mix.

What happened was that we ran into the following error:
Another CacheManager with same name 'grails-cache-ehcache' already exists in the same VM

What does it mean?

Well, it comes down to a combination of libraries and use cases in which things become tricky. Some caching component is trying to start, but somehow it was already found to exist in the running JVM. I’m not going to bore you with specific versions of libraries, but I’ll explain why it matters (you can look them up in the links section at the end of this post).

Hibernate vs. EhCache versions



Caches are everywhere
One of the factors is the Hibernate version combined with an EhCache version, which at some version of EhCache starts requiring a unique name for the cache manager, and it should not exist yet within the VM. An existing cache manager will no longer be recycled. With older versions of EhCache (that come with Hibernate by default) this was not an immediate problem (although it could cause memory problems!, more on that later).

Grails Cache-EhCache plugin version

Another one is the grails cache-ehcache plugin to enable spring method cache using EhCache (because of the awesome TTL feature). It too will require a unique manager name starting from a certain version (for jmx registration).

Tomcat parallel deployment

The final factor is the Tomcat parallel deployment feature. The same application (and version) runs twice in the same VM for a while (until the all the sessions have moved to the new version). This will mean that where the cache manager (name) used to be unique inside the VM, it will no longer be. There will be two instances.

[box type=”shadow”]Do not get confused. A similar error will tell you “Another unnamed CacheManager already exists in the same VM, this is a slightly different problem which usually occurs when hibernate is ran without a context name specified.[/box]

Workarounds

We first started out with workarounds. To have a temporary fix, we just disabled method caches, or if possible went for the naive concurrent hashmap approach (that will eventually eat your entire heap!, but that’s ok for a temporary fix).

A sneaky problem on the side

But we also discovered that PermGen problems will occur if cache managers are not cleared! (or metaspace problems for Java 8). This problem required quite some investigation using visualvm and a lot of painful researching of classloaders and classes.

A solution for using EhCache for both purposes

In short: a unique name, for the cache manager, at each deployment using a timestamp. This will allow using ehCache for both spring method caching and hibernate second level cache. The next question would be, how to implement?

This actually required a minor code change in the cache-ehcache plugin for grails.
The plugin already allowed specifying a custom ‘provider’ name which results in a cache manager name, that can be made unique. This was not enough though. During the initialization phase there was a temporary cache manager instantiated that still uses a fixed name, which would clash.
The cache-ehcache plugin initialization strategy is a bit odd, this leads to the application having to specify the cache manager name twice. The code change makes it possible to also provide a custom name for that temporary instance.

So when using hibernate 4, combine it with ehcache 2.8.2 and using the latest cache-ehcache plugin (1.0.5-SNAPSHOT at the time of writing) an example config (several files) will look like this.

The configuration for this setup (Config.groovy):

Configure hibernate properly for second level cache (DataSource.groovy):

Libraries (in BuildConfig.groovy):

Maybe add some debugging using the BootStrap.groovy:

Having all this setup correctly, caching just works, parallel deploy works and PermGen is freed!

Other benefits:

  • a jmx registration that has the name of the application in it, so you can actually see which cache belongs to whom
  • a timestamp in the name provides direct information on whether the caches are old or new (when cache managers are re-used, it’s hard to tell)

Read more