0

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.

4
  • 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). Commented 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. Commented 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? Commented 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. Commented Dec 23, 2014 at 4:41

3 Answers 3

5

"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

Sign up to request clarification or add additional context in comments.

1 Comment

Does hibernate enforce that QueryCache is always local?
1

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

1

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:

  1. 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.
  2. The DistributedQueryCacheDataRegion implements QueryResultsRegion, but extends

    AbstractGeneralRegion<IMapRegionCache>
    
  3. 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.

3 Comments

Essentially you've posted the same answer than Luis'. Could you please elaborate on where yours provide more information about the problem? Cheers!
It's based on Lui's answer, but not exact: first change is that to avoid "merging" two classes into one, and follow possible changes in upgrades of 2 classes, I created an replica of one, with a minor 1-line change that is easier to follow. Second, the details of how to implement buildCollectionRegion() are not specified in Lui's answer. And last, I added more details on the generic interface, and the implementation using code samples.
Four years had passed, I just wonder if it did worked out well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.