2

Using JBoss Cache, it was possible to store the entity cache and query cache in the same cache region without any issue. But once migrated to wildfly 10 (with infinispan as 2LC) , there seems to be problem.

I have provided the cache region for entity as below.

@Entity     
@Cacheable  
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY, 
     region="regionA")
public class EntityXYZ{

And query cache as

 entManager.createQuery(
        "....")
    .setHint("org.hibernate.cacheable", true)
    .setHint("org.hibernate.cacheRegion", "regionA").getResultList();

It is important to note that the above query also contains the entities that are themselves declared as cacheable and has same cache region as regionA.

Now on execution, there is this error. I suspect that it is due to conflict as they are stored in same region and it tries to fetch object id that returns another object. But can someone throw light. Is this really the case ? and explain more about the error ?

But the same works in JBoss cache in JBoss 5. Does infinispan handles differently ? Or is this Hibernate issue ?

ERROR [org.jboss.as.ejb3.invocation] (default task-8) WFLYEJB0034: EJB Invocation failed on component... javax.ejb.EJBTransactionRolledbackException: Object [id=4] was not of the specified subclass [ com.abc.xyz] : loaded object was of wrong class class  com.abc.yyy
                at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:159)
                at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:256)

     [org.hibernate.event.internal.DefaultLoadEventListener] (default task-8) HHH000327: Error performing load command : org.hibernate.WrongClassException: Object [id=4] was not of the specified subclass [com.abc.xyz] : loaded object was of wrong class class com.abc.yyy

UPDATE:

The entitymanager tries to load in different calls of 2 such classes (in same shared cache 2LC region) that has @id as int. As Flavius pointed out, the id=4 seems to be common between 2 classes.

On adding below config to persistence.xml , there is a startup error.

persistence.xml

<property name="hibernate.cache.keys_factory" value="default" />

error

 javax.persistence.PersistenceException: [PersistenceUnit: app-entity] Unable to build Hibernate SessionFactory
            at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:179)
            at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:121)
            at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:667)
            at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:193)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at java.lang.Thread.run(Thread.java:745)
            at org.jboss.threads.JBossThread.run(JBossThread.java:320)
    Caused by: javax.persistence.PersistenceException: [PersistenceUnit: app-entity] Unable to build Hibernate SessionFactory
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954)
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:882)
            at org.jboss.as.jpa.hibernate5.TwoPhaseBootstrapImpl.build(TwoPhaseBootstrapImpl.java:44)
            at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:161)
            ... 7 more
    Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.spi.CacheImplementor]
            at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264)
            at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:228)
            at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:207)
            at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:242)
            at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
            at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879)
            ... 9 more
    Caused by: org.hibernate.boot.registry.selector.spi.StrategySelectionException: Unable to resolve name [default] as strategy [org.hibernate.cache.spi.CacheKeysFactory]
            at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.selectStrategyImplementor(StrategySelectorImpl.java:113)
            at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveDefaultableStrategy(StrategySelectorImpl.java:162)
            at org.hibernate.boot.registry.selector.internal.StrategySelectorImpl.resolveDefaultableStrategy(StrategySelectorImpl.java:126)

UPDATE 2

I have changed to provide the default to exact FQN, however it does not work. The error is not correct as the class is implementation of the specified class.

<property name="hibernate.cache.keys_factory" value="org.hibernate.cache.internal.DefaultCacheKeysFactory" />

error:

Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.spi.CacheImplementor]
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:264)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:228)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:207)
        at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:242)
        at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:444)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:879)
        ... 9 more
Caused by: java.lang.ClassCastException: org.hibernate.cache.internal.DefaultCacheKeysFactory cannot be cast to org.hibernate.cache.spi.CacheKeysFactory
        at org.hibernate.cache.infinispan.InfinispanRegionFactory.determineCacheKeysFactory(InfinispanRegionFactory.java:427)
        at org.hibernate.cache.infinispan.InfinispanRegionFactory.start(InfinispanRegionFactory.java:378)
        at org.hibernate.internal.CacheImpl.<init>(CacheImpl.java:49)
        at org.hibernate.engine.spi.CacheInitiator.initiateService(CacheInitiator.java:28)
        at org.hibernate.engine.spi.CacheInitiator.initiateService(CacheInitiator.java:20)
        at org.hibernate.service.internal.SessionFactoryServiceRegistryImpl.initiateService(SessionFactoryServiceRegistryImpl.java:46)
        at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:254)
ulab
  • 1,079
  • 3
  • 15
  • 45
  • According to JIRA it seems that the issue with DefaultCacheKeysFactory has been fixed in 5.0.12, 5.1.3 and 5.2.5. Usually you should be able to manually update WF's hibernate-orm module to 5.0.12 (as for any micro version). – Radim Vansa May 16 '17 at 12:21
  • Thanks. If there is no performance gain due to shared cache region, then I will just stick with best practices. – ulab May 16 '17 at 12:36

1 Answers1

3

Query cache is string-indexed, and the entity cache is indexed either using raw ids (the same object as the field/method marked with @Id in EntityXYZ) so I wonder how the conflict could happen on id=4.

Anyway, it's not a good idea to use the same region (cache) for entities and queries - entities sometimes need more complex handling to achieve DB-style isolation. Such combination may not be possible at all with Hibernate 6. You may not hit the issues until you run stress tests in many threads, sequential invocation usually works ok.

If you insist on storing them into the same cache, you could try setting hibernate.cache.keys_factory=default (I hope your WF version already contains this setting, newer versions should have it already as default).

See https://hibernate.atlassian.net/browse/HHH-11083 and https://hibernate.atlassian.net/browse/HHH-10287 for details.

Radim Vansa
  • 5,686
  • 2
  • 25
  • 40
  • 1
    Thanks. I have added the default cache key implementation as suggested and I get the error `Unable to resolve name [default] as strategy [org.hibernate.cache.spi.CacheKeysFactory]` on startup. I'm using the default hibernate (5.0.10) and Infinispan (8.2.4) that comes with WF 10.1. – ulab May 15 '17 at 08:33
  • I have added an UPDATE in my question. Infact you are right. The problem is not with query cache and entity cache in same region. But due to shared entity cache in same region. It looks like entitymanager.find (EntityXYZ.class, 4) returns different object than it is expected. And I think the solution described is not fixed in 5.0.x versions. – ulab May 15 '17 at 09:12
  • Also I wouldn't like to keep all entity in shared cache region. But I find the application run 3x times slower than earlier JBoss cache version which employs shared cache region for all entities. Does it provide any performance gain if entities are cached in shared cache region than separately? Any setting to improve performance is much appreciated. Thanks – ulab May 15 '17 at 09:16
  • I don't think that using shared cache region would give you any benefits; IMO it's useful only when you want to limit resource usage (which can be done only per cache) or aggregate some statistics together (though you could just sum it up...). Wrt 3x slower times: there have been some bugfixes that introduced more roundtrips between the nodes, especially if you use distributed/replicated caches. These operations fix some race conditions. However 3x is rather too much: do you have significantly lower hit/miss ratio? – Radim Vansa May 16 '17 at 12:17
  • I found that the application has little more extra step added (like unmarshalling) in new version and hence could be the delay. So sorry for not so exact comparison. – ulab May 16 '17 at 12:38