I am successfully using Hazelcast as L2 distributed cache for Hibernate. It looks like query cache is not getting distributed. Is it not possible to use a distributed cache for the 'hibernate query cache'? Or am I missing a configuration to ensure that 'query cache' is also distributed? Using Hazelcast 3.2.6 and Grails 2.2.3.
-
How do you know that query cache is not distributed? Also note that query cache requires configuration at the query level (to mark it as cacheable).Andy Dufresne– Andy Dufresne2014-12-22 13:29:11 +00:00Commented Dec 22, 2014 at 13:29
-
@AndyDufresne I am successfully able to use the distributed L2 cache but query cache is not getting distributed by default and there is no documentation to make that happen.Champ– Champ2014-12-23 03:24:25 +00:00Commented Dec 23, 2014 at 3:24
-
How do you verify that query cache is not distributed? What distributed cache provider do you use? JBoss TreeCache?Andy Dufresne– Andy Dufresne2014-12-23 03:42:30 +00:00Commented Dec 23, 2014 at 3:42
-
1@AndyDufresne I am using Hazelcast for distributed caching. On executing a cacheable query once, the second time the application does not execute that query as it does not print with hibernate show_sql set to true. But it prints on another application node. For a fetch by ID, if the fetch has been done on one application node, then on another node the sql does not print (so in L2 cache distributed for the two application nodes). I can also query L2 distributed cache of Hazelcast to see the entry being present there. But this is not true of the query cache.Champ– Champ2014-12-23 04:41:11 +00:00Commented Dec 23, 2014 at 4:41
3 Answers
"NOTE: QueryCache is always LOCAL to the node and never distributed across Hazelcast Cluster" its from hazelcast documentation. Maybe if you use HazelcastLocalCacheRegionFactory on hibernate regionFactory config which stores data in a local node and sends invalidation messages when an entry is updated/deleted locally.
Here is the hazelcast documentation http://docs.hazelcast.org/docs/3.4/manual/pdf/hazelcast-documentation-3.4.pdf page 177
1 Comment
I'm testing the solution but apparently it works...
1 - Create DistributeQueryCacheHazelcastFactory that implements RegionCache.
2 - Put inside this class the content of HazelcastCacheRegionFactory + AbstractHazelcastCacheRegionFactory (you need to do this because buildQueryResultsRegion is marked as final).
3 - Implement buildQueryResultsRegion to return the class DistributedQueryCacheDataRegion that extends AbstractTransactionDataRegion (you need to create it) and implements QueryResultsRegion.
4 - Change the "hibernate.cache.region.factory_class" property to DistributeQueryCacheHazelcastFactory that you created.
5 - To cache the query in the distributed cache:
query.unwrap(org.hibernate.Query.class).setCacheable(true); query.unwrap(org.hibernate.Query.class).setCacheRegion("cacheName")
The cache region will be the name of the map created for this query in the Hazelcast distributed cache.
Take care with the size of each query cache.
Enjoy!
Comments
As suggested by @Luís Otávio Braga, I implemented a solution for making hibernate query cache distributed using hazelcast. There are several differences and more info to completing the answer:
- I copied AbstractHazelcastCacheRegionFactory to my own file, and just changed the buildQueryResultsRegion() method, not to be final. This enables me to do (relatively) easy future upgrades, as I know the only change is one modifier of a single method.
The DistributedQueryCacheDataRegion implements QueryResultsRegion, but extends
AbstractGeneralRegion<IMapRegionCache>The implementation of the buildQueryResultsRegion() method is:
@Override public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException { return new DistributedQueryCacheDataRegion(instance, regionName, properties, new IMapRegionCache(regionName, instance, properties, null)); }
So Complete code is:
AbstractHazelcastCacheRegionFactory same as hibernate, only none-final buildQueryResultsRegion().
DistributeQueryCacheHazelcastFactory:
/**
* Similar to com.hazelcast.hibernate.HazelcastCacheRegionFactory, only differences:
* 1. Extends our own implementation of AbstractHazelcastCacheRegionFactory.
* 2. Override buildQueryResultsRegion() to return DistributedQueryCacheDataRegion (that's why we needed our own
* implementation of AbstractHazelcastCacheRegionFactory to be able to override).
*
*/
public class DistributeQueryCacheHazelcastFactory extends AbstractHazelcastCacheRegionFactory {
private static final long serialVersionUID = 1L;
public DistributeQueryCacheHazelcastFactory() {
super();
}
public DistributeQueryCacheHazelcastFactory(final HazelcastInstance instance) {
super(instance);
}
public DistributeQueryCacheHazelcastFactory(final Properties properties) {
super(properties);
}
@Override
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
return new DistributedQueryCacheDataRegion(instance, regionName, properties, new IMapRegionCache(regionName,
instance, properties, null));
}
@Override
public CollectionRegion buildCollectionRegion(final String regionName, final Properties properties,
final CacheDataDescription metadata) throws CacheException {
return new HazelcastCollectionRegion<IMapRegionCache>(instance, regionName, properties, metadata,
new IMapRegionCache(regionName, instance, properties, metadata));
}
@Override
public EntityRegion buildEntityRegion(final String regionName, final Properties properties,
final CacheDataDescription metadata) throws CacheException {
return new HazelcastEntityRegion<IMapRegionCache>(instance, regionName, properties, metadata,
new IMapRegionCache(regionName, instance, properties, metadata));
}
@Override
public TimestampsRegion buildTimestampsRegion(final String regionName, final Properties properties)
throws CacheException {
return new HazelcastTimestampsRegion<IMapRegionCache>(instance, regionName, properties, new IMapRegionCache(
regionName, instance, properties, null));
}
}
DistributedQueryCacheDataRegion:
public class DistributedQueryCacheDataRegion extends AbstractGeneralRegion<IMapRegionCache> implements
QueryResultsRegion {
protected DistributedQueryCacheDataRegion(HazelcastInstance instance, String name, Properties props,
IMapRegionCache cache) {
super(instance, name, props, cache);
}
}
Last, need to change the factory in the hibernate configuration hibernate.cache.region.factory_class to the new DistributeQueryCacheHazelcastFactory class.