diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java index 7625685222..3dd26f8cd5 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java @@ -104,12 +104,12 @@ public class InfinispanRegionFactory implements RegionFactory { */ public static final String INFINISPAN_CONFIG_RESOURCE_PROP = "hibernate.cache.infinispan.cfg"; - /** - * Property name that controls whether Infinispan statistics are enabled. - * The property value is expected to be a boolean true or false, and it - * overrides statistic configuration in base Infinispan configuration, - * if provided. - */ + /** + * Property name that controls whether Infinispan statistics are enabled. + * The property value is expected to be a boolean true or false, and it + * overrides statistic configuration in base Infinispan configuration, + * if provided. + */ public static final String INFINISPAN_GLOBAL_STATISTICS_PROP = "hibernate.cache.infinispan.statistics"; /** diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/AccessDelegate.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/AccessDelegate.java new file mode 100644 index 0000000000..8d16419e72 --- /dev/null +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/AccessDelegate.java @@ -0,0 +1,157 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cache.infinispan.access; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; + +/** + * Defines the strategy for access to entity or collection data in a Infinispan instance. + *

+ * The intent of this class is to encapsulate common code and serve as a delegate for + * {@link org.hibernate.cache.spi.access.EntityRegionAccessStrategy} + * and {@link org.hibernate.cache.spi.access.CollectionRegionAccessStrategy} implementations. + * + * @author Radim Vansa <rvansa@redhat.com> + */ +public interface AccessDelegate { + Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException; + + /** + * Attempt to cache an object, after loading from the database. + * + * @param session Current session + * @param key The item key + * @param value The item + * @param txTimestamp a timestamp prior to the transaction start time + * @param version the item version number + * @return true if the object was successfully cached + */ + boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version); + + /** + * Attempt to cache an object, after loading from the database, explicitly + * specifying the minimalPut behavior. + * + * @param session Current session. + * @param key The item key + * @param value The item + * @param txTimestamp a timestamp prior to the transaction start time + * @param version the item version number + * @param minimalPutOverride Explicit minimalPut flag + * @return true if the object was successfully cached + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) + throws CacheException; + + /** + * Called after an item has been inserted (before the transaction completes), + * instead of calling evict(). + * + * @param session Current session + * @param key The item key + * @param value The item + * @param version The item's version value + * @return Were the contents of the cache actual changed by this operation? + * @throws CacheException if the insert fails + */ + boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException; + + /** + * Called after an item has been updated (before the transaction completes), + * instead of calling evict(). + * + * @param session Current session + * @param key The item key + * @param value The item + * @param currentVersion The item's current version value + * @param previousVersion The item's previous version value + * @return Whether the contents of the cache actual changed by this operation + * @throws CacheException if the update fails + */ + boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) + throws CacheException; + + /** + * Called after an item has become stale (before the transaction completes). + * + * @param session Current session + * @param key The key of the item to remove + * @throws CacheException if removing the cached item fails + */ + void remove(SessionImplementor session, Object key) throws CacheException; + + /** + * Called to evict data from the entire region + * + * @throws CacheException if eviction the region fails + */ + void removeAll() throws CacheException; + + /** + * Forcibly evict an item from the cache immediately without regard for transaction + * isolation. + * + * @param key The key of the item to remove + * @throws CacheException if evicting the item fails + */ + void evict(Object key) throws CacheException; + + /** + * Forcibly evict all items from the cache immediately without regard for transaction + * isolation. + * + * @throws CacheException if evicting items fails + */ + void evictAll() throws CacheException; + + /** + * Called when we have finished the attempted update/delete (which may or + * may not have been successful), after transaction completion. This method + * is used by "asynchronous" concurrency strategies. + * + * + * @param session + * @param key The item key + * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} + */ + void unlockItem(SessionImplementor session, Object key) throws CacheException; + + /** + * Called after an item has been inserted (after the transaction completes), + * instead of calling release(). + * This method is used by "asynchronous" concurrency strategies. + * + * + * @param session + * @param key The item key + * @param value The item + * @param version The item's version value + * @return Were the contents of the cache actual changed by this operation? + * @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region} + */ + boolean afterInsert(SessionImplementor session, Object key, Object value, Object version); + + /** + * Called after an item has been updated (after the transaction completes), + * instead of calling release(). This method is used by "asynchronous" + * concurrency strategies. + * + * + * @param session + * @param key The item key + * @param value The item + * @param currentVersion The item's current version value + * @param previousVersion The item's previous version value + * @param lock The lock previously obtained from {@link #lockItem} + * @return Were the contents of the cache actual changed by this operation? + * @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region} + */ + boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock); +} diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/InvalidationCacheAccessDelegate.java similarity index 51% rename from hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java rename to hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/InvalidationCacheAccessDelegate.java index 2943141ed3..0589e70320 100755 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/InvalidationCacheAccessDelegate.java @@ -9,37 +9,31 @@ package org.hibernate.cache.infinispan.access; import org.hibernate.cache.CacheException; import org.hibernate.cache.infinispan.impl.BaseRegion; import org.hibernate.cache.infinispan.util.Caches; -import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SessionImplementor; import org.infinispan.AdvancedCache; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; /** - * Defines the strategy for transactional access to entity or collection data in a Infinispan instance. - *

- * The intent of this class is to encapsulate common code and serve as a delegate for - * {@link org.hibernate.cache.spi.access.EntityRegionAccessStrategy} - * and {@link org.hibernate.cache.spi.access.CollectionRegionAccessStrategy} implementations. * * @author Brian Stansberry * @author Galder Zamarreño * @since 3.5 */ -public abstract class TransactionalAccessDelegate { - protected static final Log log = LogFactory.getLog( TransactionalAccessDelegate.class ); +public abstract class InvalidationCacheAccessDelegate implements AccessDelegate { + protected static final Log log = LogFactory.getLog( InvalidationCacheAccessDelegate.class ); protected static final boolean TRACE_ENABLED = log.isTraceEnabled(); protected final AdvancedCache cache; protected final BaseRegion region; protected final PutFromLoadValidator putValidator; protected final AdvancedCache writeCache; - public static TransactionalAccessDelegate create(BaseRegion region, PutFromLoadValidator validator) { + public static InvalidationCacheAccessDelegate create(BaseRegion region, PutFromLoadValidator validator) { if (region.getCache().getCacheConfiguration().transaction().transactionMode().isTransactional()) { - return new TxTransactionalAccessDelegate(region, validator); + return new TxInvalidationCacheAccessDelegate(region, validator); } else { - return new NonTxTransactionalAccessDelegate(region, validator); + return new NonTxInvalidationCacheAccessDelegate(region, validator); } } @@ -50,7 +44,7 @@ public abstract class TransactionalAccessDelegate { * @param validator put from load validator */ @SuppressWarnings("unchecked") - protected TransactionalAccessDelegate(BaseRegion region, PutFromLoadValidator validator) { + protected InvalidationCacheAccessDelegate(BaseRegion region, PutFromLoadValidator validator) { this.region = region; this.cache = region.getCache(); this.putValidator = validator; @@ -67,6 +61,7 @@ public abstract class TransactionalAccessDelegate { * @return the cached object or null * @throws CacheException if the cache retrieval failed */ + @Override @SuppressWarnings("UnusedParameters") public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException { if ( !region.checkValid() ) { @@ -79,16 +74,7 @@ public abstract class TransactionalAccessDelegate { return val; } - /** - * Attempt to cache an object, after loading from the database. - * - * @param session Current session - * @param key The item key - * @param value The item - * @param txTimestamp a timestamp prior to the transaction start time - * @param version the item version number - * @return true if the object was successfully cached - */ + @Override public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version) { return putFromLoad(session, key, value, txTimestamp, version, false ); } @@ -106,6 +92,7 @@ public abstract class TransactionalAccessDelegate { * @return true if the object was successfully cached * @throws CacheException if storing the object failed */ + @Override @SuppressWarnings("UnusedParameters") public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException { @@ -143,41 +130,7 @@ public abstract class TransactionalAccessDelegate { return true; } - /** - * Called after an item has been inserted (before the transaction completes), - * instead of calling evict(). - * - * @param session Current session - * @param key The item key - * @param value The item - * @param version The item's version value - * @return Were the contents of the cache actual changed by this operation? - * @throws CacheException if the insert fails - */ - public abstract boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException; - - /** - * Called after an item has been updated (before the transaction completes), - * instead of calling evict(). - * - * @param session Current session - * @param key The item key - * @param value The item - * @param currentVersion The item's current version value - * @param previousVersion The item's previous version value - * @return Whether the contents of the cache actual changed by this operation - * @throws CacheException if the update fails - */ - public abstract boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) - throws CacheException; - - /** - * Called after an item has become stale (before the transaction completes). - * - * @param session Current session - * @param key The key of the item to remove - * @throws CacheException if removing the cached item fails - */ + @Override public void remove(SessionImplementor session, Object key) throws CacheException { if ( !putValidator.beginInvalidatingKey(session, key)) { throw new CacheException( @@ -196,11 +149,7 @@ public abstract class TransactionalAccessDelegate { } } - /** - * Called to evict data from the entire region - * - * @throws CacheException if eviction the region fails - */ + @Override public void removeAll() throws CacheException { try { if (!putValidator.beginInvalidatingRegion()) { @@ -213,23 +162,12 @@ public abstract class TransactionalAccessDelegate { } } - /** - * Forcibly evict an item from the cache immediately without regard for transaction - * isolation. - * - * @param key The key of the item to remove - * @throws CacheException if evicting the item fails - */ + @Override public void evict(Object key) throws CacheException { writeCache.remove( key ); } - /** - * Forcibly evict all items from the cache immediately without regard for transaction - * isolation. - * - * @throws CacheException if evicting items fails - */ + @Override public void evictAll() throws CacheException { try { if (!putValidator.beginInvalidatingRegion()) { @@ -245,16 +183,7 @@ public abstract class TransactionalAccessDelegate { } } - /** - * Called when we have finished the attempted update/delete (which may or - * may not have been successful), after transaction completion. This method - * is used by "asynchronous" concurrency strategies. - * - * - * @param session - * @param key The item key - * @throws org.hibernate.cache.CacheException Propogated from underlying {@link org.hibernate.cache.spi.Region} - */ + @Override public void unlockItem(SessionImplementor session, Object key) throws CacheException { if ( !putValidator.endInvalidatingKey(session, key) ) { // TODO: localization @@ -262,50 +191,4 @@ public abstract class TransactionalAccessDelegate { + region.getName() + "; the key won't be cached until invalidation expires."); } } - - /** - * Called after an item has been inserted (after the transaction completes), - * instead of calling release(). - * This method is used by "asynchronous" concurrency strategies. - * - * - * @param session - * @param key The item key - * @param value The item - * @param version The item's version value - * @return Were the contents of the cache actual changed by this operation? - * @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region} - */ - public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) { - if ( !putValidator.endInvalidatingKey(session, key) ) { - // TODO: localization - log.warn("Failed to end invalidating pending putFromLoad calls for key " + key + " from region " - + region.getName() + "; the key won't be cached until invalidation expires."); - } - return false; - } - - /** - * Called after an item has been updated (after the transaction completes), - * instead of calling release(). This method is used by "asynchronous" - * concurrency strategies. - * - * - * @param session - * @param key The item key - * @param value The item - * @param currentVersion The item's current version value - * @param previousVersion The item's previous version value - * @param lock The lock previously obtained from {@link #lockItem} - * @return Were the contents of the cache actual changed by this operation? - * @throws CacheException Propagated from underlying {@link org.hibernate.cache.spi.Region} - */ - public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) { - if ( !putValidator.endInvalidatingKey(session, key) ) { - // TODO: localization - log.warn("Failed to end invalidating pending putFromLoad calls for key " + key + " from region " - + region.getName() + "; the key won't be cached until invalidation expires."); - } - return false; - } } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/NonTxInvalidationCacheAccessDelegate.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/NonTxInvalidationCacheAccessDelegate.java new file mode 100644 index 0000000000..3c0be3179b --- /dev/null +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/NonTxInvalidationCacheAccessDelegate.java @@ -0,0 +1,136 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cache.infinispan.access; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.impl.BaseRegion; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.resource.transaction.TransactionCoordinator; +import org.hibernate.resource.transaction.spi.TransactionStatus; + +import javax.transaction.Status; +import javax.transaction.SystemException; +import javax.transaction.TransactionManager; + +/** + * Delegate for non-transactional caches + * + * @author Radim Vansa <rvansa@redhat.com> + */ +public class NonTxInvalidationCacheAccessDelegate extends InvalidationCacheAccessDelegate { + public NonTxInvalidationCacheAccessDelegate(BaseRegion region, PutFromLoadValidator validator) { + super(region, validator); + } + + @Override + @SuppressWarnings("UnusedParameters") + public boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException { + if ( !region.checkValid() ) { + return false; + } + + // We need to be invalidating even for regular writes; if we were not and the write was followed by eviction + // (or any other invalidation), naked put that was started after the eviction ended but before this insert + // ended could insert the stale entry into the cache (since the entry was removed by eviction). + if ( !putValidator.beginInvalidatingWithPFER(session, key, value)) { + throw new CacheException( + "Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName() + ); + } + putValidator.setCurrentSession(session); + try { + writeCache.remove(key); + } + finally { + putValidator.resetCurrentSession(); + } + return true; + } + + @Override + @SuppressWarnings("UnusedParameters") + public boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) + throws CacheException { + // We update whether or not the region is valid. Other nodes + // may have already restored the region so they need to + // be informed of the change. + + // We need to be invalidating even for regular writes; if we were not and the write was followed by eviction + // (or any other invalidation), naked put that was started after the eviction ended but before this update + // ended could insert the stale entry into the cache (since the entry was removed by eviction). + if ( !putValidator.beginInvalidatingWithPFER(session, key, value)) { + throw new CacheException( + "Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName() + ); + } + putValidator.setCurrentSession(session); + try { + writeCache.remove(key); + } + finally { + putValidator.resetCurrentSession(); + } + return true; + } + + protected boolean isCommitted(SessionImplementor session) { + if (session.isClosed()) { + // If the session has been closed before transaction ends, so we cannot find out + // if the transaction was successful and if we can do the PFER. + // As this can happen only in JTA environment, we can query the TransactionManager + // directly here. + TransactionManager tm = region.getTransactionManager(); + if (tm != null) { + try { + switch (tm.getStatus()) { + case Status.STATUS_COMMITTED: + case Status.STATUS_COMMITTING: + return true; + default: + return false; + } + } + catch (SystemException e) { + log.debug("Failed to retrieve transaction status", e); + return false; + } + } + } + TransactionCoordinator tc = session.getTransactionCoordinator(); + return tc != null && tc.getTransactionDriverControl().getStatus() == TransactionStatus.COMMITTED; + } + + @Override + public void unlockItem(SessionImplementor session, Object key) throws CacheException { + if ( !putValidator.endInvalidatingKey(session, key, isCommitted(session)) ) { + // TODO: localization + log.warn("Failed to end invalidating pending putFromLoad calls for key " + key + " from region " + + region.getName() + "; the key won't be cached until invalidation expires."); + } + } + + @Override + public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) { + if ( !putValidator.endInvalidatingKey(session, key, isCommitted(session)) ) { + // TODO: localization + log.warn("Failed to end invalidating pending putFromLoad calls for key " + key + " from region " + + region.getName() + "; the key won't be cached until invalidation expires."); + } + return false; + } + + @Override + public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) { + if ( !putValidator.endInvalidatingKey(session, key, isCommitted(session)) ) { + // TODO: localization + log.warn("Failed to end invalidating pending putFromLoad calls for key " + key + " from region " + + region.getName() + "; the key won't be cached until invalidation expires."); + } + return false; + } +} diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java index f23f9abda4..a7e50d0a69 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java @@ -24,6 +24,7 @@ import org.hibernate.cache.spi.RegionFactory; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.resource.transaction.TransactionCoordinator; import org.infinispan.AdvancedCache; +import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.Configuration; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.interceptors.EntryWrappingInterceptor; @@ -34,8 +35,8 @@ import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; /** - * Encapsulates logic to allow a {@link TransactionalAccessDelegate} to determine - * whether a {@link TransactionalAccessDelegate#putFromLoad(org.hibernate.engine.spi.SessionImplementor, Object, Object, long, Object, boolean)} + * Encapsulates logic to allow a {@link InvalidationCacheAccessDelegate} to determine + * whether a {@link InvalidationCacheAccessDelegate#putFromLoad(org.hibernate.engine.spi.SessionImplementor, Object, Object, long, Object, boolean)} * call should be allowed to update the cache. A putFromLoad has * the potential to store stale data, since the data may have been removed from the * database and the cache between the time when the data was read from the database @@ -134,13 +135,10 @@ public class PutFromLoadValidator { /** * Creates a new put from load validator instance. - * - * @param cache Cache instance on which to store pending put information. - * @param cacheManager where to find a cache to store pending put information - */ - public PutFromLoadValidator(AdvancedCache cache, - EmbeddedCacheManager cacheManager) { - + * @param cache Cache instance on which to store pending put information. + * @param cacheManager where to find a cache to store pending put information + */ + public PutFromLoadValidator(AdvancedCache cache, EmbeddedCacheManager cacheManager) { Configuration cacheConfiguration = cache.getCacheConfiguration(); Configuration pendingPutsConfiguration = cacheManager.getCacheConfiguration(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME); ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); @@ -155,11 +153,14 @@ public class PutFromLoadValidator { else { throw new IllegalArgumentException("Pending puts cache needs to have maxIdle expiration set!"); } - + CacheMode cacheMode = cache.getCacheConfiguration().clustering().cacheMode(); // Since we need to intercept both invalidations of entries that are in the cache and those // that are not, we need to use custom interceptor, not listeners (which fire only for present entries). NonTxPutFromLoadInterceptor nonTxPutFromLoadInterceptor = null; - if (cacheConfiguration.clustering().cacheMode().isClustered()) { + if (cacheMode.isClustered()) { + if (!cacheMode.isInvalidation()) { + throw new IllegalArgumentException("PutFromLoadValidator in clustered caches requires invalidation mode."); + } List interceptorChain = cache.getInterceptorChain(); log.debug("Interceptor chain was: " + interceptorChain); int position = 0; diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/NonTxTransactionalAccessDelegate.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxInvalidationCacheAccessDelegate.java similarity index 70% rename from hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/NonTxTransactionalAccessDelegate.java rename to hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxInvalidationCacheAccessDelegate.java index 8cd1cb4969..11f688126f 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/NonTxTransactionalAccessDelegate.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxInvalidationCacheAccessDelegate.java @@ -8,17 +8,16 @@ package org.hibernate.cache.infinispan.access; import org.hibernate.cache.CacheException; import org.hibernate.cache.infinispan.impl.BaseRegion; +import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.resource.transaction.TransactionCoordinator; -import org.hibernate.resource.transaction.spi.TransactionStatus; /** - * Delegate for non-transactional caches + * Delegate for transactional caches * * @author Radim Vansa <rvansa@redhat.com> */ -public class NonTxTransactionalAccessDelegate extends TransactionalAccessDelegate { - public NonTxTransactionalAccessDelegate(BaseRegion region, PutFromLoadValidator validator) { +public class TxInvalidationCacheAccessDelegate extends InvalidationCacheAccessDelegate { + public TxInvalidationCacheAccessDelegate(BaseRegion region, PutFromLoadValidator validator) { super(region, validator); } @@ -32,14 +31,14 @@ public class NonTxTransactionalAccessDelegate extends TransactionalAccessDelegat // We need to be invalidating even for regular writes; if we were not and the write was followed by eviction // (or any other invalidation), naked put that was started after the eviction ended but before this insert // ended could insert the stale entry into the cache (since the entry was removed by eviction). - if ( !putValidator.beginInvalidatingWithPFER(session, key, value)) { + if ( !putValidator.beginInvalidatingKey(session, key)) { throw new CacheException( "Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName() ); } putValidator.setCurrentSession(session); try { - writeCache.remove(key); + writeCache.put(key, value); } finally { putValidator.resetCurrentSession(); @@ -58,14 +57,14 @@ public class NonTxTransactionalAccessDelegate extends TransactionalAccessDelegat // We need to be invalidating even for regular writes; if we were not and the write was followed by eviction // (or any other invalidation), naked put that was started after the eviction ended but before this update // ended could insert the stale entry into the cache (since the entry was removed by eviction). - if ( !putValidator.beginInvalidatingWithPFER(session, key, value)) { + if ( !putValidator.beginInvalidatingKey(session, key)) { throw new CacheException( "Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName() ); } putValidator.setCurrentSession(session); try { - writeCache.remove(key); + writeCache.put(key, value); } finally { putValidator.resetCurrentSession(); @@ -74,13 +73,22 @@ public class NonTxTransactionalAccessDelegate extends TransactionalAccessDelegat } @Override - public void unlockItem(SessionImplementor session, Object key) throws CacheException { - TransactionCoordinator tc = session.getTransactionCoordinator(); - boolean doPFER = tc != null && tc.getTransactionDriverControl().getStatus() == TransactionStatus.COMMITTED; - if ( !putValidator.endInvalidatingKey(session, key, doPFER) ) { + public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) { + if ( !putValidator.endInvalidatingKey(session, key) ) { // TODO: localization log.warn("Failed to end invalidating pending putFromLoad calls for key " + key + " from region " + region.getName() + "; the key won't be cached until invalidation expires."); } + return false; + } + + @Override + public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) { + if ( !putValidator.endInvalidatingKey(session, key) ) { + // TODO: localization + log.warn("Failed to end invalidating pending putFromLoad calls for key " + key + " from region " + + region.getName() + "; the key won't be cached until invalidation expires."); + } + return false; } } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxTransactionalAccessDelegate.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxTransactionalAccessDelegate.java deleted file mode 100644 index 09c093d8f0..0000000000 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TxTransactionalAccessDelegate.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.cache.infinispan.access; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.infinispan.impl.BaseRegion; -import org.hibernate.engine.spi.SessionImplementor; - -/** - * Delegate for transactional caches - * - * @author Radim Vansa <rvansa@redhat.com> - */ -public class TxTransactionalAccessDelegate extends TransactionalAccessDelegate { - public TxTransactionalAccessDelegate(BaseRegion region, PutFromLoadValidator validator) { - super(region, validator); - } - - @Override - @SuppressWarnings("UnusedParameters") - public boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException { - if ( !region.checkValid() ) { - return false; - } - - // We need to be invalidating even for regular writes; if we were not and the write was followed by eviction - // (or any other invalidation), naked put that was started after the eviction ended but before this insert - // ended could insert the stale entry into the cache (since the entry was removed by eviction). - if ( !putValidator.beginInvalidatingKey(session, key)) { - throw new CacheException( - "Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName() - ); - } - putValidator.setCurrentSession(session); - try { - writeCache.put(key, value); - } - finally { - putValidator.resetCurrentSession(); - } - return true; - } - - @Override - @SuppressWarnings("UnusedParameters") - public boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) - throws CacheException { - // We update whether or not the region is valid. Other nodes - // may have already restored the region so they need to - // be informed of the change. - - // We need to be invalidating even for regular writes; if we were not and the write was followed by eviction - // (or any other invalidation), naked put that was started after the eviction ended but before this update - // ended could insert the stale entry into the cache (since the entry was removed by eviction). - if ( !putValidator.beginInvalidatingKey(session, key)) { - throw new CacheException( - "Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName() - ); - } - putValidator.setCurrentSession(session); - try { - writeCache.put(key, value); - } - finally { - putValidator.resetCurrentSession(); - } - return true; - } -} diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/TransactionalAccess.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionAccess.java similarity index 86% rename from hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/TransactionalAccess.java rename to hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionAccess.java index 667ab05517..e9e7f6432f 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/TransactionalAccess.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionAccess.java @@ -7,7 +7,7 @@ package org.hibernate.cache.infinispan.collection; import org.hibernate.cache.CacheException; -import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate; +import org.hibernate.cache.infinispan.access.AccessDelegate; import org.hibernate.cache.spi.CollectionRegion; import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; import org.hibernate.cache.spi.access.SoftLock; @@ -16,21 +16,19 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.persister.collection.CollectionPersister; /** - * Transactional collection region access for Infinispan. + * Collection region access for Infinispan. * * @author Chris Bredesen * @author Galder Zamarreño * @since 3.5 */ -class TransactionalAccess implements CollectionRegionAccessStrategy { - +class CollectionAccess implements CollectionRegionAccessStrategy { private final CollectionRegionImpl region; + private final AccessDelegate delegate; - private final TransactionalAccessDelegate delegate; - - TransactionalAccess(CollectionRegionImpl region) { + CollectionAccess(CollectionRegionImpl region, AccessDelegate delegate) { this.region = region; - this.delegate = TransactionalAccessDelegate.create( region, region.getPutFromLoadValidator() ); + this.delegate = delegate; } public void evict(Object key) throws CacheException { diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionRegionImpl.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionRegionImpl.java index a24ae1984d..fc79383bc9 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionRegionImpl.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionRegionImpl.java @@ -7,7 +7,8 @@ package org.hibernate.cache.infinispan.collection; import org.hibernate.cache.CacheException; -import org.hibernate.cache.infinispan.access.PutFromLoadValidator; +import org.hibernate.cache.infinispan.access.AccessDelegate; +import org.hibernate.cache.infinispan.access.InvalidationCacheAccessDelegate; import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion; import org.hibernate.cache.spi.CacheDataDescription; import org.hibernate.cache.spi.CacheKeysFactory; @@ -27,17 +28,16 @@ import javax.transaction.TransactionManager; * @since 3.5 */ public class CollectionRegionImpl extends BaseTransactionalDataRegion implements CollectionRegion { - - /** - * Construct a collection region - * - * @param cache instance to store collection instances - * @param name of collection type + /** + * Construct a collection region + * + * @param cache instance to store collection instances + * @param name of collection type * @param transactionManager - * @param metadata for the collection type - * @param factory for the region - * @param cacheKeysFactory factory for cache keys - */ + * @param metadata for the collection type + * @param factory for the region + * @param cacheKeysFactory factory for cache keys + */ public CollectionRegionImpl( AdvancedCache cache, String name, TransactionManager transactionManager, CacheDataDescription metadata, RegionFactory factory, CacheKeysFactory cacheKeysFactory) { @@ -46,16 +46,16 @@ public class CollectionRegionImpl extends BaseTransactionalDataRegion implements @Override public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { - if ( AccessType.READ_ONLY.equals( accessType ) - || AccessType.TRANSACTIONAL.equals( accessType ) ) { - return new TransactionalAccess( this ); + checkAccessType( accessType ); + getValidator(); + AccessDelegate delegate = InvalidationCacheAccessDelegate.create(this, getValidator()); + switch ( accessType ) { + case READ_ONLY: + case READ_WRITE: + case TRANSACTIONAL: + return new CollectionAccess( this, delegate ); + default: + throw new CacheException( "Unsupported access type [" + accessType.getExternalName() + "]" ); } - - throw new CacheException( "Unsupported access type [" + accessType.getExternalName() + "]" ); } - - public PutFromLoadValidator getPutFromLoadValidator() { - return new PutFromLoadValidator( cache ); - } - } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java index 265b7f7470..759933830a 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java @@ -7,7 +7,7 @@ package org.hibernate.cache.infinispan.entity; import org.hibernate.cache.CacheException; -import org.hibernate.cache.infinispan.access.PutFromLoadValidator; +import org.hibernate.cache.infinispan.access.InvalidationCacheAccessDelegate; import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion; import org.hibernate.cache.spi.CacheDataDescription; import org.hibernate.cache.spi.CacheKeysFactory; @@ -28,17 +28,16 @@ import javax.transaction.TransactionManager; * @since 3.5 */ public class EntityRegionImpl extends BaseTransactionalDataRegion implements EntityRegion { - - /** - * Construct a entity region - * - * @param cache instance to store entity instances - * @param name of entity type + /** + * Construct a entity region + * + * @param cache instance to store entity instances + * @param name of entity type * @param transactionManager - * @param metadata for the entity type - * @param factory for the region - * @param cacheKeysFactory factory for cache keys - */ + * @param metadata for the entity type + * @param factory for the region + * @param cacheKeysFactory factory for cache keys + */ public EntityRegionImpl( AdvancedCache cache, String name, TransactionManager transactionManager, CacheDataDescription metadata, RegionFactory factory, CacheKeysFactory cacheKeysFactory) { @@ -47,22 +46,19 @@ public class EntityRegionImpl extends BaseTransactionalDataRegion implements Ent @Override public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { + checkAccessType(accessType); + if ( !getCacheDataDescription().isMutable() ) { + accessType = AccessType.READ_ONLY; + } + InvalidationCacheAccessDelegate accessDelegate = InvalidationCacheAccessDelegate.create(this, getValidator()); switch ( accessType ) { case READ_ONLY: - return new ReadOnlyAccess( this ); + return new ReadOnlyAccess( this, accessDelegate); + case READ_WRITE: case TRANSACTIONAL: - if ( getCacheDataDescription().isMutable() ) { - return new TransactionalAccess( this ); - } - else { - return new ReadOnlyAccess( this ); - } + return new ReadWriteAccess( this, accessDelegate); default: throw new CacheException( "Unsupported access type [" + accessType.getExternalName() + "]" ); } } - - public PutFromLoadValidator getPutFromLoadValidator() { - return new PutFromLoadValidator( cache ); - } } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java index af3e57b390..af92f1b97b 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java @@ -7,21 +7,66 @@ package org.hibernate.cache.infinispan.entity; import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.access.InvalidationCacheAccessDelegate; +import org.hibernate.cache.spi.EntityRegion; +import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.persister.entity.EntityPersister; /** - * A specialization of {@link TransactionalAccess} that ensures we never update data. Infinispan - * access is always transactional. + * A specialization of {@link ReadWriteAccess} that ensures we never update data. * * @author Chris Bredesen * @author Galder Zamarreño * @since 3.5 */ -class ReadOnlyAccess extends TransactionalAccess { +class ReadOnlyAccess implements EntityRegionAccessStrategy { - ReadOnlyAccess(EntityRegionImpl region) { - super( region ); + protected final EntityRegionImpl region; + protected final InvalidationCacheAccessDelegate delegate; + + ReadOnlyAccess(EntityRegionImpl region, InvalidationCacheAccessDelegate delegate) { + this.region = region; + this.delegate = delegate; + } + + public void evict(Object key) throws CacheException { + delegate.evict( key ); + } + + public void evictAll() throws CacheException { + delegate.evictAll(); + } + + public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException { + return delegate.get( session, key, txTimestamp ); + } + + public EntityRegion getRegion() { + return this.region; + } + + public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version) throws CacheException { + return delegate.putFromLoad( session, key, value, txTimestamp, version ); + } + + public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) + throws CacheException { + return delegate.putFromLoad( session, key, value, txTimestamp, version, minimalPutOverride ); + } + + public void remove(SessionImplementor session, Object key) throws CacheException { + delegate.remove ( session, key ); + } + + public void removeAll() throws CacheException { + delegate.removeAll(); + } + + public boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException { + return delegate.insert( session, key, value, version ); } @Override @@ -31,6 +76,25 @@ class ReadOnlyAccess extends TransactionalAccess { throw new UnsupportedOperationException( "Illegal attempt to edit read only item" ); } + public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException { + return null; + } + + public SoftLock lockRegion() throws CacheException { + return null; + } + + public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException { + delegate.unlockItem( session, key ); + } + + public void unlockRegion(SoftLock lock) throws CacheException { + } + + public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) throws CacheException { + return delegate.afterInsert( session, key, value, version ); + } + @Override public boolean afterUpdate( SessionImplementor session, Object key, Object value, Object currentVersion, @@ -38,4 +102,13 @@ class ReadOnlyAccess extends TransactionalAccess { throw new UnsupportedOperationException( "Illegal attempt to edit read only item" ); } + @Override + public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) { + return region.getCacheKeysFactory().createEntityKey(id, persister, factory, tenantIdentifier); + } + + @Override + public Object getCacheKeyId(Object cacheKey) { + return region.getCacheKeysFactory().getEntityId(cacheKey); + } } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadWriteAccess.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadWriteAccess.java new file mode 100644 index 0000000000..f8dd4b439f --- /dev/null +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadWriteAccess.java @@ -0,0 +1,36 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cache.infinispan.entity; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.access.InvalidationCacheAccessDelegate; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; + +/** + * Read-write or transactional entity region access for Infinispan. + * + * @author Chris Bredesen + * @author Galder Zamarreño + * @since 3.5 + */ +class ReadWriteAccess extends ReadOnlyAccess { + + ReadWriteAccess(EntityRegionImpl region, InvalidationCacheAccessDelegate delegate) { + super(region, delegate); + } + + public boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) + throws CacheException { + return delegate.update( session, key, value, currentVersion, previousVersion ); + } + + public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) + throws CacheException { + return delegate.afterUpdate( session, key, value, currentVersion, previousVersion, lock ); + } +} diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java deleted file mode 100644 index b8bd59ceef..0000000000 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.cache.infinispan.entity; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate; -import org.hibernate.cache.spi.EntityRegion; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.persister.entity.EntityPersister; - -/** - * Transactional entity region access for Infinispan. - * - * @author Chris Bredesen - * @author Galder Zamarreño - * @since 3.5 - */ -class TransactionalAccess implements EntityRegionAccessStrategy { - - private final EntityRegionImpl region; - - private final TransactionalAccessDelegate delegate; - - TransactionalAccess(EntityRegionImpl region) { - this.region = region; - this.delegate = TransactionalAccessDelegate.create( region, region.getPutFromLoadValidator() ); - } - - public void evict(Object key) throws CacheException { - delegate.evict( key ); - } - - public void evictAll() throws CacheException { - delegate.evictAll(); - } - - public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException { - return delegate.get( session, key, txTimestamp ); - } - - public EntityRegion getRegion() { - return this.region; - } - - public boolean insert(SessionImplementor session, Object key, Object value, Object version) throws CacheException { - return delegate.insert( session, key, value, version ); - } - - public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version) throws CacheException { - return delegate.putFromLoad( session, key, value, txTimestamp, version ); - } - - public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) - throws CacheException { - return delegate.putFromLoad( session, key, value, txTimestamp, version, minimalPutOverride ); - } - - public void remove(SessionImplementor session, Object key) throws CacheException { - delegate.remove ( session, key ); - } - - public void removeAll() throws CacheException { - delegate.removeAll(); - } - - public boolean update(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion) - throws CacheException { - return delegate.update( session, key, value, currentVersion, previousVersion ); - } - - public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException { - return null; - } - - public SoftLock lockRegion() throws CacheException { - return null; - } - - public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException { - delegate.unlockItem( session, key ); - } - - public void unlockRegion(SoftLock lock) throws CacheException { - } - - public boolean afterInsert(SessionImplementor session, Object key, Object value, Object version) throws CacheException { - return delegate.afterInsert( session, key, value, version ); - } - - public boolean afterUpdate(SessionImplementor session, Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock) - throws CacheException { - return delegate.afterUpdate( session, key, value, currentVersion, previousVersion, lock ); - } - - @Override - public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) { - return region.getCacheKeysFactory().createEntityKey(id, persister, factory, tenantIdentifier); - } - - @Override - public Object getCacheKeyId(Object cacheKey) { - return region.getCacheKeysFactory().getEntityId(cacheKey); - } -} diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java index 2a825af24c..cf6953c14b 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java @@ -14,10 +14,12 @@ import javax.transaction.Transaction; import javax.transaction.TransactionManager; import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.access.PutFromLoadValidator; import org.hibernate.cache.infinispan.util.Caches; import org.hibernate.cache.spi.Region; import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; import org.infinispan.AdvancedCache; import org.infinispan.context.Flag; import org.infinispan.util.logging.Log; @@ -35,7 +37,6 @@ import org.infinispan.util.logging.LogFactory; public abstract class BaseRegion implements Region { private static final Log log = LogFactory.getLog( BaseRegion.class ); - private Transaction currentTransaction; private enum InvalidateState { INVALID, CLEARING, VALID @@ -48,12 +49,13 @@ public abstract class BaseRegion implements Region { private final Object invalidationMutex = new Object(); private final AtomicReference invalidateState = new AtomicReference( InvalidateState.VALID ); - private volatile Transaction invalidateTransaction; private final RegionFactory factory; protected final AdvancedCache cache; + private PutFromLoadValidator validator; + /** * Base region constructor. * @@ -110,7 +112,7 @@ public abstract class BaseRegion implements Region { @Override public int getTimeout() { // 60 seconds - return 600; + return 60000; } @Override @@ -149,21 +151,7 @@ public abstract class BaseRegion implements Region { synchronized (invalidationMutex) { if ( invalidateState.compareAndSet( InvalidateState.INVALID, InvalidateState.CLEARING ) ) { try { - // If we're running inside a transaction, we need to remove elements one-by-one - // to clean the context as well (cache.clear() does not do that). - // When we don't have transaction, we can do a clear operation (since we don't - // case about context) and can't do the one-by-one remove: remove() on tx cache - // requires transactional context. - Transaction tx = getCurrentTransaction(); - if ( tx != null ) { - log.tracef( "Transaction, clearing one element at the time" ); - Caches.removeAll( localAndSkipLoadCache ); - } - else { - log.tracef( "Non-transactional, clear in one go" ); - localAndSkipLoadCache.clear(); - } - + runInvalidation( getCurrentTransaction() != null ); log.tracef( "Transition state from CLEARING to VALID" ); invalidateState.compareAndSet( InvalidateState.CLEARING, InvalidateState.VALID @@ -228,7 +216,7 @@ public abstract class BaseRegion implements Region { if (log.isTraceEnabled()) { log.trace( "Invalidate region: " + name ); } - invalidateState.set( InvalidateState.INVALID ); + invalidateState.set(InvalidateState.INVALID); } public TransactionManager getTransactionManager() { @@ -255,4 +243,35 @@ public abstract class BaseRegion implements Region { } } + protected void checkAccessType(AccessType accessType) { + if (accessType == AccessType.TRANSACTIONAL && !cache.getCacheConfiguration().transaction().transactionMode().isTransactional()) { + log.warn("Requesting TRANSACTIONAL cache concurrency strategy but the cache is not configured as transactional."); + } + else if (accessType == AccessType.READ_WRITE && cache.getCacheConfiguration().transaction().transactionMode().isTransactional()) { + log.warn("Requesting READ_WRITE cache concurrency strategy but the cache was configured as transactional."); + } + } + + protected synchronized PutFromLoadValidator getValidator() { + if (validator == null) { + validator = new PutFromLoadValidator(cache); + } + return validator; + } + + protected void runInvalidation(boolean inTransaction) { + // If we're running inside a transaction, we need to remove elements one-by-one + // to clean the context as well (cache.clear() does not do that). + // When we don't have transaction, we can do a clear operation (since we don't + // case about context) and can't do the one-by-one remove: remove() on tx cache + // requires transactional context. + if ( inTransaction ) { + log.tracef( "Transaction, clearing one element at the time" ); + Caches.removeAll( localAndSkipLoadCache ); + } + else { + log.tracef( "Non-transactional, clear in one go" ); + localAndSkipLoadCache.clear(); + } + } } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/NaturalIdRegionImpl.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/NaturalIdRegionImpl.java index 8539f737c6..4a6c522c6e 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/NaturalIdRegionImpl.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/NaturalIdRegionImpl.java @@ -7,7 +7,9 @@ package org.hibernate.cache.infinispan.naturalid; import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.access.AccessDelegate; import org.hibernate.cache.infinispan.access.PutFromLoadValidator; +import org.hibernate.cache.infinispan.access.InvalidationCacheAccessDelegate; import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion; import org.hibernate.cache.spi.CacheDataDescription; import org.hibernate.cache.spi.CacheKeysFactory; @@ -46,18 +48,19 @@ public class NaturalIdRegionImpl extends BaseTransactionalDataRegion @Override public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException { + checkAccessType( accessType ); + if (!getCacheDataDescription().isMutable()) { + accessType = AccessType.READ_ONLY; + } + AccessDelegate delegate = InvalidationCacheAccessDelegate.create( this, getValidator()); switch ( accessType ) { case READ_ONLY: - return new ReadOnlyAccess( this ); + return new ReadOnlyAccess( this, delegate ); + case READ_WRITE: case TRANSACTIONAL: - return new TransactionalAccess( this ); + return new ReadWriteAccess( this, delegate ); default: throw new CacheException( "Unsupported access type [" + accessType.getExternalName() + "]" ); } } - - public PutFromLoadValidator getPutFromLoadValidator() { - return new PutFromLoadValidator( cache ); - } - } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/ReadOnlyAccess.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/ReadOnlyAccess.java index 83cc4b6fe0..ca27471c4f 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/ReadOnlyAccess.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/ReadOnlyAccess.java @@ -7,16 +7,29 @@ package org.hibernate.cache.infinispan.naturalid; import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.access.AccessDelegate; +import org.hibernate.cache.spi.NaturalIdRegion; +import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.persister.entity.EntityPersister; /** * @author Strong Liu */ -class ReadOnlyAccess extends TransactionalAccess { +class ReadOnlyAccess implements NaturalIdRegionAccessStrategy { - ReadOnlyAccess(NaturalIdRegionImpl naturalIdRegion) { - super( naturalIdRegion ); + protected final NaturalIdRegionImpl region; + protected final AccessDelegate delegate; + + ReadOnlyAccess(NaturalIdRegionImpl region, AccessDelegate delegate) { + this.region = region; + this.delegate = delegate; + } + + @Override + public boolean insert(SessionImplementor session, Object key, Object value) throws CacheException { + return delegate.insert( session, key, value, null ); } @Override @@ -24,9 +37,83 @@ class ReadOnlyAccess extends TransactionalAccess { throw new UnsupportedOperationException( "Illegal attempt to edit read only item" ); } + @Override + public NaturalIdRegion getRegion() { + return region; + } + + @Override + public void evict(Object key) throws CacheException { + delegate.evict( key ); + } + + @Override + public void evictAll() throws CacheException { + delegate.evictAll(); + } + + @Override + public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException { + return delegate.get( session, key, txTimestamp ); + } + + @Override + public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version) throws CacheException { + return delegate.putFromLoad( session, key, value, txTimestamp, version ); + } + + @Override + public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) + throws CacheException { + return delegate.putFromLoad( session, key, value, txTimestamp, version, minimalPutOverride ); + } + + @Override + public void remove(SessionImplementor session, Object key) throws CacheException { + delegate.remove( session, key ); + } + + @Override + public void removeAll() throws CacheException { + delegate.removeAll(); + } + + @Override + public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException { + return null; + } + + @Override + public SoftLock lockRegion() throws CacheException { + return null; + } + + @Override + public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException { + delegate.unlockItem( session, key ); + } + + @Override + public void unlockRegion(SoftLock lock) throws CacheException { + } + + @Override + public boolean afterInsert(SessionImplementor session, Object key, Object value) throws CacheException { + return delegate.afterInsert( session, key, value, null ); + } + @Override public boolean afterUpdate(SessionImplementor session, Object key, Object value, SoftLock lock) throws CacheException { throw new UnsupportedOperationException( "Illegal attempt to edit read only item" ); } + @Override + public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) { + return region.getCacheKeysFactory().createNaturalIdKey(naturalIdValues, persister, session); + } + + @Override + public Object[] getNaturalIdValues(Object cacheKey) { + return region.getCacheKeysFactory().getNaturalIdValues(cacheKey); + } } diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/ReadWriteAccess.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/ReadWriteAccess.java new file mode 100644 index 0000000000..6b59511933 --- /dev/null +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/ReadWriteAccess.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cache.infinispan.naturalid; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.access.AccessDelegate; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; + +/** + * @author Strong Liu + */ +class ReadWriteAccess extends ReadOnlyAccess { + + ReadWriteAccess(NaturalIdRegionImpl region, AccessDelegate delegate) { + super(region, delegate); + } + + @Override + public boolean update(SessionImplementor session, Object key, Object value) throws CacheException { + return delegate.update( session, key, value, null, null ); + } + + @Override + public boolean afterUpdate(SessionImplementor session, Object key, Object value, SoftLock lock) throws CacheException { + return delegate.afterUpdate( session, key, value, null, null, lock ); + } + +} diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/TransactionalAccess.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/TransactionalAccess.java deleted file mode 100644 index da3ad010ef..0000000000 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/naturalid/TransactionalAccess.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.cache.infinispan.naturalid; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate; -import org.hibernate.cache.spi.NaturalIdRegion; -import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.persister.entity.EntityPersister; - -/** - * @author Strong Liu - */ -class TransactionalAccess implements NaturalIdRegionAccessStrategy { - private final NaturalIdRegionImpl region; - private final TransactionalAccessDelegate delegate; - - TransactionalAccess(NaturalIdRegionImpl region) { - this.region = region; - this.delegate = TransactionalAccessDelegate.create( region, region.getPutFromLoadValidator() ); - } - - @Override - public boolean insert(SessionImplementor session, Object key, Object value) throws CacheException { - return delegate.insert( session, key, value, null ); - } - - @Override - public boolean update(SessionImplementor session, Object key, Object value) throws CacheException { - return delegate.update( session, key, value, null, null ); - } - - @Override - public NaturalIdRegion getRegion() { - return region; - } - - @Override - public void evict(Object key) throws CacheException { - delegate.evict( key ); - } - - @Override - public void evictAll() throws CacheException { - delegate.evictAll(); - } - - @Override - public Object get(SessionImplementor session, Object key, long txTimestamp) throws CacheException { - return delegate.get( session, key, txTimestamp ); - } - - @Override - public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version) throws CacheException { - return delegate.putFromLoad( session, key, value, txTimestamp, version ); - } - - @Override - public boolean putFromLoad(SessionImplementor session, Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) - throws CacheException { - return delegate.putFromLoad( session, key, value, txTimestamp, version, minimalPutOverride ); - } - - @Override - public void remove(SessionImplementor session, Object key) throws CacheException { - delegate.remove( session, key ); - } - - @Override - public void removeAll() throws CacheException { - delegate.removeAll(); - } - - @Override - public SoftLock lockItem(SessionImplementor session, Object key, Object version) throws CacheException { - return null; - } - - @Override - public SoftLock lockRegion() throws CacheException { - return null; - } - - @Override - public void unlockItem(SessionImplementor session, Object key, SoftLock lock) throws CacheException { - delegate.unlockItem( session, key ); - } - - @Override - public void unlockRegion(SoftLock lock) throws CacheException { - } - - @Override - public boolean afterInsert(SessionImplementor session, Object key, Object value) throws CacheException { - return delegate.afterInsert( session, key, value, null ); - } - - @Override - public boolean afterUpdate(SessionImplementor session, Object key, Object value, SoftLock lock) throws CacheException { - return delegate.afterUpdate( session, key, value, null, null, lock ); - } - - @Override - public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) { - return region.getCacheKeysFactory().createNaturalIdKey(naturalIdValues, persister, session); - } - - @Override - public Object[] getNaturalIdValues(Object cacheKey) { - return region.getCacheKeysFactory().getNaturalIdValues(cacheKey); - } -} diff --git a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/Caches.java b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/Caches.java index a85aeddd68..89e8ff615f 100644 --- a/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/Caches.java +++ b/hibernate-infinispan/src/main/java/org/hibernate/cache/infinispan/util/Caches.java @@ -124,7 +124,7 @@ public class Caches { * @return a cache that ignores return values */ public static AdvancedCache ignoreReturnValuesCache(AdvancedCache cache) { - return cache.withFlags( Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP ); + return cache.withFlags( Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP, Flag.IGNORE_RETURN_VALUES ); } /** @@ -139,7 +139,7 @@ public class Caches { public static AdvancedCache ignoreReturnValuesCache( AdvancedCache cache, Flag extraFlag) { return cache.withFlags( - Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP, extraFlag + Flag.SKIP_CACHE_LOAD, Flag.SKIP_REMOTE_LOOKUP, Flag.IGNORE_RETURN_VALUES, extraFlag ); } @@ -270,6 +270,11 @@ public class Caches { .clustering().cacheMode().isClustered(); } + public static boolean isTransactionalCache(AdvancedCache cache) { + return cache.getCacheConfiguration().transaction().transactionMode().isTransactional(); + } + + public static void removeAll(AdvancedCache cache) { CloseableIterator it = keys(cache).iterator(); try { diff --git a/hibernate-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml b/hibernate-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml index 74a30adaf7..b8fca11b15 100644 --- a/hibernate-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml +++ b/hibernate-infinispan/src/main/resources/org/hibernate/cache/infinispan/builder/infinispan-configs.xml @@ -20,40 +20,23 @@ - - + + - + - - - - - - - - - - - - - - - - - - + @@ -61,7 +44,7 @@ - + @@ -71,7 +54,7 @@ is required if query caching is used, even if the query cache itself is configured with CacheMode=LOCAL. --> - + diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractEntityCollectionRegionTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractEntityCollectionRegionTest.java similarity index 96% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractEntityCollectionRegionTestCase.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractEntityCollectionRegionTest.java index d8b84bf9fe..7e179c80ab 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractEntityCollectionRegionTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractEntityCollectionRegionTest.java @@ -30,7 +30,7 @@ import static org.junit.Assert.assertTrue; * @author Galder Zamarreño * @since 3.5 */ -public abstract class AbstractEntityCollectionRegionTestCase extends AbstractRegionImplTestCase { +public abstract class AbstractEntityCollectionRegionTest extends AbstractRegionImplTest { protected static CacheDataDescription MUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(true, false, ComparableComparator.INSTANCE, null); @Test @@ -43,7 +43,8 @@ public abstract class AbstractEntityCollectionRegionTestCase extends AbstractReg "test", InfinispanRegionFactory.class, true, - false + false, + jtaPlatform ); ssrb.applySetting( InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, "entity" ); final StandardServiceRegistry registry = ssrb.build(); @@ -72,7 +73,8 @@ public abstract class AbstractEntityCollectionRegionTestCase extends AbstractReg "test", InfinispanRegionFactory.class, true, - false + false, + jtaPlatform ); final StandardServiceRegistry registry = ssrb.build(); try { @@ -101,7 +103,8 @@ public abstract class AbstractEntityCollectionRegionTestCase extends AbstractReg "test", InfinispanRegionFactory.class, true, - false + false, + jtaPlatform ); final StandardServiceRegistry registry = ssrb.build(); try { diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractExtraAPITest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractExtraAPITest.java new file mode 100644 index 0000000000..e4e5c07028 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractExtraAPITest.java @@ -0,0 +1,80 @@ +package org.hibernate.test.cache.infinispan; + +import org.hibernate.cache.internal.CacheDataDescriptionImpl; +import org.hibernate.cache.spi.CacheDataDescription; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.RegionAccessStrategy; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.internal.util.compare.ComparableComparator; +import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; +import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; + +/** + * @author Radim Vansa <rvansa@redhat.com> + */ +public abstract class AbstractExtraAPITest extends AbstractNonFunctionalTest { + @Rule + public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + + public static final String REGION_NAME = "test/com.foo.test"; + public static final Object KEY = TestingKeyFactory.generateCollectionCacheKey( "KEY" ); + public static final CacheDataDescription CACHE_DATA_DESCRIPTION + = new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE, null); + protected static final SessionImplementor SESSION = mock(SessionImplementor.class); + + protected S accessStrategy; + protected NodeEnvironment environment; + + @Before + public final void prepareLocalAccessStrategy() throws Exception { + environment = new NodeEnvironment( createStandardServiceRegistryBuilder() ); + environment.prepare(); + + // Sleep a bit to avoid concurrent FLUSH problem + avoidConcurrentFlush(); + + accessStrategy = getAccessStrategy(); + } + + protected abstract S getAccessStrategy(); + + protected abstract AccessType getAccessType(); + + @After + public final void releaseLocalAccessStrategy() throws Exception { + if ( environment != null ) { + environment.release(); + } + } + + @Test + public void testLockItem() { + assertNull( accessStrategy.lockItem(SESSION, KEY, Integer.valueOf( 1 ) ) ); + } + + @Test + public void testLockRegion() { + assertNull( accessStrategy.lockRegion() ); + } + + @Test + public void testUnlockItem() { + accessStrategy.unlockItem(SESSION, KEY, new MockSoftLock() ); + } + + @Test + public void testUnlockRegion() { + accessStrategy.unlockItem(SESSION, KEY, new MockSoftLock() ); + } + + public static class MockSoftLock implements SoftLock { + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTest.java similarity index 85% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTestCase.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTest.java index e118f0327d..e382428324 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTest.java @@ -12,7 +12,6 @@ import java.util.Properties; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; -import java.util.function.BiConsumer; import org.hibernate.Session; import org.hibernate.SessionFactory; @@ -29,18 +28,12 @@ import org.hibernate.cache.spi.Region; import org.hibernate.cache.spi.RegionFactory; import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; -import org.hibernate.test.cache.infinispan.functional.SingleNodeTestCase; -import org.hibernate.test.cache.infinispan.util.BatchModeJtaPlatform; import org.hibernate.test.cache.infinispan.util.CacheTestUtil; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; import org.infinispan.AdvancedCache; -import org.infinispan.commons.util.CloseableIterable; -import org.infinispan.transaction.tm.BatchModeTransactionManager; import org.jboss.logging.Logger; import org.junit.Test; -import javax.transaction.TransactionManager; - import static org.hibernate.test.cache.infinispan.util.CacheTestUtil.assertEqualsEventually; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -51,8 +44,8 @@ import static org.junit.Assert.assertNull; * @author Galder Zamarreño * @since 3.5 */ -public abstract class AbstractGeneralDataRegionTestCase extends AbstractRegionImplTestCase { - private static final Logger log = Logger.getLogger( AbstractGeneralDataRegionTestCase.class ); +public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTest { + private static final Logger log = Logger.getLogger( AbstractGeneralDataRegionTest.class ); protected static final String KEY = "Key"; @@ -60,17 +53,6 @@ public abstract class AbstractGeneralDataRegionTestCase extends AbstractRegionIm protected static final String VALUE2 = "value2"; protected static final String VALUE3 = "value3"; - protected TransactionManager tm = BatchModeTransactionManager.getInstance(); - - protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() { - return CacheTestUtil.buildBaselineStandardServiceRegistryBuilder( - "test", - InfinispanRegionFactory.class, - false, - true - ); - } - @Override protected void putInRegion(Region region, Object key, Object value) { ((GeneralDataRegion) region).put(null, key, value ); @@ -92,9 +74,7 @@ public abstract class AbstractGeneralDataRegionTestCase extends AbstractRegionIm protected void withSessionFactoriesAndRegions(int num, SFRConsumer consumer) throws Exception { StandardServiceRegistryBuilder ssrb = createStandardServiceRegistryBuilder() - .applySetting(AvailableSettings.CACHE_REGION_FACTORY, SingleNodeTestCase.TestInfinispanRegionFactory.class.getName()) - .applySetting(AvailableSettings.JTA_PLATFORM, BatchModeJtaPlatform.class.getName()) - .applySetting(AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class.getName()); + .applySetting(AvailableSettings.CACHE_REGION_FACTORY, TestInfinispanRegionFactory.class.getName()); Properties properties = CacheTestUtil.toProperties( ssrb.getSettings() ); List registries = new ArrayList<>(); List sessionFactories = new ArrayList<>(); @@ -168,7 +148,7 @@ public abstract class AbstractGeneralDataRegionTestCase extends AbstractRegionIm region.evict(KEY); } - protected abstract String getStandardRegionName(String regionPrefix); + protected abstract String getStandardRegionName(String regionPrefix); /** * Test method for {@link QueryResultsRegion#evictAll()}. diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTest.java new file mode 100644 index 0000000000..8f5d6fc98b --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTest.java @@ -0,0 +1,169 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cache.infinispan.util.Caches; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; +import org.hibernate.resource.transaction.spi.TransactionStatus; +import org.hibernate.test.cache.infinispan.util.BatchModeJtaPlatform; +import org.hibernate.test.cache.infinispan.util.CacheTestUtil; +import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; +import org.hibernate.testing.junit4.CustomParameterized; +import org.infinispan.Cache; +import org.jboss.logging.Logger; +import org.junit.After; +import org.junit.Before; + +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.test.cache.infinispan.util.CacheTestSupport; +import org.junit.Rule; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import javax.transaction.TransactionManager; + +/** + * Base class for all non-functional tests of Infinispan integration. + * + * @author Galder Zamarreño + * @since 3.5 + */ +@RunWith(CustomParameterized.class) +public abstract class AbstractNonFunctionalTest extends org.hibernate.testing.junit4.BaseUnitTestCase { + private static final Logger log = Logger.getLogger(AbstractNonFunctionalTest.class); + + @Rule + public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + + @Parameterized.Parameters(name = "{0}") + public static List getJtaParameters() { + return Arrays.asList( + new Object[] { "JTA", BatchModeJtaPlatform.class }, + new Object[] { "non-JTA", null }); + } + + @Parameterized.Parameter(value = 0) + public String mode; + + @Parameterized.Parameter(value = 1) + public Class jtaPlatform; + + public static final String REGION_PREFIX = "test"; + + private static final String PREFER_IPV4STACK = "java.net.preferIPv4Stack"; + private String preferIPv4Stack; + private static final String JGROUPS_CFG_FILE = "hibernate.cache.infinispan.jgroups_cfg"; + private String jgroupsCfgFile; + + private CacheTestSupport testSupport = new CacheTestSupport(); + + @Before + public void prepareCacheSupport() throws Exception { + preferIPv4Stack = System.getProperty(PREFER_IPV4STACK); + System.setProperty(PREFER_IPV4STACK, "true"); + jgroupsCfgFile = System.getProperty(JGROUPS_CFG_FILE); + System.setProperty(JGROUPS_CFG_FILE, "2lc-test-tcp.xml"); + + testSupport.setUp(); + } + + @After + public void releaseCachSupport() throws Exception { + testSupport.tearDown(); + + if (preferIPv4Stack == null) { + System.clearProperty(PREFER_IPV4STACK); + } else { + System.setProperty(PREFER_IPV4STACK, preferIPv4Stack); + } + + if (jgroupsCfgFile == null) + System.clearProperty(JGROUPS_CFG_FILE); + else + System.setProperty(JGROUPS_CFG_FILE, jgroupsCfgFile); + } + + protected T withTx(NodeEnvironment environment, SessionImplementor session, Callable callable) throws Exception { + if (jtaPlatform != null) { + TransactionManager tm = environment.getServiceRegistry().getService(JtaPlatform.class).retrieveTransactionManager(); + return Caches.withinTx(tm, callable); + } else { + Transaction transaction = ((Session) session).beginTransaction(); + boolean rollingBack = false; + try { + T retval = callable.call(); + if (transaction.getStatus() == TransactionStatus.ACTIVE) { + transaction.commit(); + } else { + rollingBack = true; + transaction.rollback(); + } + return retval; + } catch (Exception e) { + if (!rollingBack) { + try { + transaction.rollback(); + } catch (Exception suppressed) { + e.addSuppressed(suppressed); + } + } + throw e; + } + } + } + + protected void registerCache(Cache cache) { + testSupport.registerCache(cache); + } + + protected void unregisterCache(Cache cache) { + testSupport.unregisterCache(cache); + } + + protected void registerFactory(RegionFactory factory) { + testSupport.registerFactory(factory); + } + + protected void unregisterFactory(RegionFactory factory) { + testSupport.unregisterFactory(factory); + } + + protected CacheTestSupport getCacheTestSupport() { + return testSupport; + } + + protected void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + log.warn("Interrupted during sleep", e); + } + } + + protected void avoidConcurrentFlush() { + testSupport.avoidConcurrentFlush(); + } + + protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() { + final StandardServiceRegistryBuilder ssrb = CacheTestUtil.buildBaselineStandardServiceRegistryBuilder( + REGION_PREFIX, getRegionFactoryClass(), true, false, jtaPlatform); + return ssrb; + } + + protected Class getRegionFactoryClass() { + return TestInfinispanRegionFactory.class; + } +} \ No newline at end of file diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTestCase.java deleted file mode 100644 index f01344dbdc..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTestCase.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan; - -import java.util.Set; - -import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.infinispan.Cache; -import org.jboss.logging.Logger; -import org.junit.After; -import org.junit.Before; - -import org.hibernate.cache.spi.RegionFactory; -import org.hibernate.test.cache.infinispan.util.CacheTestSupport; -import org.junit.Rule; - -/** - * Base class for all non-functional tests of Infinispan integration. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public abstract class AbstractNonFunctionalTestCase extends org.hibernate.testing.junit4.BaseUnitTestCase { - private static final Logger log = Logger.getLogger(AbstractNonFunctionalTestCase.class); - - @Rule - public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - - public static final String REGION_PREFIX = "test"; - - private static final String PREFER_IPV4STACK = "java.net.preferIPv4Stack"; - private String preferIPv4Stack; - private static final String JGROUPS_CFG_FILE = "hibernate.cache.infinispan.jgroups_cfg"; - private String jgroupsCfgFile; - - private CacheTestSupport testSupport = new CacheTestSupport(); - - @Before - public void prepareCacheSupport() throws Exception { - preferIPv4Stack = System.getProperty(PREFER_IPV4STACK); - System.setProperty(PREFER_IPV4STACK, "true"); - jgroupsCfgFile = System.getProperty(JGROUPS_CFG_FILE); - System.setProperty(JGROUPS_CFG_FILE, "2lc-test-tcp.xml"); - - testSupport.setUp(); - } - - @After - public void releaseCachSupport() throws Exception { - testSupport.tearDown(); - - if (preferIPv4Stack == null) { - System.clearProperty(PREFER_IPV4STACK); - } else { - System.setProperty(PREFER_IPV4STACK, preferIPv4Stack); - } - - if (jgroupsCfgFile == null) - System.clearProperty(JGROUPS_CFG_FILE); - else - System.setProperty(JGROUPS_CFG_FILE, jgroupsCfgFile); - } - - protected void registerCache(Cache cache) { - testSupport.registerCache(cache); - } - - protected void unregisterCache(Cache cache) { - testSupport.unregisterCache(cache); - } - - protected void registerFactory(RegionFactory factory) { - testSupport.registerFactory(factory); - } - - protected void unregisterFactory(RegionFactory factory) { - testSupport.unregisterFactory(factory); - } - - protected CacheTestSupport getCacheTestSupport() { - return testSupport; - } - - protected void sleep(long ms) { - try { - Thread.sleep(ms); - } catch (InterruptedException e) { - log.warn("Interrupted during sleep", e); - } - } - - protected void avoidConcurrentFlush() { - testSupport.avoidConcurrentFlush(); - } -} \ No newline at end of file diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionAccessStrategyTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionAccessStrategyTest.java new file mode 100644 index 0000000000..b47910e268 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionAccessStrategyTest.java @@ -0,0 +1,360 @@ +package org.hibernate.test.cache.infinispan; + +import junit.framework.AssertionFailedError; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cache.infinispan.impl.BaseRegion; +import org.hibernate.cache.infinispan.util.Caches; +import org.hibernate.cache.internal.CacheDataDescriptionImpl; +import org.hibernate.cache.spi.CacheDataDescription; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.RegionAccessStrategy; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.transaction.internal.TransactionImpl; +import org.hibernate.internal.util.compare.ComparableComparator; +import org.hibernate.resource.transaction.TransactionCoordinator; +import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl; +import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransactionAccess; +import org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner; +import org.hibernate.test.cache.infinispan.util.BatchModeJtaPlatform; +import org.hibernate.test.cache.infinispan.util.BatchModeTransactionCoordinator; +import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; +import org.hibernate.test.cache.infinispan.util.JdbcResourceTransactionMock; +import org.hibernate.test.cache.infinispan.util.TestSynchronization; +import org.infinispan.Cache; +import org.infinispan.test.TestingUtil; +import org.jboss.logging.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import javax.transaction.RollbackException; +import javax.transaction.SystemException; +import javax.transaction.TransactionManager; + +import java.util.Arrays; +import java.util.concurrent.CountDownLatch; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author Radim Vansa <rvansa@redhat.com> + */ +public abstract class AbstractRegionAccessStrategyTest + extends AbstractNonFunctionalTest { + protected final Logger log = Logger.getLogger(getClass()); + + @Rule + public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + + public static final String REGION_NAME = "test/com.foo.test"; + public static final String KEY_BASE = "KEY"; + public static final String VALUE1 = "VALUE1"; + public static final String VALUE2 = "VALUE2"; + public static final CacheDataDescription CACHE_DATA_DESCRIPTION + = new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE, null); + + protected NodeEnvironment localEnvironment; + protected R localRegion; + protected S localAccessStrategy; + + protected NodeEnvironment remoteEnvironment; + protected R remoteRegion; + protected S remoteAccessStrategy; + + protected boolean transactional; + protected boolean invalidation; + protected boolean synchronous; + protected Exception node1Exception; + protected Exception node2Exception; + protected AssertionFailedError node1Failure; + protected AssertionFailedError node2Failure; + + protected abstract AccessType getAccessType(); + + @Before + public void prepareResources() throws Exception { + // to mimic exactly the old code results, both environments here are exactly the same... + StandardServiceRegistryBuilder ssrb = createStandardServiceRegistryBuilder(); + localEnvironment = new NodeEnvironment( ssrb ); + localEnvironment.prepare(); + + localRegion = getRegion(localEnvironment); + localAccessStrategy = getAccessStrategy(localRegion); + + transactional = Caches.isTransactionalCache(localRegion.getCache()); + invalidation = Caches.isInvalidationCache(localRegion.getCache()); + synchronous = Caches.isSynchronousCache(localRegion.getCache()); + + // Sleep a bit to avoid concurrent FLUSH problem + avoidConcurrentFlush(); + + remoteEnvironment = new NodeEnvironment( ssrb ); + remoteEnvironment.prepare(); + + remoteRegion = getRegion(remoteEnvironment); + remoteAccessStrategy = getAccessStrategy(remoteRegion); + + waitForClusterToForm(localRegion.getCache(), remoteRegion.getCache()); + } + + private interface SessionMock extends Session, SessionImplementor { + } + + private interface NonJtaTransactionCoordinator extends TransactionCoordinatorOwner, JdbcResourceTransactionAccess { + } + + protected SessionImplementor mockedSession() { + SessionMock session = mock(SessionMock.class); + when(session.isClosed()).thenReturn(false); + if (jtaPlatform == BatchModeJtaPlatform.class) { + BatchModeTransactionCoordinator txCoord = new BatchModeTransactionCoordinator(); + when(session.getTransactionCoordinator()).thenReturn(txCoord); + when(session.beginTransaction()).then(invocation -> { + Transaction tx = txCoord.newTransaction(); + tx.begin(); + return tx; + }); + } else if (jtaPlatform == null) { + NonJtaTransactionCoordinator txOwner = mock(NonJtaTransactionCoordinator.class); + when(txOwner.getResourceLocalTransaction()).thenReturn(new JdbcResourceTransactionMock()); + TransactionCoordinator txCoord = JdbcResourceLocalTransactionCoordinatorBuilderImpl.INSTANCE + .buildTransactionCoordinator(txOwner, null); + when(session.getTransactionCoordinator()).thenReturn(txCoord); + when(session.beginTransaction()).then(invocation -> { + Transaction tx = new TransactionImpl(txCoord); + tx.begin(); + return tx; + }); + } else { + throw new IllegalStateException("Unknown JtaPlatform: " + jtaPlatform); + } + return session; + } + + protected abstract S getAccessStrategy(R region); + + @Test + public void testRemove() throws Exception { + evictOrRemoveTest( false ); + } + + @Test + public void testEvict() throws Exception { + evictOrRemoveTest( true ); + } + + protected abstract R getRegion(NodeEnvironment environment); + + protected void waitForClusterToForm(Cache... caches) { + TestingUtil.blockUntilViewsReceived(10000, Arrays.asList(caches)); + } + + @After + public void releaseResources() throws Exception { + try { + if (localEnvironment != null) { + localEnvironment.release(); + } + } + finally { + if (remoteEnvironment != null) { + remoteEnvironment.release(); + } + } + } + + protected boolean isTransactional() { + return transactional; + } + + protected boolean isUsingInvalidation() { + return invalidation; + } + + protected boolean isSynchronous() { + return synchronous; + } + + protected void evictOrRemoveTest(final boolean evict) throws Exception { + final Object KEY = generateNextKey(); + assertEquals(0, localRegion.getCache().size()); + assertEquals(0, remoteRegion.getCache().size()); + + assertNull("local is clean", localAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + assertNull("remote is clean", remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + + localAccessStrategy.putFromLoad(mockedSession(), KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); + assertEquals(VALUE1, localAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + remoteAccessStrategy.putFromLoad(mockedSession(), KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); + assertEquals(VALUE1, remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, () -> { + if (evict) { + localAccessStrategy.evict(KEY); + } + else { + doRemove(localRegion.getTransactionManager(), localAccessStrategy, session, KEY); + } + return null; + }); + + assertNull(localAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + assertEquals(0, localRegion.getCache().size()); + assertNull(remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + assertEquals(0, remoteRegion.getCache().size()); + } + + protected void doRemove(TransactionManager tm, S strategy, SessionImplementor session, Object key) throws SystemException, RollbackException { + SoftLock softLock = strategy.lockItem(session, key, null); + strategy.remove(session, key); + session.getTransactionCoordinator().getLocalSynchronizations().registerSynchronization( + new TestSynchronization.UnlockItem(strategy, session, key, softLock)); + } + + @Test + public void testRemoveAll() throws Exception { + evictOrRemoveAllTest(false); + } + + @Test + public void testEvictAll() throws Exception { + evictOrRemoveAllTest(true); + } + + protected void assertThreadsRanCleanly() { + if (node1Failure != null) { + throw node1Failure; + } + if (node2Failure != null) { + throw node2Failure; + } + + if (node1Exception != null) { + log.error("node1 saw an exception", node1Exception); + assertEquals("node1 saw no exceptions", null, node1Exception); + } + + if (node2Exception != null) { + log.error("node2 saw an exception", node2Exception); + assertEquals("node2 saw no exceptions", null, node2Exception); + } + } + + @Test + public void testPutFromLoad() throws Exception { + putFromLoadTest( false ); + } + + @Test + public void testPutFromLoadMinimal() throws Exception { + putFromLoadTest( true ); + } + + protected abstract void putFromLoadTest(boolean useMinimalAPI) throws Exception; + + protected abstract Object generateNextKey(); + + protected void evictOrRemoveAllTest(final boolean evict) throws Exception { + final Object KEY = generateNextKey(); + assertEquals(0, localRegion.getCache().size()); + assertEquals(0, remoteRegion.getCache().size()); + assertNull("local is clean", localAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + assertNull("remote is clean", remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + + localAccessStrategy.putFromLoad(mockedSession(), KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); + assertEquals(VALUE1, localAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + remoteAccessStrategy.putFromLoad(mockedSession(), KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); + assertEquals(VALUE1, remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + + // Wait for async propagation + sleep(250); + + withTx(localEnvironment, mockedSession(), () -> { + if (evict) { + localAccessStrategy.evictAll(); + } else { + SoftLock softLock = localAccessStrategy.lockRegion(); + localAccessStrategy.removeAll(); + localAccessStrategy.unlockRegion(softLock); + } + return null; + }); + // This should re-establish the region root node in the optimistic case + assertNull(localAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + assertEquals(0, localRegion.getCache().size()); + + // Re-establishing the region root on the local node doesn't + // propagate it to other nodes. Do a get on the remote node to re-establish + assertNull(remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + assertEquals(0, remoteRegion.getCache().size()); + + // Wait for async propagation of EndInvalidationCommand before executing naked put + sleep(250); + + // Test whether the get above messes up the optimistic version + remoteAccessStrategy.putFromLoad(mockedSession(), KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); + assertEquals(VALUE1, remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + assertEquals(1, remoteRegion.getCache().size()); + + // Wait for async propagation + sleep(250); + + assertEquals((isUsingInvalidation() ? null : VALUE1), localAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + assertEquals(VALUE1, remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + } + + protected class PutFromLoadNode2 extends Thread { + private final Object KEY; + private final CountDownLatch writeLatch1; + private final CountDownLatch writeLatch2; + private final boolean useMinimalAPI; + private final CountDownLatch completionLatch; + + public PutFromLoadNode2(Object KEY, CountDownLatch writeLatch1, CountDownLatch writeLatch2, boolean useMinimalAPI, CountDownLatch completionLatch) { + this.KEY = KEY; + this.writeLatch1 = writeLatch1; + this.writeLatch2 = writeLatch2; + this.useMinimalAPI = useMinimalAPI; + this.completionLatch = completionLatch; + } + + @Override + public void run() { + try { + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mockedSession(); + withTx(remoteEnvironment, session, () -> { + + assertNull(remoteAccessStrategy.get(session, KEY, txTimestamp)); + + // Let node1 write + writeLatch1.countDown(); + // Wait for node1 to finish + writeLatch2.await(); + + if (useMinimalAPI) { + remoteAccessStrategy.putFromLoad(session, KEY, VALUE1, txTimestamp, new Integer(1), true); + } else { + remoteAccessStrategy.putFromLoad(session, KEY, VALUE1, txTimestamp, new Integer(1)); + } + return null; + }); + } catch (Exception e) { + log.error("node2 caught exception", e); + node2Exception = e; + } catch (AssertionFailedError e) { + node2Failure = e; + } finally { + completionLatch.countDown(); + } + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTest.java similarity index 93% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTestCase.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTest.java index 57c3198b7f..4ee32d1b2e 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTest.java @@ -21,7 +21,7 @@ import org.infinispan.AdvancedCache; * @author Galder Zamarreño * @since 3.5 */ -public abstract class AbstractRegionImplTestCase extends AbstractNonFunctionalTestCase { +public abstract class AbstractRegionImplTest extends AbstractNonFunctionalTest { protected abstract AdvancedCache getInfinispanCache(InfinispanRegionFactory regionFactory); diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java index 34fcc3d047..30d539c1fa 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java @@ -27,8 +27,8 @@ import org.hibernate.engine.transaction.jta.platform.internal.JBossStandAloneJta import org.hibernate.service.ServiceRegistry; import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; import org.hibernate.testing.ServiceRegistryBuilder; -import org.hibernate.test.cache.infinispan.functional.SingleNodeTestCase; import org.hibernate.testing.boot.ServiceRegistryTestingImpl; import org.junit.Rule; import org.junit.Test; @@ -58,561 +58,561 @@ import static org.junit.Assert.fail; * @since 3.5 */ public class InfinispanRegionFactoryTestCase { - private static final CacheDataDescription MUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(true, false, null, null); - private static final CacheDataDescription IMMUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(false, false, null, null); + private static final CacheDataDescription MUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(true, false, null, null); + private static final CacheDataDescription IMMUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(false, false, null, null); - @Rule - public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + @Rule + public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - @Test - public void testConfigurationProcessing() { - final String person = "com.acme.Person"; - final String addresses = "com.acme.Person.addresses"; - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.cfg", "person-cache"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.wake_up_interval", "2000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_entries", "5000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.cfg", "person-addresses-cache"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.expiration.lifespan", "120000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.expiration.max_idle", "60000"); - p.setProperty("hibernate.cache.infinispan.query.cfg", "my-query-cache"); - p.setProperty("hibernate.cache.infinispan.query.eviction.strategy", "LIRS"); - p.setProperty("hibernate.cache.infinispan.query.eviction.wake_up_interval", "3000"); - p.setProperty("hibernate.cache.infinispan.query.eviction.max_entries", "10000"); + @Test + public void testConfigurationProcessing() { + final String person = "com.acme.Person"; + final String addresses = "com.acme.Person.addresses"; + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.cfg", "person-cache"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.wake_up_interval", "2000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_entries", "5000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.cfg", "person-addresses-cache"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.expiration.lifespan", "120000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.expiration.max_idle", "60000"); + p.setProperty("hibernate.cache.infinispan.query.cfg", "my-query-cache"); + p.setProperty("hibernate.cache.infinispan.query.eviction.strategy", "LIRS"); + p.setProperty("hibernate.cache.infinispan.query.eviction.wake_up_interval", "3000"); + p.setProperty("hibernate.cache.infinispan.query.eviction.max_entries", "10000"); - InfinispanRegionFactory factory = createRegionFactory(p); + InfinispanRegionFactory factory = createRegionFactory(p); - try { - assertEquals("entity", factory.getTypeOverrides().get("entity").getCacheName()); - assertEquals("entity", factory.getTypeOverrides().get("collection").getCacheName()); - assertEquals("timestamps", factory.getTypeOverrides().get("timestamps").getCacheName()); + try { + assertEquals("entity", factory.getTypeOverrides().get("entity").getCacheName()); + assertEquals("entity", factory.getTypeOverrides().get("collection").getCacheName()); + assertEquals("timestamps", factory.getTypeOverrides().get("timestamps").getCacheName()); - assertEquals("person-cache", factory.getTypeOverrides().get(person).getCacheName()); - assertEquals(EvictionStrategy.LRU, factory.getTypeOverrides().get(person).getEvictionStrategy()); - assertEquals(2000, factory.getTypeOverrides().get(person).getEvictionWakeUpInterval()); - assertEquals(5000, factory.getTypeOverrides().get(person).getEvictionMaxEntries()); - assertEquals(60000, factory.getTypeOverrides().get(person).getExpirationLifespan()); - assertEquals(30000, factory.getTypeOverrides().get(person).getExpirationMaxIdle()); + assertEquals("person-cache", factory.getTypeOverrides().get(person).getCacheName()); + assertEquals(EvictionStrategy.LRU, factory.getTypeOverrides().get(person).getEvictionStrategy()); + assertEquals(2000, factory.getTypeOverrides().get(person).getEvictionWakeUpInterval()); + assertEquals(5000, factory.getTypeOverrides().get(person).getEvictionMaxEntries()); + assertEquals(60000, factory.getTypeOverrides().get(person).getExpirationLifespan()); + assertEquals(30000, factory.getTypeOverrides().get(person).getExpirationMaxIdle()); - assertEquals("person-addresses-cache", factory.getTypeOverrides().get(addresses).getCacheName()); - assertEquals(120000, factory.getTypeOverrides().get(addresses).getExpirationLifespan()); - assertEquals(60000, factory.getTypeOverrides().get(addresses).getExpirationMaxIdle()); + assertEquals("person-addresses-cache", factory.getTypeOverrides().get(addresses).getCacheName()); + assertEquals(120000, factory.getTypeOverrides().get(addresses).getExpirationLifespan()); + assertEquals(60000, factory.getTypeOverrides().get(addresses).getExpirationMaxIdle()); - assertEquals("my-query-cache", factory.getTypeOverrides().get("query").getCacheName()); - assertEquals(EvictionStrategy.LIRS, factory.getTypeOverrides().get("query").getEvictionStrategy()); - assertEquals(3000, factory.getTypeOverrides().get("query").getEvictionWakeUpInterval()); - assertEquals(10000, factory.getTypeOverrides().get("query").getEvictionMaxEntries()); - } finally { - factory.stop(); - } - } + assertEquals("my-query-cache", factory.getTypeOverrides().get("query").getCacheName()); + assertEquals(EvictionStrategy.LIRS, factory.getTypeOverrides().get("query").getEvictionStrategy()); + assertEquals(3000, factory.getTypeOverrides().get("query").getEvictionWakeUpInterval()); + assertEquals(10000, factory.getTypeOverrides().get("query").getEvictionMaxEntries()); + } finally { + factory.stop(); + } + } - @Test - public void testBuildEntityCollectionRegionsPersonPlusEntityCollectionOverrides() { - final String person = "com.acme.Person"; - final String address = "com.acme.Address"; - final String car = "com.acme.Car"; - final String addresses = "com.acme.Person.addresses"; - final String parts = "com.acme.Car.parts"; - Properties p = createProperties(); - // First option, cache defined for entity and overrides for generic entity data type and entity itself. - p.setProperty("hibernate.cache.infinispan.com.acme.Person.cfg", "person-cache"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.wake_up_interval", "2000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_entries", "5000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); - p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "LIRS"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "20000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.cfg", "addresses-cache"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.strategy", "LIRS"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.wake_up_interval", "2500"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.max_entries", "5500"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.expiration.lifespan", "65000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.expiration.max_idle", "35000"); - p.setProperty("hibernate.cache.infinispan.collection.cfg", "mycollection-cache"); - p.setProperty("hibernate.cache.infinispan.collection.eviction.strategy", "LRU"); - p.setProperty("hibernate.cache.infinispan.collection.eviction.wake_up_interval", "3500"); - p.setProperty("hibernate.cache.infinispan.collection.eviction.max_entries", "25000"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - EmbeddedCacheManager manager = factory.getCacheManager(); - assertFalse(manager.getCacheManagerConfiguration() - .globalJmxStatistics().enabled()); - assertNotNull(factory.getTypeOverrides().get(person)); - assertFalse(factory.getDefinedConfigurations().contains(person)); - assertNotNull(factory.getTypeOverrides().get(addresses)); - assertFalse(factory.getDefinedConfigurations().contains(addresses)); - AdvancedCache cache; + @Test + public void testBuildEntityCollectionRegionsPersonPlusEntityCollectionOverrides() { + final String person = "com.acme.Person"; + final String address = "com.acme.Address"; + final String car = "com.acme.Car"; + final String addresses = "com.acme.Person.addresses"; + final String parts = "com.acme.Car.parts"; + Properties p = createProperties(); + // First option, cache defined for entity and overrides for generic entity data type and entity itself. + p.setProperty("hibernate.cache.infinispan.com.acme.Person.cfg", "person-cache"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.wake_up_interval", "2000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_entries", "5000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); + p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "LIRS"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "20000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.cfg", "addresses-cache"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.strategy", "LIRS"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.wake_up_interval", "2500"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.max_entries", "5500"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.expiration.lifespan", "65000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.expiration.max_idle", "35000"); + p.setProperty("hibernate.cache.infinispan.collection.cfg", "mycollection-cache"); + p.setProperty("hibernate.cache.infinispan.collection.eviction.strategy", "LRU"); + p.setProperty("hibernate.cache.infinispan.collection.eviction.wake_up_interval", "3500"); + p.setProperty("hibernate.cache.infinispan.collection.eviction.max_entries", "25000"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + EmbeddedCacheManager manager = factory.getCacheManager(); + assertFalse(manager.getCacheManagerConfiguration() + .globalJmxStatistics().enabled()); + assertNotNull(factory.getTypeOverrides().get(person)); + assertFalse(factory.getDefinedConfigurations().contains(person)); + assertNotNull(factory.getTypeOverrides().get(addresses)); + assertFalse(factory.getDefinedConfigurations().contains(addresses)); + AdvancedCache cache; - EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion(person, p, MUTABLE_NON_VERSIONED); - assertNotNull(factory.getTypeOverrides().get(person)); - assertTrue(factory.getDefinedConfigurations().contains(person)); - assertNull(factory.getTypeOverrides().get(address)); - cache = region.getCache(); - Configuration cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); - assertEquals(2000, cacheCfg.expiration().wakeUpInterval()); - assertEquals(5000, cacheCfg.eviction().maxEntries()); - assertEquals(60000, cacheCfg.expiration().lifespan()); - assertEquals(30000, cacheCfg.expiration().maxIdle()); - assertFalse(cacheCfg.jmxStatistics().enabled()); + EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion(person, p, MUTABLE_NON_VERSIONED); + assertNotNull(factory.getTypeOverrides().get(person)); + assertTrue(factory.getDefinedConfigurations().contains(person)); + assertNull(factory.getTypeOverrides().get(address)); + cache = region.getCache(); + Configuration cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); + assertEquals(2000, cacheCfg.expiration().wakeUpInterval()); + assertEquals(5000, cacheCfg.eviction().maxEntries()); + assertEquals(60000, cacheCfg.expiration().lifespan()); + assertEquals(30000, cacheCfg.expiration().maxIdle()); + assertFalse(cacheCfg.jmxStatistics().enabled()); - region = (EntityRegionImpl) factory.buildEntityRegion(address, p, MUTABLE_NON_VERSIONED); - assertNotNull(factory.getTypeOverrides().get(person)); - assertTrue(factory.getDefinedConfigurations().contains(person)); - assertNull(factory.getTypeOverrides().get(address)); - cache = region.getCache(); - cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); - assertEquals(3000, cacheCfg.expiration().wakeUpInterval()); - assertEquals(20000, cacheCfg.eviction().maxEntries()); - assertFalse(cacheCfg.jmxStatistics().enabled()); + region = (EntityRegionImpl) factory.buildEntityRegion(address, p, MUTABLE_NON_VERSIONED); + assertNotNull(factory.getTypeOverrides().get(person)); + assertTrue(factory.getDefinedConfigurations().contains(person)); + assertNull(factory.getTypeOverrides().get(address)); + cache = region.getCache(); + cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); + assertEquals(3000, cacheCfg.expiration().wakeUpInterval()); + assertEquals(20000, cacheCfg.eviction().maxEntries()); + assertFalse(cacheCfg.jmxStatistics().enabled()); - region = (EntityRegionImpl) factory.buildEntityRegion(car, p, MUTABLE_NON_VERSIONED); - assertNotNull(factory.getTypeOverrides().get(person)); - assertTrue(factory.getDefinedConfigurations().contains(person)); - assertNull(factory.getTypeOverrides().get(address)); - cache = region.getCache(); - cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); - assertEquals(3000, cacheCfg.expiration().wakeUpInterval()); - assertEquals(20000, cacheCfg.eviction().maxEntries()); - assertFalse(cacheCfg.jmxStatistics().enabled()); + region = (EntityRegionImpl) factory.buildEntityRegion(car, p, MUTABLE_NON_VERSIONED); + assertNotNull(factory.getTypeOverrides().get(person)); + assertTrue(factory.getDefinedConfigurations().contains(person)); + assertNull(factory.getTypeOverrides().get(address)); + cache = region.getCache(); + cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); + assertEquals(3000, cacheCfg.expiration().wakeUpInterval()); + assertEquals(20000, cacheCfg.eviction().maxEntries()); + assertFalse(cacheCfg.jmxStatistics().enabled()); - CollectionRegionImpl collectionRegion = (CollectionRegionImpl) - factory.buildCollectionRegion(addresses, p, MUTABLE_NON_VERSIONED); - assertNotNull(factory.getTypeOverrides().get(addresses)); - assertTrue(factory.getDefinedConfigurations().contains(person)); - assertNull(factory.getTypeOverrides().get(parts)); - cache = collectionRegion .getCache(); - cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); - assertEquals(2500, cacheCfg.expiration().wakeUpInterval()); - assertEquals(5500, cacheCfg.eviction().maxEntries()); - assertEquals(65000, cacheCfg.expiration().lifespan()); - assertEquals(35000, cacheCfg.expiration().maxIdle()); - assertFalse(cacheCfg.jmxStatistics().enabled()); + CollectionRegionImpl collectionRegion = (CollectionRegionImpl) + factory.buildCollectionRegion(addresses, p, MUTABLE_NON_VERSIONED); + assertNotNull(factory.getTypeOverrides().get(addresses)); + assertTrue(factory.getDefinedConfigurations().contains(person)); + assertNull(factory.getTypeOverrides().get(parts)); + cache = collectionRegion .getCache(); + cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); + assertEquals(2500, cacheCfg.expiration().wakeUpInterval()); + assertEquals(5500, cacheCfg.eviction().maxEntries()); + assertEquals(65000, cacheCfg.expiration().lifespan()); + assertEquals(35000, cacheCfg.expiration().maxIdle()); + assertFalse(cacheCfg.jmxStatistics().enabled()); - collectionRegion = (CollectionRegionImpl) factory.buildCollectionRegion(parts, p, MUTABLE_NON_VERSIONED); - assertNotNull(factory.getTypeOverrides().get(addresses)); - assertTrue(factory.getDefinedConfigurations().contains(addresses)); - assertNull(factory.getTypeOverrides().get(parts)); - cache = collectionRegion.getCache(); - cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); - assertEquals(3500, cacheCfg.expiration().wakeUpInterval()); - assertEquals(25000, cacheCfg.eviction().maxEntries()); - assertFalse(cacheCfg.jmxStatistics().enabled()); + collectionRegion = (CollectionRegionImpl) factory.buildCollectionRegion(parts, p, MUTABLE_NON_VERSIONED); + assertNotNull(factory.getTypeOverrides().get(addresses)); + assertTrue(factory.getDefinedConfigurations().contains(addresses)); + assertNull(factory.getTypeOverrides().get(parts)); + cache = collectionRegion.getCache(); + cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); + assertEquals(3500, cacheCfg.expiration().wakeUpInterval()); + assertEquals(25000, cacheCfg.eviction().maxEntries()); + assertFalse(cacheCfg.jmxStatistics().enabled()); - collectionRegion = (CollectionRegionImpl) factory.buildCollectionRegion(parts, p, MUTABLE_NON_VERSIONED); - assertNotNull(factory.getTypeOverrides().get(addresses)); - assertTrue(factory.getDefinedConfigurations().contains(addresses)); - assertNull(factory.getTypeOverrides().get(parts)); - cache = collectionRegion.getCache(); - cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); - assertEquals(3500, cacheCfg.expiration().wakeUpInterval()); - assertEquals(25000, cacheCfg.eviction().maxEntries()); - assertFalse(cacheCfg.jmxStatistics().enabled()); - } finally { - factory.stop(); - } - } + collectionRegion = (CollectionRegionImpl) factory.buildCollectionRegion(parts, p, MUTABLE_NON_VERSIONED); + assertNotNull(factory.getTypeOverrides().get(addresses)); + assertTrue(factory.getDefinedConfigurations().contains(addresses)); + assertNull(factory.getTypeOverrides().get(parts)); + cache = collectionRegion.getCache(); + cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); + assertEquals(3500, cacheCfg.expiration().wakeUpInterval()); + assertEquals(25000, cacheCfg.eviction().maxEntries()); + assertFalse(cacheCfg.jmxStatistics().enabled()); + } finally { + factory.stop(); + } + } - @Test - public void testBuildEntityCollectionRegionOverridesOnly() { - AdvancedCache cache; - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "LIRS"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "30000"); - p.setProperty("hibernate.cache.infinispan.collection.eviction.strategy", "LRU"); - p.setProperty("hibernate.cache.infinispan.collection.eviction.wake_up_interval", "3500"); - p.setProperty("hibernate.cache.infinispan.collection.eviction.max_entries", "35000"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - factory.getCacheManager(); - EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, MUTABLE_NON_VERSIONED); - assertNull(factory.getTypeOverrides().get("com.acme.Address")); - cache = region.getCache(); - Configuration cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); - assertEquals(3000, cacheCfg.expiration().wakeUpInterval()); - assertEquals(30000, cacheCfg.eviction().maxEntries()); - // Max idle value comes from base XML configuration - assertEquals(100000, cacheCfg.expiration().maxIdle()); + @Test + public void testBuildEntityCollectionRegionOverridesOnly() { + AdvancedCache cache; + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "LIRS"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "30000"); + p.setProperty("hibernate.cache.infinispan.collection.eviction.strategy", "LRU"); + p.setProperty("hibernate.cache.infinispan.collection.eviction.wake_up_interval", "3500"); + p.setProperty("hibernate.cache.infinispan.collection.eviction.max_entries", "35000"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + factory.getCacheManager(); + EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, MUTABLE_NON_VERSIONED); + assertNull(factory.getTypeOverrides().get("com.acme.Address")); + cache = region.getCache(); + Configuration cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); + assertEquals(3000, cacheCfg.expiration().wakeUpInterval()); + assertEquals(30000, cacheCfg.eviction().maxEntries()); + // Max idle value comes from base XML configuration + assertEquals(100000, cacheCfg.expiration().maxIdle()); - CollectionRegionImpl collectionRegion = (CollectionRegionImpl) - factory.buildCollectionRegion("com.acme.Person.addresses", p, MUTABLE_NON_VERSIONED); - assertNull(factory.getTypeOverrides().get("com.acme.Person.addresses")); - cache = collectionRegion.getCache(); - cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); - assertEquals(3500, cacheCfg.expiration().wakeUpInterval()); - assertEquals(35000, cacheCfg.eviction().maxEntries()); - assertEquals(100000, cacheCfg.expiration().maxIdle()); - } finally { - factory.stop(); - } - } - @Test - public void testBuildEntityRegionPersonPlusEntityOverridesWithoutCfg() { - final String person = "com.acme.Person"; - Properties p = createProperties(); - // Third option, no cache defined for entity and overrides for generic entity data type and entity itself. - p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); - p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "10000"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - factory.getCacheManager(); - assertNotNull( factory.getTypeOverrides().get( person ) ); - assertFalse( factory.getDefinedConfigurations().contains( person ) ); - EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion( person, p, MUTABLE_NON_VERSIONED ); - assertNotNull(factory.getTypeOverrides().get(person)); - assertTrue( factory.getDefinedConfigurations().contains( person ) ); - AdvancedCache cache = region.getCache(); - Configuration cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); - assertEquals(3000, cacheCfg.expiration().wakeUpInterval()); - assertEquals(10000, cacheCfg.eviction().maxEntries()); - assertEquals(60000, cacheCfg.expiration().lifespan()); - assertEquals(30000, cacheCfg.expiration().maxIdle()); - } finally { - factory.stop(); - } - } + CollectionRegionImpl collectionRegion = (CollectionRegionImpl) + factory.buildCollectionRegion("com.acme.Person.addresses", p, MUTABLE_NON_VERSIONED); + assertNull(factory.getTypeOverrides().get("com.acme.Person.addresses")); + cache = collectionRegion.getCache(); + cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); + assertEquals(3500, cacheCfg.expiration().wakeUpInterval()); + assertEquals(35000, cacheCfg.eviction().maxEntries()); + assertEquals(100000, cacheCfg.expiration().maxIdle()); + } finally { + factory.stop(); + } + } + @Test + public void testBuildEntityRegionPersonPlusEntityOverridesWithoutCfg() { + final String person = "com.acme.Person"; + Properties p = createProperties(); + // Third option, no cache defined for entity and overrides for generic entity data type and entity itself. + p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); + p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "10000"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + factory.getCacheManager(); + assertNotNull( factory.getTypeOverrides().get( person ) ); + assertFalse( factory.getDefinedConfigurations().contains( person ) ); + EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion( person, p, MUTABLE_NON_VERSIONED ); + assertNotNull(factory.getTypeOverrides().get(person)); + assertTrue( factory.getDefinedConfigurations().contains( person ) ); + AdvancedCache cache = region.getCache(); + Configuration cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LRU, cacheCfg.eviction().strategy()); + assertEquals(3000, cacheCfg.expiration().wakeUpInterval()); + assertEquals(10000, cacheCfg.eviction().maxEntries()); + assertEquals(60000, cacheCfg.expiration().lifespan()); + assertEquals(30000, cacheCfg.expiration().maxIdle()); + } finally { + factory.stop(); + } + } - @Test - public void testBuildImmutableEntityRegion() { - AdvancedCache cache; - Properties p = new Properties(); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - factory.getCacheManager(); - EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, IMMUTABLE_NON_VERSIONED); - assertNull( factory.getTypeOverrides().get( "com.acme.Address" ) ); - cache = region.getCache(); - Configuration cacheCfg = cache.getCacheConfiguration(); - assertEquals("Immutable entity should get non-transactional cache", TransactionMode.NON_TRANSACTIONAL, cacheCfg.transaction().transactionMode()); - } finally { - factory.stop(); - } - } + @Test + public void testBuildImmutableEntityRegion() { + AdvancedCache cache; + Properties p = new Properties(); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + factory.getCacheManager(); + EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, IMMUTABLE_NON_VERSIONED); + assertNull( factory.getTypeOverrides().get( "com.acme.Address" ) ); + cache = region.getCache(); + Configuration cacheCfg = cache.getCacheConfiguration(); + assertEquals("Immutable entity should get non-transactional cache", TransactionMode.NON_TRANSACTIONAL, cacheCfg.transaction().transactionMode()); + } finally { + factory.stop(); + } + } - @Test(expected = CacheException.class) - public void testTimestampValidation() { - Properties p = createProperties(); - final DefaultCacheManager manager = new DefaultCacheManager(GlobalConfigurationBuilder.defaultClusteredBuilder().build()); - try { - InfinispanRegionFactory factory = createRegionFactory(manager, p); - ConfigurationBuilder builder = new ConfigurationBuilder(); - builder.clustering().cacheMode(CacheMode.INVALIDATION_SYNC); - manager.defineConfiguration( "timestamps", builder.build() ); - factory.start(null, p); - fail( "Should have failed saying that invalidation is not allowed for timestamp caches." ); - } finally { - TestingUtil.killCacheManagers( manager ); - } - } + @Test(expected = CacheException.class) + public void testTimestampValidation() { + Properties p = createProperties(); + final DefaultCacheManager manager = new DefaultCacheManager(GlobalConfigurationBuilder.defaultClusteredBuilder().build()); + try { + InfinispanRegionFactory factory = createRegionFactory(manager, p); + ConfigurationBuilder builder = new ConfigurationBuilder(); + builder.clustering().cacheMode(CacheMode.INVALIDATION_SYNC); + manager.defineConfiguration( "timestamps", builder.build() ); + factory.start(null, p); + fail( "Should have failed saying that invalidation is not allowed for timestamp caches." ); + } finally { + TestingUtil.killCacheManagers( manager ); + } + } - @Test - public void testBuildDefaultTimestampsRegion() { - final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; - Properties p = createProperties(); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - assertTrue(factory.getDefinedConfigurations().contains("timestamps")); - assertTrue(factory.getTypeOverrides().get("timestamps") - .getCacheName().equals("timestamps")); - TimestampsRegionImpl region = (TimestampsRegionImpl) - factory.buildTimestampsRegion(timestamps, p); - AdvancedCache cache = region.getCache(); - Configuration cacheCfg = cache.getCacheConfiguration(); - assertEquals( EvictionStrategy.NONE, cacheCfg.eviction().strategy() ); - assertEquals( CacheMode.REPL_ASYNC, cacheCfg.clustering().cacheMode() ); - assertFalse( cacheCfg.jmxStatistics().enabled() ); - } finally { - factory.stop(); - } - } + @Test + public void testBuildDefaultTimestampsRegion() { + final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; + Properties p = createProperties(); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + assertTrue(factory.getDefinedConfigurations().contains("timestamps")); + assertTrue(factory.getTypeOverrides().get("timestamps") + .getCacheName().equals("timestamps")); + TimestampsRegionImpl region = (TimestampsRegionImpl) + factory.buildTimestampsRegion(timestamps, p); + AdvancedCache cache = region.getCache(); + Configuration cacheCfg = cache.getCacheConfiguration(); + assertEquals( EvictionStrategy.NONE, cacheCfg.eviction().strategy() ); + assertEquals( CacheMode.REPL_ASYNC, cacheCfg.clustering().cacheMode() ); + assertFalse( cacheCfg.jmxStatistics().enabled() ); + } finally { + factory.stop(); + } + } - @Test - public void testBuildDiffCacheNameTimestampsRegion() { - final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "unrecommended-timestamps"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - EmbeddedCacheManager manager = factory.getCacheManager(); - assertFalse(factory.getDefinedConfigurations().contains("timestamp")); - assertTrue(factory.getDefinedConfigurations().contains("unrecommended-timestamps")); - assertTrue(factory.getTypeOverrides().get("timestamps").getCacheName().equals("unrecommended-timestamps")); - ConfigurationBuilder builder = new ConfigurationBuilder(); - builder.clustering().stateTransfer().fetchInMemoryState(true); - builder.clustering().cacheMode( CacheMode.REPL_SYNC ); - manager.defineConfiguration( "unrecommended-timestamps", builder.build() ); - TimestampsRegionImpl region = (TimestampsRegionImpl) factory.buildTimestampsRegion(timestamps, p); - AdvancedCache cache = region.getCache(); - Configuration cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.NONE, cacheCfg.eviction().strategy()); - assertEquals(CacheMode.REPL_SYNC, cacheCfg.clustering().cacheMode()); - assertFalse( cacheCfg.storeAsBinary().enabled() ); - assertFalse(cacheCfg.jmxStatistics().enabled()); - } finally { - factory.stop(); - } - } + @Test + public void testBuildDiffCacheNameTimestampsRegion() { + final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "unrecommended-timestamps"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + EmbeddedCacheManager manager = factory.getCacheManager(); + assertFalse(factory.getDefinedConfigurations().contains("timestamp")); + assertTrue(factory.getDefinedConfigurations().contains("unrecommended-timestamps")); + assertTrue(factory.getTypeOverrides().get("timestamps").getCacheName().equals("unrecommended-timestamps")); + ConfigurationBuilder builder = new ConfigurationBuilder(); + builder.clustering().stateTransfer().fetchInMemoryState(true); + builder.clustering().cacheMode( CacheMode.REPL_SYNC ); + manager.defineConfiguration( "unrecommended-timestamps", builder.build() ); + TimestampsRegionImpl region = (TimestampsRegionImpl) factory.buildTimestampsRegion(timestamps, p); + AdvancedCache cache = region.getCache(); + Configuration cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.NONE, cacheCfg.eviction().strategy()); + assertEquals(CacheMode.REPL_SYNC, cacheCfg.clustering().cacheMode()); + assertFalse( cacheCfg.storeAsBinary().enabled() ); + assertFalse(cacheCfg.jmxStatistics().enabled()); + } finally { + factory.stop(); + } + } - @Test - public void testBuildTimestamRegionWithCacheNameOverride() { - final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "mytimestamps-cache"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - factory.buildTimestampsRegion(timestamps, p); - assertTrue(factory.getDefinedConfigurations().contains("mytimestamps-cache")); - } finally { - factory.stop(); - } - } + @Test + public void testBuildTimestamRegionWithCacheNameOverride() { + final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "mytimestamps-cache"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + factory.buildTimestampsRegion(timestamps, p); + assertTrue(factory.getDefinedConfigurations().contains("mytimestamps-cache")); + } finally { + factory.stop(); + } + } - @Test - public void testBuildTimestamRegionWithFifoEvictionOverride() { - final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "mytimestamps-cache"); - p.setProperty("hibernate.cache.infinispan.timestamps.eviction.strategy", "FIFO"); - p.setProperty("hibernate.cache.infinispan.timestamps.eviction.wake_up_interval", "3000"); - p.setProperty("hibernate.cache.infinispan.timestamps.eviction.max_entries", "10000"); - InfinispanRegionFactory factory = null; - try { - factory = createRegionFactory(p); - factory.buildTimestampsRegion(timestamps, p); - assertTrue( factory.getDefinedConfigurations().contains( "mytimestamps-cache" ) ); - fail( "Should fail cos no eviction configurations are allowed for timestamp caches" ); - } catch(CacheException ce) { - } finally { - if (factory != null) factory.stop(); - } - } + @Test + public void testBuildTimestamRegionWithFifoEvictionOverride() { + final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "mytimestamps-cache"); + p.setProperty("hibernate.cache.infinispan.timestamps.eviction.strategy", "FIFO"); + p.setProperty("hibernate.cache.infinispan.timestamps.eviction.wake_up_interval", "3000"); + p.setProperty("hibernate.cache.infinispan.timestamps.eviction.max_entries", "10000"); + InfinispanRegionFactory factory = null; + try { + factory = createRegionFactory(p); + factory.buildTimestampsRegion(timestamps, p); + assertTrue( factory.getDefinedConfigurations().contains( "mytimestamps-cache" ) ); + fail( "Should fail cos no eviction configurations are allowed for timestamp caches" ); + } catch(CacheException ce) { + } finally { + if (factory != null) factory.stop(); + } + } - @Test - public void testBuildTimestamRegionWithNoneEvictionOverride() { - final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "timestamps-none-eviction"); - p.setProperty("hibernate.cache.infinispan.timestamps.eviction.strategy", "NONE"); - p.setProperty("hibernate.cache.infinispan.timestamps.eviction.wake_up_interval", "3000"); - p.setProperty("hibernate.cache.infinispan.timestamps.eviction.max_entries", "0"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - factory.buildTimestampsRegion( timestamps, p ); - assertTrue( factory.getDefinedConfigurations().contains( "timestamps-none-eviction" ) ); - } finally { - factory.stop(); - } - } + @Test + public void testBuildTimestamRegionWithNoneEvictionOverride() { + final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "timestamps-none-eviction"); + p.setProperty("hibernate.cache.infinispan.timestamps.eviction.strategy", "NONE"); + p.setProperty("hibernate.cache.infinispan.timestamps.eviction.wake_up_interval", "3000"); + p.setProperty("hibernate.cache.infinispan.timestamps.eviction.max_entries", "0"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + factory.buildTimestampsRegion( timestamps, p ); + assertTrue( factory.getDefinedConfigurations().contains( "timestamps-none-eviction" ) ); + } finally { + factory.stop(); + } + } - @Test - public void testBuildQueryRegion() { - final String query = "org.hibernate.cache.internal.StandardQueryCache"; - Properties p = createProperties(); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - assertTrue(factory.getDefinedConfigurations().contains("local-query")); - QueryResultsRegionImpl region = (QueryResultsRegionImpl) factory.buildQueryResultsRegion(query, p); - AdvancedCache cache = region.getCache(); - Configuration cacheCfg = cache.getCacheConfiguration(); - assertEquals( CacheMode.LOCAL, cacheCfg.clustering().cacheMode() ); - assertFalse( cacheCfg.jmxStatistics().enabled() ); - } finally { - factory.stop(); - } - } + @Test + public void testBuildQueryRegion() { + final String query = "org.hibernate.cache.internal.StandardQueryCache"; + Properties p = createProperties(); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + assertTrue(factory.getDefinedConfigurations().contains("local-query")); + QueryResultsRegionImpl region = (QueryResultsRegionImpl) factory.buildQueryResultsRegion(query, p); + AdvancedCache cache = region.getCache(); + Configuration cacheCfg = cache.getCacheConfiguration(); + assertEquals( CacheMode.LOCAL, cacheCfg.clustering().cacheMode() ); + assertFalse( cacheCfg.jmxStatistics().enabled() ); + } finally { + factory.stop(); + } + } - @Test - public void testBuildQueryRegionWithCustomRegionName() { - final String queryRegionName = "myquery"; - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.myquery.cfg", "timestamps-none-eviction"); - p.setProperty("hibernate.cache.infinispan.myquery.eviction.strategy", "LIRS"); - p.setProperty("hibernate.cache.infinispan.myquery.eviction.wake_up_interval", "2222"); - p.setProperty("hibernate.cache.infinispan.myquery.eviction.max_entries", "11111"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - assertTrue(factory.getDefinedConfigurations().contains("local-query")); - QueryResultsRegionImpl region = (QueryResultsRegionImpl) factory.buildQueryResultsRegion(queryRegionName, p); - assertNotNull(factory.getTypeOverrides().get(queryRegionName)); - assertTrue(factory.getDefinedConfigurations().contains(queryRegionName)); - AdvancedCache cache = region.getCache(); - Configuration cacheCfg = cache.getCacheConfiguration(); - assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); - assertEquals(2222, cacheCfg.expiration().wakeUpInterval()); - assertEquals( 11111, cacheCfg.eviction().maxEntries() ); - } finally { - factory.stop(); - } - } - @Test - public void testEnableStatistics() { - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.statistics", "true"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); - p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "10000"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - EmbeddedCacheManager manager = factory.getCacheManager(); - assertTrue(manager.getCacheManagerConfiguration().globalJmxStatistics().enabled()); - EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, MUTABLE_NON_VERSIONED); - AdvancedCache cache = region.getCache(); - assertTrue(factory.getTypeOverrides().get("entity").isExposeStatistics()); - assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); + @Test + public void testBuildQueryRegionWithCustomRegionName() { + final String queryRegionName = "myquery"; + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.myquery.cfg", "timestamps-none-eviction"); + p.setProperty("hibernate.cache.infinispan.myquery.eviction.strategy", "LIRS"); + p.setProperty("hibernate.cache.infinispan.myquery.eviction.wake_up_interval", "2222"); + p.setProperty("hibernate.cache.infinispan.myquery.eviction.max_entries", "11111"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + assertTrue(factory.getDefinedConfigurations().contains("local-query")); + QueryResultsRegionImpl region = (QueryResultsRegionImpl) factory.buildQueryResultsRegion(queryRegionName, p); + assertNotNull(factory.getTypeOverrides().get(queryRegionName)); + assertTrue(factory.getDefinedConfigurations().contains(queryRegionName)); + AdvancedCache cache = region.getCache(); + Configuration cacheCfg = cache.getCacheConfiguration(); + assertEquals(EvictionStrategy.LIRS, cacheCfg.eviction().strategy()); + assertEquals(2222, cacheCfg.expiration().wakeUpInterval()); + assertEquals( 11111, cacheCfg.eviction().maxEntries() ); + } finally { + factory.stop(); + } + } + @Test + public void testEnableStatistics() { + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.statistics", "true"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); + p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "10000"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + EmbeddedCacheManager manager = factory.getCacheManager(); + assertTrue(manager.getCacheManagerConfiguration().globalJmxStatistics().enabled()); + EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, MUTABLE_NON_VERSIONED); + AdvancedCache cache = region.getCache(); + assertTrue(factory.getTypeOverrides().get("entity").isExposeStatistics()); + assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); - region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Person", p, MUTABLE_NON_VERSIONED); - cache = region.getCache(); - assertTrue(factory.getTypeOverrides().get("com.acme.Person").isExposeStatistics()); - assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); + region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Person", p, MUTABLE_NON_VERSIONED); + cache = region.getCache(); + assertTrue(factory.getTypeOverrides().get("com.acme.Person").isExposeStatistics()); + assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); - final String query = "org.hibernate.cache.internal.StandardQueryCache"; - QueryResultsRegionImpl queryRegion = (QueryResultsRegionImpl) - factory.buildQueryResultsRegion(query, p); - cache = queryRegion.getCache(); - assertTrue(factory.getTypeOverrides().get("query").isExposeStatistics()); - assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); + final String query = "org.hibernate.cache.internal.StandardQueryCache"; + QueryResultsRegionImpl queryRegion = (QueryResultsRegionImpl) + factory.buildQueryResultsRegion(query, p); + cache = queryRegion.getCache(); + assertTrue(factory.getTypeOverrides().get("query").isExposeStatistics()); + assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); - final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; - ConfigurationBuilder builder = new ConfigurationBuilder(); - builder.clustering().stateTransfer().fetchInMemoryState(true); - manager.defineConfiguration("timestamps", builder.build()); - TimestampsRegionImpl timestampsRegion = (TimestampsRegionImpl) - factory.buildTimestampsRegion(timestamps, p); - cache = timestampsRegion.getCache(); - assertTrue(factory.getTypeOverrides().get("timestamps").isExposeStatistics()); - assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); + final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; + ConfigurationBuilder builder = new ConfigurationBuilder(); + builder.clustering().stateTransfer().fetchInMemoryState(true); + manager.defineConfiguration("timestamps", builder.build()); + TimestampsRegionImpl timestampsRegion = (TimestampsRegionImpl) + factory.buildTimestampsRegion(timestamps, p); + cache = timestampsRegion.getCache(); + assertTrue(factory.getTypeOverrides().get("timestamps").isExposeStatistics()); + assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); - CollectionRegionImpl collectionRegion = (CollectionRegionImpl) - factory.buildCollectionRegion("com.acme.Person.addresses", p, MUTABLE_NON_VERSIONED); - cache = collectionRegion.getCache(); - assertTrue(factory.getTypeOverrides().get("collection").isExposeStatistics()); - assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); - } finally { - factory.stop(); - } - } + CollectionRegionImpl collectionRegion = (CollectionRegionImpl) + factory.buildCollectionRegion("com.acme.Person.addresses", p, MUTABLE_NON_VERSIONED); + cache = collectionRegion.getCache(); + assertTrue(factory.getTypeOverrides().get("collection").isExposeStatistics()); + assertTrue(cache.getCacheConfiguration().jmxStatistics().enabled()); + } finally { + factory.stop(); + } + } - @Test - public void testDisableStatistics() { - Properties p = createProperties(); - p.setProperty("hibernate.cache.infinispan.statistics", "false"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); - p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); - p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); - p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "10000"); - InfinispanRegionFactory factory = createRegionFactory(p); - try { - EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, MUTABLE_NON_VERSIONED); - AdvancedCache cache = region.getCache(); - assertFalse( factory.getTypeOverrides().get( "entity" ).isExposeStatistics() ); - assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); + @Test + public void testDisableStatistics() { + Properties p = createProperties(); + p.setProperty("hibernate.cache.infinispan.statistics", "false"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.lifespan", "60000"); + p.setProperty("hibernate.cache.infinispan.com.acme.Person.expiration.max_idle", "30000"); + p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000"); + p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "10000"); + InfinispanRegionFactory factory = createRegionFactory(p); + try { + EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, MUTABLE_NON_VERSIONED); + AdvancedCache cache = region.getCache(); + assertFalse( factory.getTypeOverrides().get( "entity" ).isExposeStatistics() ); + assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); - region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Person", p, MUTABLE_NON_VERSIONED); - cache = region.getCache(); - assertFalse( factory.getTypeOverrides().get( "com.acme.Person" ).isExposeStatistics() ); - assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); + region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Person", p, MUTABLE_NON_VERSIONED); + cache = region.getCache(); + assertFalse( factory.getTypeOverrides().get( "com.acme.Person" ).isExposeStatistics() ); + assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); - final String query = "org.hibernate.cache.internal.StandardQueryCache"; - QueryResultsRegionImpl queryRegion = (QueryResultsRegionImpl) factory.buildQueryResultsRegion(query, p); - cache = queryRegion.getCache(); - assertFalse( factory.getTypeOverrides().get( "query" ).isExposeStatistics() ); - assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); + final String query = "org.hibernate.cache.internal.StandardQueryCache"; + QueryResultsRegionImpl queryRegion = (QueryResultsRegionImpl) factory.buildQueryResultsRegion(query, p); + cache = queryRegion.getCache(); + assertFalse( factory.getTypeOverrides().get( "query" ).isExposeStatistics() ); + assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); - final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; - ConfigurationBuilder builder = new ConfigurationBuilder(); - builder.clustering().stateTransfer().fetchInMemoryState(true); - factory.getCacheManager().defineConfiguration( "timestamps", builder.build() ); - TimestampsRegionImpl timestampsRegion = (TimestampsRegionImpl) - factory.buildTimestampsRegion(timestamps, p); - cache = timestampsRegion.getCache(); - assertFalse( factory.getTypeOverrides().get( "timestamps" ).isExposeStatistics() ); - assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); + final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache"; + ConfigurationBuilder builder = new ConfigurationBuilder(); + builder.clustering().stateTransfer().fetchInMemoryState(true); + factory.getCacheManager().defineConfiguration( "timestamps", builder.build() ); + TimestampsRegionImpl timestampsRegion = (TimestampsRegionImpl) + factory.buildTimestampsRegion(timestamps, p); + cache = timestampsRegion.getCache(); + assertFalse( factory.getTypeOverrides().get( "timestamps" ).isExposeStatistics() ); + assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); - CollectionRegionImpl collectionRegion = (CollectionRegionImpl) - factory.buildCollectionRegion("com.acme.Person.addresses", p, MUTABLE_NON_VERSIONED); - cache = collectionRegion.getCache(); - assertFalse( factory.getTypeOverrides().get( "collection" ).isExposeStatistics() ); - assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); - } finally { - factory.stop(); - } - } + CollectionRegionImpl collectionRegion = (CollectionRegionImpl) + factory.buildCollectionRegion("com.acme.Person.addresses", p, MUTABLE_NON_VERSIONED); + cache = collectionRegion.getCache(); + assertFalse( factory.getTypeOverrides().get( "collection" ).isExposeStatistics() ); + assertFalse( cache.getCacheConfiguration().jmxStatistics().enabled() ); + } finally { + factory.stop(); + } + } - private InfinispanRegionFactory createRegionFactory(Properties p) { - return createRegionFactory(null, p); - } + private InfinispanRegionFactory createRegionFactory(Properties p) { + return createRegionFactory(null, p); + } - private InfinispanRegionFactory createRegionFactory(final EmbeddedCacheManager manager, Properties p) { - final InfinispanRegionFactory factory = new SingleNodeTestCase.TestInfinispanRegionFactory() { + private InfinispanRegionFactory createRegionFactory(final EmbeddedCacheManager manager, Properties p) { + final InfinispanRegionFactory factory = new TestInfinispanRegionFactory() { - @Override - protected org.infinispan.transaction.lookup.TransactionManagerLookup createTransactionManagerLookup(SessionFactoryOptions settings, Properties properties) { - return new HibernateTransactionManagerLookup(null, null) { - @Override - public TransactionManager getTransactionManager() throws Exception { - AbstractJtaPlatform jta = new JBossStandAloneJtaPlatform(); - jta.injectServices(ServiceRegistryBuilder.buildServiceRegistry()); - return jta.getTransactionManager(); - } - }; - } + @Override + protected org.infinispan.transaction.lookup.TransactionManagerLookup createTransactionManagerLookup(SessionFactoryOptions settings, Properties properties) { + return new HibernateTransactionManagerLookup(null, null) { + @Override + public TransactionManager getTransactionManager() throws Exception { + AbstractJtaPlatform jta = new JBossStandAloneJtaPlatform(); + jta.injectServices(ServiceRegistryBuilder.buildServiceRegistry()); + return jta.getTransactionManager(); + } + }; + } - @Override - protected EmbeddedCacheManager createCacheManager(Properties properties, ServiceRegistry serviceRegistry) throws CacheException { - if (manager != null) - return manager; - else - return super.createCacheManager( properties, serviceRegistry); - } + @Override + protected EmbeddedCacheManager createCacheManager(Properties properties, ServiceRegistry serviceRegistry) throws CacheException { + if (manager != null) + return manager; + else + return super.createCacheManager( properties, serviceRegistry); + } - }; + }; - factory.start( sfOptionsForStart(), p ); - return factory; - } + factory.start( sfOptionsForStart(), p ); + return factory; + } - private SessionFactoryOptions sfOptionsForStart() { - return new SessionFactoryOptionsImpl( - new SessionFactoryBuilderImpl.SessionFactoryOptionsStateStandardImpl( - ServiceRegistryTestingImpl.forUnitTesting() - ) - ); - } + private SessionFactoryOptions sfOptionsForStart() { + return new SessionFactoryOptionsImpl( + new SessionFactoryBuilderImpl.SessionFactoryOptionsStateStandardImpl( + ServiceRegistryTestingImpl.forUnitTesting() + ) + ); + } - private static Properties createProperties() { - final Properties properties = new Properties(); - // If configured in the environment, add configuration file name to properties. - final String cfgFileName = - (String) Environment.getProperties().get( InfinispanRegionFactory.INFINISPAN_CONFIG_RESOURCE_PROP ); - if ( cfgFileName != null ) { - properties.put( InfinispanRegionFactory.INFINISPAN_CONFIG_RESOURCE_PROP, cfgFileName ); - } - return properties; - } + private static Properties createProperties() { + final Properties properties = new Properties(); + // If configured in the environment, add configuration file name to properties. + final String cfgFileName = + (String) Environment.getProperties().get( InfinispanRegionFactory.INFINISPAN_CONFIG_RESOURCE_PROP ); + if ( cfgFileName != null ) { + properties.put( InfinispanRegionFactory.INFINISPAN_CONFIG_RESOURCE_PROP, cfgFileName ); + } + return properties; + } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTest.java new file mode 100644 index 0000000000..21f65fae26 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTest.java @@ -0,0 +1,565 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.access; + +import javax.transaction.TransactionManager; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import org.hibernate.cache.infinispan.InfinispanRegionFactory; +import org.hibernate.cache.infinispan.access.PutFromLoadValidator; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl; +import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; +import org.hibernate.testing.TestForIssue; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.manager.EmbeddedCacheManager; +import org.infinispan.test.CacheManagerCallable; +import org.infinispan.test.fwk.TestCacheManagerFactory; +import org.infinispan.util.logging.Log; +import org.infinispan.util.logging.LogFactory; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import static org.infinispan.test.TestingUtil.withCacheManager; +import static org.infinispan.test.TestingUtil.withTx; +import static org.mockito.Mockito.mock; +import static org.junit.Assert.*; + +/** + * Tests of {@link PutFromLoadValidator}. + * + * @author Brian Stansberry + * @author Galder Zamarreño + * @version $Revision: $ + */ +public class PutFromLoadValidatorUnitTest { + + private static final Log log = LogFactory.getLog( + PutFromLoadValidatorUnitTest.class); + + @Rule + public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + + private Object KEY1 = "KEY1"; + + private TransactionManager tm; + + @Before + public void setUp() throws Exception { + tm = DualNodeJtaTransactionManagerImpl.getInstance("test"); + } + + @After + public void tearDown() throws Exception { + tm = null; + try { + DualNodeJtaTransactionManagerImpl.cleanupTransactions(); + } + finally { + DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers(); + } + } + + private static EmbeddedCacheManager createCacheManager() { + EmbeddedCacheManager cacheManager = TestCacheManagerFactory.createCacheManager(false); + cacheManager.defineConfiguration(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME, + InfinispanRegionFactory.PENDING_PUTS_CACHE_CONFIGURATION); + return cacheManager; + } + + @Test + public void testNakedPut() throws Exception { + nakedPutTest(false); + } + @Test + public void testNakedPutTransactional() throws Exception { + nakedPutTest(true); + } + + private void nakedPutTest(final boolean transactional) throws Exception { + withCacheManager(new CacheManagerCallable(createCacheManager()) { + @Override + public void call() { + PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); + exec(transactional, new NakedPut(testee, true)); + } + }); + } + + @Test + public void testRegisteredPut() throws Exception { + registeredPutTest(false); + } + @Test + public void testRegisteredPutTransactional() throws Exception { + registeredPutTest(true); + } + + private void registeredPutTest(final boolean transactional) throws Exception { + withCacheManager(new CacheManagerCallable(createCacheManager()) { + @Override + public void call() { + PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); + exec(transactional, new RegularPut(testee)); + } + }); + } + + @Test + public void testNakedPutAfterKeyRemoval() throws Exception { + nakedPutAfterRemovalTest(false, false); + } + @Test + public void testNakedPutAfterKeyRemovalTransactional() throws Exception { + nakedPutAfterRemovalTest(true, false); + } + @Test + public void testNakedPutAfterRegionRemoval() throws Exception { + nakedPutAfterRemovalTest(false, true); + } + @Test + public void testNakedPutAfterRegionRemovalTransactional() throws Exception { + nakedPutAfterRemovalTest(true, true); + } + + private void nakedPutAfterRemovalTest(final boolean transactional, + final boolean removeRegion) throws Exception { + withCacheManager(new CacheManagerCallable(createCacheManager()) { + @Override + public void call() { + PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache()); + Invalidation invalidation = new Invalidation(testee, removeRegion); + // the naked put can succeed because it has txTimestamp after invalidation + NakedPut nakedPut = new NakedPut(testee, true); + exec(transactional, invalidation, nakedPut); + } + }); + + } + + @Test + public void testRegisteredPutAfterKeyRemoval() throws Exception { + registeredPutAfterRemovalTest(false, false); + } + @Test + public void testRegisteredPutAfterKeyRemovalTransactional() throws Exception { + registeredPutAfterRemovalTest(true, false); + } + @Test + public void testRegisteredPutAfterRegionRemoval() throws Exception { + registeredPutAfterRemovalTest(false, true); + } + @Test + public void testRegisteredPutAfterRegionRemovalTransactional() throws Exception { + registeredPutAfterRemovalTest(true, true); + } + + private void registeredPutAfterRemovalTest(final boolean transactional, + final boolean removeRegion) throws Exception { + withCacheManager(new CacheManagerCallable(createCacheManager()) { + @Override + public void call() { + PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); + Invalidation invalidation = new Invalidation(testee, removeRegion); + RegularPut regularPut = new RegularPut(testee); + exec(transactional, invalidation, regularPut); + } + }); + + } + @Test + public void testRegisteredPutWithInterveningKeyRemoval() throws Exception { + registeredPutWithInterveningRemovalTest(false, false); + } + @Test + public void testRegisteredPutWithInterveningKeyRemovalTransactional() throws Exception { + registeredPutWithInterveningRemovalTest(true, false); + } + @Test + public void testRegisteredPutWithInterveningRegionRemoval() throws Exception { + registeredPutWithInterveningRemovalTest(false, true); + } + @Test + public void testRegisteredPutWithInterveningRegionRemovalTransactional() throws Exception { + registeredPutWithInterveningRemovalTest(true, true); + } + + private void registeredPutWithInterveningRemovalTest( + final boolean transactional, final boolean removeRegion) + throws Exception { + withCacheManager(new CacheManagerCallable(createCacheManager()) { + @Override + public void call() { + PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); + try { + long txTimestamp = System.currentTimeMillis(); + if (transactional) { + tm.begin(); + } + SessionImplementor session1 = mock(SessionImplementor.class); + SessionImplementor session2 = mock(SessionImplementor.class); + testee.registerPendingPut(session1, KEY1, txTimestamp); + if (removeRegion) { + testee.beginInvalidatingRegion(); + } else { + testee.beginInvalidatingKey(session2, KEY1); + } + + PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session1, KEY1, txTimestamp); + try { + assertNull(lock); + } + finally { + if (lock != null) { + testee.releasePutFromLoadLock(KEY1, lock); + } + if (removeRegion) { + testee.endInvalidatingRegion(); + } else { + testee.endInvalidatingKey(session2, KEY1); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + @Test + public void testMultipleRegistrations() throws Exception { + multipleRegistrationtest(false); + } + + @Test + public void testMultipleRegistrationsTransactional() throws Exception { + multipleRegistrationtest(true); + } + + private void multipleRegistrationtest(final boolean transactional) throws Exception { + withCacheManager(new CacheManagerCallable(createCacheManager()) { + @Override + public void call() { + final PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); + + final CountDownLatch registeredLatch = new CountDownLatch(3); + final CountDownLatch finishedLatch = new CountDownLatch(3); + final AtomicInteger success = new AtomicInteger(); + + Runnable r = new Runnable() { + public void run() { + try { + long txTimestamp = System.currentTimeMillis(); + if (transactional) { + tm.begin(); + } + SessionImplementor session = mock (SessionImplementor.class); + testee.registerPendingPut(session, KEY1, txTimestamp); + registeredLatch.countDown(); + registeredLatch.await(5, TimeUnit.SECONDS); + PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp); + if (lock != null) { + try { + log.trace("Put from load lock acquired for key = " + KEY1); + success.incrementAndGet(); + } finally { + testee.releasePutFromLoadLock(KEY1, lock); + } + } else { + log.trace("Unable to acquired putFromLoad lock for key = " + KEY1); + } + finishedLatch.countDown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + + ExecutorService executor = Executors.newFixedThreadPool(3); + + // Start with a removal so the "isPutValid" calls will fail if + // any of the concurrent activity isn't handled properly + + testee.beginInvalidatingRegion(); + testee.endInvalidatingRegion(); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + // Do the registration + isPutValid calls + executor.execute(r); + executor.execute(r); + executor.execute(r); + + try { + finishedLatch.await(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + assertEquals("All threads succeeded", 3, success.get()); + } + }); + } + + @Test + public void testInvalidateKeyBlocksForInProgressPut() throws Exception { + invalidationBlocksForInProgressPutTest(true); + } + + @Test + public void testInvalidateRegionBlocksForInProgressPut() throws Exception { + invalidationBlocksForInProgressPutTest(false); + } + + private void invalidationBlocksForInProgressPutTest(final boolean keyOnly) throws Exception { + withCacheManager(new CacheManagerCallable(createCacheManager()) { + @Override + public void call() { + final PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); + final CountDownLatch removeLatch = new CountDownLatch(1); + final CountDownLatch pferLatch = new CountDownLatch(1); + final AtomicReference cache = new AtomicReference("INITIAL"); + + Callable pferCallable = new Callable() { + public Boolean call() throws Exception { + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mock (SessionImplementor.class); + testee.registerPendingPut(session, KEY1, txTimestamp); + PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp); + if (lock != null) { + try { + removeLatch.countDown(); + pferLatch.await(); + cache.set("PFER"); + return Boolean.TRUE; + } + finally { + testee.releasePutFromLoadLock(KEY1, lock); + } + } + return Boolean.FALSE; + } + }; + + Callable invalidateCallable = new Callable() { + public Void call() throws Exception { + removeLatch.await(); + if (keyOnly) { + SessionImplementor session = mock (SessionImplementor.class); + testee.beginInvalidatingKey(session, KEY1); + } else { + testee.beginInvalidatingRegion(); + } + cache.set(null); + return null; + } + }; + + ExecutorService executorService = Executors.newCachedThreadPool(); + Future pferFuture = executorService.submit(pferCallable); + Future invalidateFuture = executorService.submit(invalidateCallable); + + try { + try { + invalidateFuture.get(1, TimeUnit.SECONDS); + fail("invalidateFuture did not block"); + } + catch (TimeoutException good) {} + + pferLatch.countDown(); + + assertTrue(pferFuture.get(5, TimeUnit.SECONDS)); + invalidateFuture.get(5, TimeUnit.SECONDS); + + assertNull(cache.get()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + } + + protected void exec(boolean transactional, Callable... callables) { + try { + if (transactional) { + for (Callable c : callables) { + withTx(tm, c); + } + } else { + for (Callable c : callables) { + c.call(); + } + } + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private class Invalidation implements Callable { + private PutFromLoadValidator putFromLoadValidator; + private boolean removeRegion; + + public Invalidation(PutFromLoadValidator putFromLoadValidator, boolean removeRegion) { + this.putFromLoadValidator = putFromLoadValidator; + this.removeRegion = removeRegion; + } + + @Override + public Void call() throws Exception { + if (removeRegion) { + boolean success = putFromLoadValidator.beginInvalidatingRegion(); + assertTrue(success); + putFromLoadValidator.endInvalidatingRegion();; + } else { + SessionImplementor session = mock (SessionImplementor.class); + boolean success = putFromLoadValidator.beginInvalidatingKey(session, KEY1); + assertTrue(success); + success = putFromLoadValidator.endInvalidatingKey(session, KEY1); + assertTrue(success); + } + // if we go for the timestamp-based approach, invalidation in the same millisecond + // as the registerPendingPut/acquirePutFromLoad lock results in failure. + Thread.sleep(10); + return null; + } + } + + private class RegularPut implements Callable { + private PutFromLoadValidator putFromLoadValidator; + + public RegularPut(PutFromLoadValidator putFromLoadValidator) { + this.putFromLoadValidator = putFromLoadValidator; + } + + @Override + public Void call() throws Exception { + try { + long txTimestamp = System.currentTimeMillis(); // this should be acquired before UserTransaction.begin() + SessionImplementor session = mock (SessionImplementor.class); + putFromLoadValidator.registerPendingPut(session, KEY1, txTimestamp); + + PutFromLoadValidator.Lock lock = putFromLoadValidator.acquirePutFromLoadLock(session, KEY1, txTimestamp); + try { + assertNotNull(lock); + } finally { + if (lock != null) { + putFromLoadValidator.releasePutFromLoadLock(KEY1, lock); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + } + } + + private class NakedPut implements Callable { + private final PutFromLoadValidator testee; + private final boolean expectSuccess; + + public NakedPut(PutFromLoadValidator testee, boolean expectSuccess) { + this.testee = testee; + this.expectSuccess = expectSuccess; + } + + @Override + public Void call() throws Exception { + try { + long txTimestamp = System.currentTimeMillis(); // this should be acquired before UserTransaction.begin() + SessionImplementor session = mock (SessionImplementor.class); + PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp); + try { + if (expectSuccess) { + assertNotNull(lock); + } else { + assertNull(lock); + } + } + finally { + if (lock != null) { + testee.releasePutFromLoadLock(KEY1, lock); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return null; + } + } + + @Test + @TestForIssue(jiraKey = "HHH-9928") + public void testGetForNullReleasePuts() { + EmbeddedCacheManager cm = TestCacheManagerFactory.createCacheManager(false); + ConfigurationBuilder cb = new ConfigurationBuilder().read(InfinispanRegionFactory.PENDING_PUTS_CACHE_CONFIGURATION); + cb.expiration().maxIdle(500); + cm.defineConfiguration(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME, cb.build()); + withCacheManager(new CacheManagerCallable(cm) { + @Override + public void call() { + PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); + long lastInsert = Long.MAX_VALUE; + for (int i = 0; i < 100; ++i) { + lastInsert = System.currentTimeMillis(); + try { + withTx(tm, new Callable() { + @Override + public Object call() throws Exception { + SessionImplementor session = mock (SessionImplementor.class); + testee.registerPendingPut(session, KEY1, 0); + return null; + } + }); + Thread.sleep(10); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + String ppName = cm.getCache().getName() + "-" + InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME; + Map ppCache = cm.getCache(ppName, false); + assertNotNull(ppCache); + Object pendingPutMap = ppCache.get(KEY1); + long end = System.currentTimeMillis(); + if (end - lastInsert > 500) { + log.warn("Test took too long"); + return; + } + assertNotNull(pendingPutMap); + int size; + try { + Method sizeMethod = pendingPutMap.getClass().getMethod("size"); + sizeMethod.setAccessible(true); + size = (Integer) sizeMethod.invoke(pendingPutMap); + } catch (Exception e) { + throw new RuntimeException(e); + } + // some of the pending puts need to be expired by now + assertTrue(size < 100); + // but some are still registered + assertTrue(size > 0); + } + }); + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTestCase.java deleted file mode 100644 index b38ffb88e8..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTestCase.java +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.access; - -import javax.transaction.TransactionManager; - -import java.lang.reflect.Method; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.infinispan.access.PutFromLoadValidator; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl; -import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.hibernate.testing.TestForIssue; -import org.infinispan.configuration.cache.ConfigurationBuilder; -import org.infinispan.manager.EmbeddedCacheManager; -import org.infinispan.test.CacheManagerCallable; -import org.infinispan.test.fwk.TestCacheManagerFactory; -import org.infinispan.util.logging.Log; -import org.infinispan.util.logging.LogFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import static org.infinispan.test.TestingUtil.withCacheManager; -import static org.infinispan.test.TestingUtil.withTx; -import static org.mockito.Mockito.mock; -import static org.junit.Assert.*; - -/** - * Tests of {@link PutFromLoadValidator}. - * - * @author Brian Stansberry - * @author Galder Zamarreño - * @version $Revision: $ - */ -public class PutFromLoadValidatorUnitTestCase { - - private static final Log log = LogFactory.getLog( - PutFromLoadValidatorUnitTestCase.class); - - @Rule - public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - - private Object KEY1 = "KEY1"; - - private TransactionManager tm; - - @Before - public void setUp() throws Exception { - tm = DualNodeJtaTransactionManagerImpl.getInstance("test"); - } - - @After - public void tearDown() throws Exception { - tm = null; - try { - DualNodeJtaTransactionManagerImpl.cleanupTransactions(); - } - finally { - DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers(); - } - } - - private static EmbeddedCacheManager createCacheManager() { - EmbeddedCacheManager cacheManager = TestCacheManagerFactory.createCacheManager(false); - cacheManager.defineConfiguration(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME, - InfinispanRegionFactory.PENDING_PUTS_CACHE_CONFIGURATION); - return cacheManager; - } - - @Test - public void testNakedPut() throws Exception { - nakedPutTest(false); - } - @Test - public void testNakedPutTransactional() throws Exception { - nakedPutTest(true); - } - - private void nakedPutTest(final boolean transactional) throws Exception { - withCacheManager(new CacheManagerCallable(createCacheManager()) { - @Override - public void call() { - PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); - exec(transactional, new NakedPut(testee, true)); - } - }); - } - - @Test - public void testRegisteredPut() throws Exception { - registeredPutTest(false); - } - @Test - public void testRegisteredPutTransactional() throws Exception { - registeredPutTest(true); - } - - private void registeredPutTest(final boolean transactional) throws Exception { - withCacheManager(new CacheManagerCallable(createCacheManager()) { - @Override - public void call() { - PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); - exec(transactional, new RegularPut(testee)); - } - }); - } - - @Test - public void testNakedPutAfterKeyRemoval() throws Exception { - nakedPutAfterRemovalTest(false, false); - } - @Test - public void testNakedPutAfterKeyRemovalTransactional() throws Exception { - nakedPutAfterRemovalTest(true, false); - } - @Test - public void testNakedPutAfterRegionRemoval() throws Exception { - nakedPutAfterRemovalTest(false, true); - } - @Test - public void testNakedPutAfterRegionRemovalTransactional() throws Exception { - nakedPutAfterRemovalTest(true, true); - } - - private void nakedPutAfterRemovalTest(final boolean transactional, - final boolean removeRegion) throws Exception { - withCacheManager(new CacheManagerCallable(createCacheManager()) { - @Override - public void call() { - PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache()); - Invalidation invalidation = new Invalidation(testee, removeRegion); - // the naked put can succeed because it has txTimestamp after invalidation - NakedPut nakedPut = new NakedPut(testee, true); - exec(transactional, invalidation, nakedPut); - } - }); - - } - - @Test - public void testRegisteredPutAfterKeyRemoval() throws Exception { - registeredPutAfterRemovalTest(false, false); - } - @Test - public void testRegisteredPutAfterKeyRemovalTransactional() throws Exception { - registeredPutAfterRemovalTest(true, false); - } - @Test - public void testRegisteredPutAfterRegionRemoval() throws Exception { - registeredPutAfterRemovalTest(false, true); - } - @Test - public void testRegisteredPutAfterRegionRemovalTransactional() throws Exception { - registeredPutAfterRemovalTest(true, true); - } - - private void registeredPutAfterRemovalTest(final boolean transactional, - final boolean removeRegion) throws Exception { - withCacheManager(new CacheManagerCallable(createCacheManager()) { - @Override - public void call() { - PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); - Invalidation invalidation = new Invalidation(testee, removeRegion); - RegularPut regularPut = new RegularPut(testee); - exec(transactional, invalidation, regularPut); - } - }); - - } - @Test - public void testRegisteredPutWithInterveningKeyRemoval() throws Exception { - registeredPutWithInterveningRemovalTest(false, false); - } - @Test - public void testRegisteredPutWithInterveningKeyRemovalTransactional() throws Exception { - registeredPutWithInterveningRemovalTest(true, false); - } - @Test - public void testRegisteredPutWithInterveningRegionRemoval() throws Exception { - registeredPutWithInterveningRemovalTest(false, true); - } - @Test - public void testRegisteredPutWithInterveningRegionRemovalTransactional() throws Exception { - registeredPutWithInterveningRemovalTest(true, true); - } - - private void registeredPutWithInterveningRemovalTest( - final boolean transactional, final boolean removeRegion) - throws Exception { - withCacheManager(new CacheManagerCallable(createCacheManager()) { - @Override - public void call() { - PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); - try { - long txTimestamp = System.currentTimeMillis(); - if (transactional) { - tm.begin(); - } - SessionImplementor session1 = mock(SessionImplementor.class); - SessionImplementor session2 = mock(SessionImplementor.class); - testee.registerPendingPut(session1, KEY1, txTimestamp); - if (removeRegion) { - testee.beginInvalidatingRegion(); - } else { - testee.beginInvalidatingKey(session2, KEY1); - } - - PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session1, KEY1, txTimestamp); - try { - assertNull(lock); - } - finally { - if (lock != null) { - testee.releasePutFromLoadLock(KEY1, lock); - } - if (removeRegion) { - testee.endInvalidatingRegion(); - } else { - testee.endInvalidatingKey(session2, KEY1); - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - } - - @Test - public void testMultipleRegistrations() throws Exception { - multipleRegistrationtest(false); - } - - @Test - public void testMultipleRegistrationsTransactional() throws Exception { - multipleRegistrationtest(true); - } - - private void multipleRegistrationtest(final boolean transactional) throws Exception { - withCacheManager(new CacheManagerCallable(createCacheManager()) { - @Override - public void call() { - final PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); - - final CountDownLatch registeredLatch = new CountDownLatch(3); - final CountDownLatch finishedLatch = new CountDownLatch(3); - final AtomicInteger success = new AtomicInteger(); - - Runnable r = new Runnable() { - public void run() { - try { - long txTimestamp = System.currentTimeMillis(); - if (transactional) { - tm.begin(); - } - SessionImplementor session = mock (SessionImplementor.class); - testee.registerPendingPut(session, KEY1, txTimestamp); - registeredLatch.countDown(); - registeredLatch.await(5, TimeUnit.SECONDS); - PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp); - if (lock != null) { - try { - log.trace("Put from load lock acquired for key = " + KEY1); - success.incrementAndGet(); - } finally { - testee.releasePutFromLoadLock(KEY1, lock); - } - } else { - log.trace("Unable to acquired putFromLoad lock for key = " + KEY1); - } - finishedLatch.countDown(); - } catch (Exception e) { - e.printStackTrace(); - } - } - }; - - ExecutorService executor = Executors.newFixedThreadPool(3); - - // Start with a removal so the "isPutValid" calls will fail if - // any of the concurrent activity isn't handled properly - - testee.beginInvalidatingRegion(); - testee.endInvalidatingRegion(); - try { - Thread.sleep(10); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - // Do the registration + isPutValid calls - executor.execute(r); - executor.execute(r); - executor.execute(r); - - try { - finishedLatch.await(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - assertEquals("All threads succeeded", 3, success.get()); - } - }); - } - - @Test - public void testInvalidateKeyBlocksForInProgressPut() throws Exception { - invalidationBlocksForInProgressPutTest(true); - } - - @Test - public void testInvalidateRegionBlocksForInProgressPut() throws Exception { - invalidationBlocksForInProgressPutTest(false); - } - - private void invalidationBlocksForInProgressPutTest(final boolean keyOnly) throws Exception { - withCacheManager(new CacheManagerCallable(createCacheManager()) { - @Override - public void call() { - final PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); - final CountDownLatch removeLatch = new CountDownLatch(1); - final CountDownLatch pferLatch = new CountDownLatch(1); - final AtomicReference cache = new AtomicReference("INITIAL"); - - Callable pferCallable = new Callable() { - public Boolean call() throws Exception { - long txTimestamp = System.currentTimeMillis(); - SessionImplementor session = mock (SessionImplementor.class); - testee.registerPendingPut(session, KEY1, txTimestamp); - PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp); - if (lock != null) { - try { - removeLatch.countDown(); - pferLatch.await(); - cache.set("PFER"); - return Boolean.TRUE; - } - finally { - testee.releasePutFromLoadLock(KEY1, lock); - } - } - return Boolean.FALSE; - } - }; - - Callable invalidateCallable = new Callable() { - public Void call() throws Exception { - removeLatch.await(); - if (keyOnly) { - SessionImplementor session = mock (SessionImplementor.class); - testee.beginInvalidatingKey(session, KEY1); - } else { - testee.beginInvalidatingRegion(); - } - cache.set(null); - return null; - } - }; - - ExecutorService executorService = Executors.newCachedThreadPool(); - Future pferFuture = executorService.submit(pferCallable); - Future invalidateFuture = executorService.submit(invalidateCallable); - - try { - try { - invalidateFuture.get(1, TimeUnit.SECONDS); - fail("invalidateFuture did not block"); - } - catch (TimeoutException good) {} - - pferLatch.countDown(); - - assertTrue(pferFuture.get(5, TimeUnit.SECONDS)); - invalidateFuture.get(5, TimeUnit.SECONDS); - - assertNull(cache.get()); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - } - - protected void exec(boolean transactional, Callable... callables) { - try { - if (transactional) { - for (Callable c : callables) { - withTx(tm, c); - } - } else { - for (Callable c : callables) { - c.call(); - } - } - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private class Invalidation implements Callable { - private PutFromLoadValidator putFromLoadValidator; - private boolean removeRegion; - - public Invalidation(PutFromLoadValidator putFromLoadValidator, boolean removeRegion) { - this.putFromLoadValidator = putFromLoadValidator; - this.removeRegion = removeRegion; - } - - @Override - public Void call() throws Exception { - if (removeRegion) { - boolean success = putFromLoadValidator.beginInvalidatingRegion(); - assertTrue(success); - putFromLoadValidator.endInvalidatingRegion();; - } else { - SessionImplementor session = mock (SessionImplementor.class); - boolean success = putFromLoadValidator.beginInvalidatingKey(session, KEY1); - assertTrue(success); - success = putFromLoadValidator.endInvalidatingKey(session, KEY1); - assertTrue(success); - } - // if we go for the timestamp-based approach, invalidation in the same millisecond - // as the registerPendingPut/acquirePutFromLoad lock results in failure. - Thread.sleep(10); - return null; - } - } - - private class RegularPut implements Callable { - private PutFromLoadValidator putFromLoadValidator; - - public RegularPut(PutFromLoadValidator putFromLoadValidator) { - this.putFromLoadValidator = putFromLoadValidator; - } - - @Override - public Void call() throws Exception { - try { - long txTimestamp = System.currentTimeMillis(); // this should be acquired before UserTransaction.begin() - SessionImplementor session = mock (SessionImplementor.class); - putFromLoadValidator.registerPendingPut(session, KEY1, txTimestamp); - - PutFromLoadValidator.Lock lock = putFromLoadValidator.acquirePutFromLoadLock(session, KEY1, txTimestamp); - try { - assertNotNull(lock); - } finally { - if (lock != null) { - putFromLoadValidator.releasePutFromLoadLock(KEY1, lock); - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - return null; - } - } - - private class NakedPut implements Callable { - private final PutFromLoadValidator testee; - private final boolean expectSuccess; - - public NakedPut(PutFromLoadValidator testee, boolean expectSuccess) { - this.testee = testee; - this.expectSuccess = expectSuccess; - } - - @Override - public Void call() throws Exception { - try { - long txTimestamp = System.currentTimeMillis(); // this should be acquired before UserTransaction.begin() - SessionImplementor session = mock (SessionImplementor.class); - PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp); - try { - if (expectSuccess) { - assertNotNull(lock); - } else { - assertNull(lock); - } - } - finally { - if (lock != null) { - testee.releasePutFromLoadLock(KEY1, lock); - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - return null; - } - } - - @Test - @TestForIssue(jiraKey = "HHH-9928") - public void testGetForNullReleasePuts() { - EmbeddedCacheManager cm = TestCacheManagerFactory.createCacheManager(false); - ConfigurationBuilder cb = new ConfigurationBuilder().read(InfinispanRegionFactory.PENDING_PUTS_CACHE_CONFIGURATION); - cb.expiration().maxIdle(500); - cm.defineConfiguration(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME, cb.build()); - withCacheManager(new CacheManagerCallable(cm) { - @Override - public void call() { - PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm); - long lastInsert = Long.MAX_VALUE; - for (int i = 0; i < 100; ++i) { - lastInsert = System.currentTimeMillis(); - try { - withTx(tm, new Callable() { - @Override - public Object call() throws Exception { - SessionImplementor session = mock (SessionImplementor.class); - testee.registerPendingPut(session, KEY1, 0); - return null; - } - }); - Thread.sleep(10); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - String ppName = cm.getCache().getName() + "-" + InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME; - Map ppCache = cm.getCache(ppName, false); - assertNotNull(ppCache); - Object pendingPutMap = ppCache.get(KEY1); - long end = System.currentTimeMillis(); - if (end - lastInsert > 500) { - log.warn("Test took too long"); - return; - } - assertNotNull(pendingPutMap); - int size; - try { - Method sizeMethod = pendingPutMap.getClass().getMethod("size"); - sizeMethod.setAccessible(true); - size = (Integer) sizeMethod.invoke(pendingPutMap); - } catch (Exception e) { - throw new RuntimeException(e); - } - // some of the pending puts need to be expired by now - assertTrue(size < 100); - // but some are still registered - assertTrue(size > 0); - } - }); - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractCollectionRegionAccessStrategyTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractCollectionRegionAccessStrategyTest.java new file mode 100644 index 0000000000..6c82dc8239 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractCollectionRegionAccessStrategyTest.java @@ -0,0 +1,226 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.collection; + +import javax.transaction.TransactionManager; + +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import junit.framework.AssertionFailedError; +import org.hibernate.cache.infinispan.InfinispanRegionFactory; +import org.hibernate.cache.infinispan.access.PutFromLoadValidator; +import org.hibernate.cache.infinispan.access.InvalidationCacheAccessDelegate; +import org.hibernate.cache.infinispan.collection.CollectionRegionImpl; +import org.hibernate.cache.infinispan.util.Caches; +import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.test.cache.infinispan.AbstractRegionAccessStrategyTest; +import org.hibernate.test.cache.infinispan.NodeEnvironment; +import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; +import org.infinispan.AdvancedCache; +import org.infinispan.manager.EmbeddedCacheManager; +import org.infinispan.test.CacheManagerCallable; +import org.infinispan.test.fwk.TestCacheManagerFactory; +import org.junit.Test; + +import static org.infinispan.test.TestingUtil.withCacheManager; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +/** + * Base class for tests of CollectionRegionAccessStrategy impls. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public abstract class AbstractCollectionRegionAccessStrategyTest extends + AbstractRegionAccessStrategyTest { + protected static int testCount; + + @Override + protected Object generateNextKey() { + return TestingKeyFactory.generateCollectionCacheKey( KEY_BASE + testCount++ ); + } + + @Override + protected CollectionRegionImpl getRegion(NodeEnvironment environment) { + return environment.getCollectionRegion( REGION_NAME, CACHE_DATA_DESCRIPTION ); + } + + @Override + protected CollectionRegionAccessStrategy getAccessStrategy(CollectionRegionImpl region) { + return region.buildAccessStrategy( getAccessType() ); + } + + @Test + public abstract void testCacheConfiguration(); + + @Test + public void testGetRegion() { + assertEquals( "Correct region", localRegion, localAccessStrategy.getRegion() ); + } + + @Test + public void testPutFromLoadRemoveDoesNotProduceStaleData() throws Exception { + final CountDownLatch pferLatch = new CountDownLatch( 1 ); + final CountDownLatch removeLatch = new CountDownLatch( 1 ); + final TransactionManager remoteTm = remoteRegion.getTransactionManager(); + withCacheManager(new CacheManagerCallable(createCacheManager()) { + @Override + public void call() { + PutFromLoadValidator validator = getPutFromLoadValidator(remoteRegion.getCache(), cm, removeLatch, pferLatch); + + final InvalidationCacheAccessDelegate delegate = + InvalidationCacheAccessDelegate.create(localRegion, validator); + + Callable pferCallable = new Callable() { + public Void call() throws Exception { + SessionImplementor session = mockedSession(); + delegate.putFromLoad(session, "k1", "v1", 0, null ); + return null; + } + }; + + Callable removeCallable = new Callable() { + public Void call() throws Exception { + removeLatch.await(); + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, new Callable() { + @Override + public Void call() throws Exception { + delegate.remove(session, "k1"); + return null; + } + }); + pferLatch.countDown(); + return null; + } + }; + + ExecutorService executorService = Executors.newCachedThreadPool(); + Future pferFuture = executorService.submit( pferCallable ); + Future removeFuture = executorService.submit( removeCallable ); + + try { + pferFuture.get(); + removeFuture.get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + + assertFalse(localRegion.getCache().containsKey("k1")); + } + }); + } + + private static EmbeddedCacheManager createCacheManager() { + EmbeddedCacheManager cacheManager = TestCacheManagerFactory.createCacheManager(false); + cacheManager.defineConfiguration(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME, + InfinispanRegionFactory.PENDING_PUTS_CACHE_CONFIGURATION); + return cacheManager; + } + + protected PutFromLoadValidator getPutFromLoadValidator(AdvancedCache cache, EmbeddedCacheManager cm, + CountDownLatch removeLatch, CountDownLatch pferLatch) { + // remove the interceptor inserted by default PutFromLoadValidator, we're using different one + PutFromLoadValidator.removeFromCache(cache); + return new PutFromLoadValidator(cache, cm) { + @Override + public Lock acquirePutFromLoadLock(SessionImplementor session, Object key, long txTimestamp) { + Lock lock = super.acquirePutFromLoadLock(session, key, txTimestamp); + try { + removeLatch.countDown(); + pferLatch.await( 2, TimeUnit.SECONDS ); + } + catch (InterruptedException e) { + log.debug( "Interrupted" ); + Thread.currentThread().interrupt(); + } + catch (Exception e) { + log.error( "Error", e ); + throw new RuntimeException( "Error", e ); + } + return lock; + } + }; + } + + @Override + protected void putFromLoadTest(final boolean useMinimalAPI) throws Exception { + + final Object KEY = generateNextKey(); + + final CountDownLatch writeLatch1 = new CountDownLatch( 1 ); + final CountDownLatch writeLatch2 = new CountDownLatch( 1 ); + final CountDownLatch completionLatch = new CountDownLatch( 2 ); + + Thread node1 = new Thread() { + @Override + public void run() { + try { + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, () -> { + assertNull(localAccessStrategy.get(session, KEY, txTimestamp)); + + writeLatch1.await(); + + if (useMinimalAPI) { + localAccessStrategy.putFromLoad(session, KEY, VALUE2, txTimestamp, new Integer(2), true); + } else { + localAccessStrategy.putFromLoad(session, KEY, VALUE2, txTimestamp, new Integer(2)); + } + return null; + }); + } + catch (Exception e) { + log.error( "node1 caught exception", e ); + node1Exception = e; + } + catch (AssertionFailedError e) { + node1Failure = e; + } + finally { + // Let node2 write + writeLatch2.countDown(); + completionLatch.countDown(); + } + } + }; + + Thread node2 = new PutFromLoadNode2(KEY, writeLatch1, writeLatch2, useMinimalAPI, completionLatch); + + node1.setDaemon( true ); + node2.setDaemon( true ); + + node1.start(); + node2.start(); + + assertTrue( "Threads completed", completionLatch.await( 2, TimeUnit.SECONDS ) ); + + assertThreadsRanCleanly(); + + long txTimestamp = System.currentTimeMillis(); + + assertEquals( VALUE2, localAccessStrategy.get(mockedSession(), KEY, txTimestamp ) ); + Object remoteValue = remoteAccessStrategy.get(mockedSession(), KEY, txTimestamp); + if (isUsingInvalidation()) { + assertEquals( VALUE1, remoteValue); + } + else { + assertEquals( VALUE2, remoteValue); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractCollectionRegionAccessStrategyTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractCollectionRegionAccessStrategyTestCase.java deleted file mode 100644 index e2f9be30e2..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractCollectionRegionAccessStrategyTestCase.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.collection; - -import javax.transaction.TransactionManager; - -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import junit.framework.AssertionFailedError; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.infinispan.access.PutFromLoadValidator; -import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate; -import org.hibernate.cache.infinispan.collection.CollectionRegionImpl; -import org.hibernate.cache.infinispan.util.Caches; -import org.hibernate.cache.internal.CacheDataDescriptionImpl; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.internal.util.compare.ComparableComparator; -import org.hibernate.test.cache.infinispan.AbstractNonFunctionalTestCase; -import org.hibernate.test.cache.infinispan.NodeEnvironment; -import org.hibernate.test.cache.infinispan.util.CacheTestUtil; -import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; -import org.infinispan.AdvancedCache; -import org.infinispan.manager.EmbeddedCacheManager; -import org.infinispan.test.CacheManagerCallable; -import org.infinispan.test.fwk.TestCacheManagerFactory; -import org.infinispan.transaction.tm.BatchModeTransactionManager; -import org.jboss.logging.Logger; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import static org.infinispan.test.TestingUtil.withCacheManager; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; - -/** - * Base class for tests of CollectionRegionAccessStrategy impls. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public abstract class AbstractCollectionRegionAccessStrategyTestCase extends AbstractNonFunctionalTestCase { - private static final Logger log = Logger.getLogger( AbstractCollectionRegionAccessStrategyTestCase.class ); - - @Rule - public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - - public static final String REGION_NAME = "test/com.foo.test"; - public static final String KEY_BASE = "KEY"; - public static final String VALUE1 = "VALUE1"; - public static final String VALUE2 = "VALUE2"; - - protected static int testCount; - - protected NodeEnvironment localEnvironment; - protected CollectionRegionImpl localCollectionRegion; - protected CollectionRegionAccessStrategy localAccessStrategy; - protected SessionImplementor localSession; - - protected NodeEnvironment remoteEnvironment; - protected CollectionRegionImpl remoteCollectionRegion; - protected CollectionRegionAccessStrategy remoteAccessStrategy; - protected SessionImplementor remoteSession; - - protected boolean invalidation; - protected boolean synchronous; - - protected Exception node1Exception; - protected Exception node2Exception; - - protected AssertionFailedError node1Failure; - protected AssertionFailedError node2Failure; - - protected abstract AccessType getAccessType(); - - @Before - public void prepareResources() throws Exception { - // to mimic exactly the old code results, both environments here are exactly the same... - StandardServiceRegistryBuilder ssrb = createStandardServiceRegistryBuilder( getConfigurationName() ); - localEnvironment = new NodeEnvironment( ssrb ); - localEnvironment.prepare(); - - localCollectionRegion = localEnvironment.getCollectionRegion( REGION_NAME, getCacheDataDescription() ); - localAccessStrategy = localCollectionRegion.buildAccessStrategy( getAccessType() ); - localSession = mock(SessionImplementor.class); - - invalidation = Caches.isInvalidationCache(localCollectionRegion.getCache()); - synchronous = Caches.isSynchronousCache(localCollectionRegion.getCache()); - - // Sleep a bit to avoid concurrent FLUSH problem - avoidConcurrentFlush(); - - remoteEnvironment = new NodeEnvironment( ssrb ); - remoteEnvironment.prepare(); - - remoteCollectionRegion = remoteEnvironment.getCollectionRegion( REGION_NAME, getCacheDataDescription() ); - remoteAccessStrategy = remoteCollectionRegion.buildAccessStrategy( getAccessType() ); - remoteSession = mock(SessionImplementor.class); - } - - protected abstract String getConfigurationName(); - - protected static StandardServiceRegistryBuilder createStandardServiceRegistryBuilder(String configName) { - final StandardServiceRegistryBuilder ssrb = CacheTestUtil.buildBaselineStandardServiceRegistryBuilder( - REGION_PREFIX, - InfinispanRegionFactory.class, - true, - false - ); - ssrb.applySetting( InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, configName ); - return ssrb; - } - - protected CacheDataDescription getCacheDataDescription() { - return new CacheDataDescriptionImpl( true, true, ComparableComparator.INSTANCE, null); - } - - @After - public void releaseResources() throws Exception { - if ( localEnvironment != null ) { - localEnvironment.release(); - } - if ( remoteEnvironment != null ) { - remoteEnvironment.release(); - } - } - - protected boolean isUsingInvalidation() { - return invalidation; - } - - protected boolean isSynchronous() { - return synchronous; - } - - @Test - public abstract void testCacheConfiguration(); - - @Test - public void testGetRegion() { - assertEquals( "Correct region", localCollectionRegion, localAccessStrategy.getRegion() ); - } - - @Test - public void testPutFromLoadRemoveDoesNotProduceStaleData() throws Exception { - final CountDownLatch pferLatch = new CountDownLatch( 1 ); - final CountDownLatch removeLatch = new CountDownLatch( 1 ); - final TransactionManager remoteTm = remoteCollectionRegion.getTransactionManager(); - withCacheManager(new CacheManagerCallable(createCacheManager()) { - @Override - public void call() { - PutFromLoadValidator validator = getPutFromLoadValidator(remoteCollectionRegion.getCache(), cm, removeLatch, pferLatch); - - final TransactionalAccessDelegate delegate = - TransactionalAccessDelegate.create(localCollectionRegion, validator); - final TransactionManager localTm = localCollectionRegion.getTransactionManager(); - - Callable pferCallable = new Callable() { - public Void call() throws Exception { - SessionImplementor session = mock(SessionImplementor.class); - delegate.putFromLoad(session, "k1", "v1", 0, null ); - return null; - } - }; - - Callable removeCallable = new Callable() { - public Void call() throws Exception { - removeLatch.await(); - Caches.withinTx(localTm, new Callable() { - @Override - public Void call() throws Exception { - SessionImplementor session = mock(SessionImplementor.class); - delegate.remove(session, "k1"); - return null; - } - }); - pferLatch.countDown(); - return null; - } - }; - - ExecutorService executorService = Executors.newCachedThreadPool(); - Future pferFuture = executorService.submit( pferCallable ); - Future removeFuture = executorService.submit( removeCallable ); - - try { - pferFuture.get(); - removeFuture.get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - - assertFalse(localCollectionRegion.getCache().containsKey("k1")); - } - }); - } - - private static EmbeddedCacheManager createCacheManager() { - EmbeddedCacheManager cacheManager = TestCacheManagerFactory.createCacheManager(false); - cacheManager.defineConfiguration(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME, - InfinispanRegionFactory.PENDING_PUTS_CACHE_CONFIGURATION); - return cacheManager; - } - - protected PutFromLoadValidator getPutFromLoadValidator(AdvancedCache cache, EmbeddedCacheManager cm, - CountDownLatch removeLatch, CountDownLatch pferLatch) { - // remove the interceptor inserted by default PutFromLoadValidator, we're using different one - PutFromLoadValidator.removeFromCache(cache); - return new PutFromLoadValidator(cache, cm) { - @Override - public Lock acquirePutFromLoadLock(SessionImplementor session, Object key, long txTimestamp) { - Lock lock = super.acquirePutFromLoadLock(session, key, txTimestamp); - try { - removeLatch.countDown(); - pferLatch.await( 2, TimeUnit.SECONDS ); - } - catch (InterruptedException e) { - log.debug( "Interrupted" ); - Thread.currentThread().interrupt(); - } - catch (Exception e) { - log.error( "Error", e ); - throw new RuntimeException( "Error", e ); - } - return lock; - } - }; - } - - @Test - public void testPutFromLoad() throws Exception { - putFromLoadTest( false ); - } - - @Test - public void testPutFromLoadMinimal() throws Exception { - putFromLoadTest( true ); - } - - private void putFromLoadTest(final boolean useMinimalAPI) throws Exception { - - final Object KEY = TestingKeyFactory.generateCollectionCacheKey( KEY_BASE + testCount++ ); - - final CountDownLatch writeLatch1 = new CountDownLatch( 1 ); - final CountDownLatch writeLatch2 = new CountDownLatch( 1 ); - final CountDownLatch completionLatch = new CountDownLatch( 2 ); - - Thread node1 = new Thread() { - - public void run() { - - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - - assertEquals( "node1 starts clean", null, localAccessStrategy.get(localSession, KEY, txTimestamp ) ); - - writeLatch1.await(); - - if ( useMinimalAPI ) { - localAccessStrategy.putFromLoad(localSession, KEY, VALUE2, txTimestamp, new Integer( 2 ), true ); - } - else { - localAccessStrategy.putFromLoad(localSession, KEY, VALUE2, txTimestamp, new Integer( 2 ) ); - } - - BatchModeTransactionManager.getInstance().commit(); - } - catch (Exception e) { - log.error( "node1 caught exception", e ); - node1Exception = e; - rollback(); - } - catch (AssertionFailedError e) { - node1Failure = e; - rollback(); - } - finally { - // Let node2 write - writeLatch2.countDown(); - completionLatch.countDown(); - } - } - }; - - Thread node2 = new Thread() { - - public void run() { - - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - - assertNull( "node2 starts clean", remoteAccessStrategy.get(remoteSession, KEY, txTimestamp ) ); - - // Let node1 write - writeLatch1.countDown(); - // Wait for node1 to finish - writeLatch2.await(); - - // Let the first PFER propagate - sleep( 200 ); - - if ( useMinimalAPI ) { - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, txTimestamp, new Integer( 1 ), true ); - } - else { - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, txTimestamp, new Integer( 1 ) ); - } - - BatchModeTransactionManager.getInstance().commit(); - } - catch (Exception e) { - log.error( "node2 caught exception", e ); - node2Exception = e; - rollback(); - } - catch (AssertionFailedError e) { - node2Failure = e; - rollback(); - } - finally { - completionLatch.countDown(); - } - } - }; - - node1.setDaemon( true ); - node2.setDaemon( true ); - - node1.start(); - node2.start(); - - assertTrue( "Threads completed", completionLatch.await( 2, TimeUnit.SECONDS ) ); - - if ( node1Failure != null ) { - throw node1Failure; - } - if ( node2Failure != null ) { - throw node2Failure; - } - - assertEquals( "node1 saw no exceptions", null, node1Exception ); - assertEquals( "node2 saw no exceptions", null, node2Exception ); - - // let the final PFER propagate - sleep( 100 ); - - long txTimestamp = System.currentTimeMillis(); - String msg1 = "Correct node1 value"; - String msg2 = "Correct node2 value"; - Object expected1 = null; - Object expected2 = null; - if ( isUsingInvalidation() ) { - // PFER does not generate any invalidation, so each node should - // succeed. We count on database locking and Hibernate removing - // the collection on any update to prevent the situation we have - // here where the caches have inconsistent data - expected1 = VALUE2; - expected2 = VALUE1; - } - else { - // the initial VALUE2 should prevent the node2 put - expected1 = VALUE2; - expected2 = VALUE2; - } - - assertEquals( msg1, expected1, localAccessStrategy.get(localSession, KEY, txTimestamp ) ); - assertEquals( msg2, expected2, remoteAccessStrategy.get(remoteSession, KEY, txTimestamp ) ); - } - - @Test - public void testRemove() throws Exception { - evictOrRemoveTest( false ); - } - - @Test - public void testRemoveAll() throws Exception { - evictOrRemoveAllTest( false ); - } - - @Test - public void testEvict() throws Exception { - evictOrRemoveTest( true ); - } - - @Test - public void testEvictAll() throws Exception { - evictOrRemoveAllTest( true ); - } - - private void evictOrRemoveTest(final boolean evict) throws Exception { - - final Object KEY = TestingKeyFactory.generateCollectionCacheKey( KEY_BASE + testCount++ ); - - assertNull( "local is clean", localAccessStrategy.get(localSession, KEY, System.currentTimeMillis() ) ); - assertNull( "remote is clean", remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis() ) ); - - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, System.currentTimeMillis(), new Integer( 1 ) ); - assertEquals( VALUE1, localAccessStrategy.get(localSession, KEY, System.currentTimeMillis() ) ); - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, System.currentTimeMillis(), new Integer( 1 ) ); - assertEquals( VALUE1, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis() ) ); - - // Wait for async propagation - sleep( 250 ); - - Caches.withinTx(localCollectionRegion.getTransactionManager(), new Callable() { - @Override - public Void call() throws Exception { - if (evict) - localAccessStrategy.evict(KEY); - else - localAccessStrategy.remove(localSession, KEY); - return null; - } - }); - - assertEquals( null, localAccessStrategy.get(localSession, KEY, System.currentTimeMillis() ) ); - - assertEquals( null, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis() ) ); - } - - private void evictOrRemoveAllTest(final boolean evict) throws Exception { - - final Object KEY = TestingKeyFactory.generateCollectionCacheKey( KEY_BASE + testCount++ ); - - assertEquals( 0, localCollectionRegion.getCache().size() ); - - assertEquals( 0, remoteCollectionRegion.getCache().size() ); - - assertNull( "local is clean", localAccessStrategy.get(localSession, KEY, System.currentTimeMillis() ) ); - assertNull( "remote is clean", remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis() ) ); - - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, System.currentTimeMillis(), new Integer( 1 ) ); - assertEquals( VALUE1, localAccessStrategy.get(localSession, KEY, System.currentTimeMillis() ) ); - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, System.currentTimeMillis(), new Integer( 1 ) ); - assertEquals( VALUE1, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis() ) ); - - // Wait for async propagation - sleep( 250 ); - - Caches.withinTx(localCollectionRegion.getTransactionManager(), new Callable() { - @Override - public Void call() throws Exception { - if (evict) - localAccessStrategy.evictAll(); - else - localAccessStrategy.removeAll(); - return null; - } - }); - - // This should re-establish the region root node - assertNull( localAccessStrategy.get(localSession, KEY, System.currentTimeMillis() ) ); - - assertEquals( 0, localCollectionRegion.getCache().size() ); - - // Re-establishing the region root on the local node doesn't - // propagate it to other nodes. Do a get on the remote node to re-establish - assertEquals( null, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis() ) ); - - assertEquals( 0, remoteCollectionRegion.getCache().size() ); - - // Wait for async propagation of EndInvalidationCommand - sleep( 250 ); - - // Test whether the get above messes up the optimistic version - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, System.currentTimeMillis(), new Integer( 1 ) ); - assertEquals( VALUE1, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis() ) ); - - assertEquals( 1, remoteCollectionRegion.getCache().size() ); - - // Wait for async propagation of the putFromLoad - sleep( 250 ); - - assertEquals( - "local is correct", (isUsingInvalidation() ? null : VALUE1), localAccessStrategy.get( - localSession, KEY, System - .currentTimeMillis() - ) - ); - assertEquals( "remote is correct", VALUE1, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis() ) ); - } - - private void rollback() { - try { - BatchModeTransactionManager.getInstance().rollback(); - } - catch (Exception e) { - log.error( e.getMessage(), e ); - } - - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractReadOnlyAccessTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractReadOnlyAccessTestCase.java deleted file mode 100644 index dae0a8aec9..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractReadOnlyAccessTestCase.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.collection; - -import org.hibernate.cache.spi.access.AccessType; - -/** - * Base class for tests of TRANSACTIONAL access. - * - * @author Brian Stansberry - */ -public abstract class AbstractReadOnlyAccessTestCase extends AbstractCollectionRegionAccessStrategyTestCase { - @Override - protected AccessType getAccessType() { - return AccessType.READ_ONLY; - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractTransactionalAccessTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractTransactionalAccessTestCase.java deleted file mode 100644 index 1f9076d830..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/AbstractTransactionalAccessTestCase.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.collection; -import org.hibernate.cache.spi.access.AccessType; - -/** - * Base class for tests of TRANSACTIONAL access. - * - * @author Brian Stansberry - */ -public abstract class AbstractTransactionalAccessTestCase extends AbstractCollectionRegionAccessStrategyTestCase { - @Override - protected AccessType getAccessType() { - return AccessType.TRANSACTIONAL; - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionAccessExtraAPITest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionAccessExtraAPITest.java new file mode 100644 index 0000000000..e79672617e --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionAccessExtraAPITest.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.collection; + +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.test.cache.infinispan.AbstractExtraAPITest; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; + +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; + +/** + * @author Galder Zamarreño + * @since 3.5 + */ +public abstract class CollectionRegionAccessExtraAPITest extends AbstractExtraAPITest { + @Override + protected CollectionRegionAccessStrategy getAccessStrategy() { + return environment.getCollectionRegion( REGION_NAME, CACHE_DATA_DESCRIPTION).buildAccessStrategy( getAccessType() ); + } + + public static class Transactional extends CollectionRegionAccessExtraAPITest { + @Override + protected AccessType getAccessType() { + return AccessType.TRANSACTIONAL; + } + + @Override + protected Class getRegionFactoryClass() { + return TestInfinispanRegionFactory.Transactional.class; + } + } + + public static class ReadWrite extends CollectionRegionAccessExtraAPITest { + @Override + protected AccessType getAccessType() { + return AccessType.READ_WRITE; + } + } + + public static class ReadOnly extends CollectionRegionAccessExtraAPITest { + @Override + protected AccessType getAccessType() { + return AccessType.READ_ONLY; + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTest.java new file mode 100644 index 0000000000..bfafb3d3b5 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTest.java @@ -0,0 +1,64 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.collection; + +import java.util.Properties; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.InfinispanRegionFactory; +import org.hibernate.cache.spi.CacheDataDescription; +import org.hibernate.cache.spi.CollectionRegion; +import org.hibernate.cache.spi.Region; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; +import org.hibernate.test.cache.infinispan.AbstractEntityCollectionRegionTest; +import org.infinispan.AdvancedCache; + +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +/** + * @author Galder Zamarreño + */ +public class CollectionRegionImplTest extends AbstractEntityCollectionRegionTest { + @Override + protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) { + CollectionRegion region = regionFactory.buildCollectionRegion("test", properties, MUTABLE_NON_VERSIONED); + assertNotNull(region.buildAccessStrategy(AccessType.READ_ONLY)); + assertNotNull(region.buildAccessStrategy(AccessType.READ_WRITE)); + assertNotNull(region.buildAccessStrategy(AccessType.TRANSACTIONAL)); + try { + region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE); + fail("Incorrectly got NONSTRICT_READ_WRITE"); + } catch (CacheException good) { + } + } + + @Override + protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) { + return regionFactory.buildCollectionRegion(regionName, properties, cdd); + } + + @Override + protected AdvancedCache getInfinispanCache(InfinispanRegionFactory regionFactory) { + return regionFactory.getCacheManager().getCache(InfinispanRegionFactory.DEF_ENTITY_RESOURCE).getAdvancedCache(); + } + + @Override + protected void putInRegion(Region region, Object key, Object value) { + CollectionRegionAccessStrategy strategy = ((CollectionRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL); + strategy.putFromLoad(null, key, value, System.currentTimeMillis(), new Integer(1)); + } + + @Override + protected void removeFromRegion(Region region, Object key) { + ((CollectionRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).remove(null, key); + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTestCase.java deleted file mode 100644 index c158a1ae4a..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTestCase.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.collection; - -import java.util.Properties; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.CollectionRegion; -import org.hibernate.cache.spi.Region; -import org.hibernate.cache.spi.RegionFactory; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; -import org.hibernate.test.cache.infinispan.AbstractEntityCollectionRegionTestCase; -import org.infinispan.AdvancedCache; - -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -/** - * Tests of CollectionRegionImpl. - * - * @author Galder Zamarreño - */ -public class CollectionRegionImplTestCase extends AbstractEntityCollectionRegionTestCase { - @Override - protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) { - CollectionRegion region = regionFactory.buildCollectionRegion("test", properties, MUTABLE_NON_VERSIONED); - assertNull("Got TRANSACTIONAL", region.buildAccessStrategy(AccessType.TRANSACTIONAL) - .lockRegion()); - try { - region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE); - fail("Incorrectly got NONSTRICT_READ_WRITE"); - } catch (CacheException good) { - } - - try { - region.buildAccessStrategy(AccessType.READ_WRITE); - fail("Incorrectly got READ_WRITE"); - } catch (CacheException good) { - } - } - - @Override - protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) { - return regionFactory.buildCollectionRegion(regionName, properties, cdd); - } - - @Override - protected AdvancedCache getInfinispanCache(InfinispanRegionFactory regionFactory) { - return regionFactory.getCacheManager().getCache(InfinispanRegionFactory.DEF_ENTITY_RESOURCE).getAdvancedCache(); - } - - @Override - protected void putInRegion(Region region, Object key, Object value) { - CollectionRegionAccessStrategy strategy = ((CollectionRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL); - strategy.putFromLoad(null, key, value, System.currentTimeMillis(), new Integer(1)); - } - - @Override - protected void removeFromRegion(Region region, Object key) { - ((CollectionRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).remove(null, key); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionReadOnlyAccessTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionReadOnlyAccessTest.java new file mode 100644 index 0000000000..25718b6851 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionReadOnlyAccessTest.java @@ -0,0 +1,39 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.collection; + +import org.hibernate.cache.spi.access.AccessType; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Base class for tests of READ_ONLY access. + * + * @author Brian Stansberry + */ +public abstract class CollectionRegionReadOnlyAccessTest extends AbstractCollectionRegionAccessStrategyTest { + @Override + protected AccessType getAccessType() { + return AccessType.READ_ONLY; + } + + /** + * Tests READ_ONLY access when invalidation is used. + * + * @author Galder Zamarreño + * @since 3.5 + */ + public static class Invalidation extends CollectionRegionReadOnlyAccessTest { + @Override + public void testCacheConfiguration() { + assertFalse(isTransactional()); + assertTrue( "Using Invalidation", isUsingInvalidation() ); + assertTrue( isSynchronous() ); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionReadWriteAccessTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionReadWriteAccessTest.java new file mode 100644 index 0000000000..0a8004504f --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionReadWriteAccessTest.java @@ -0,0 +1,27 @@ +package org.hibernate.test.cache.infinispan.collection; + +import org.hibernate.cache.spi.access.AccessType; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Tests read-write access + * + * @author Radim Vansa <rvansa@redhat.com> + */ +public abstract class CollectionRegionReadWriteAccessTest extends AbstractCollectionRegionAccessStrategyTest { + @Override + protected AccessType getAccessType() { + return AccessType.READ_WRITE; + } + + public static class Invalidation extends CollectionRegionReadWriteAccessTest { + @Override + public void testCacheConfiguration() { + assertFalse(isTransactional()); + assertTrue(isUsingInvalidation()); + assertTrue(isSynchronous()); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionTransactionalAccessTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionTransactionalAccessTest.java new file mode 100644 index 0000000000..02783499f6 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionTransactionalAccessTest.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.collection; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; + +import static org.junit.Assert.assertTrue; + +/** + * Base class for tests of TRANSACTIONAL access. + * + * @author Brian Stansberry + */ +public abstract class CollectionRegionTransactionalAccessTest extends AbstractCollectionRegionAccessStrategyTest { + @Override + protected AccessType getAccessType() { + return AccessType.TRANSACTIONAL; + } + + @Override + protected Class getRegionFactoryClass() { + return TestInfinispanRegionFactory.Transactional.class; + } + + /** + * InvalidatedTransactionalTestCase. + * + * @author Galder Zamarreño + * @since 3.5 + */ + public static class Invalidation extends CollectionRegionTransactionalAccessTest { + @Override + public void testCacheConfiguration() { + assertTrue("Transactions", isTransactional()); + assertTrue("Using Invalidation", isUsingInvalidation()); + assertTrue("Synchronous mode", isSynchronous()); + } + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/InvalidatedTransactionalTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/InvalidatedTransactionalTestCase.java deleted file mode 100644 index 3193ddd342..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/InvalidatedTransactionalTestCase.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.collection; - -import org.junit.Test; - -import static org.junit.Assert.assertTrue; - -/** - * InvalidatedTransactionalTestCase. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class InvalidatedTransactionalTestCase extends AbstractTransactionalAccessTestCase { - @Test - @Override - public void testCacheConfiguration() { - assertTrue("Using Invalidation", isUsingInvalidation()); - assertTrue("Synchronous mode", isSynchronous()); - } - - @Override - protected String getConfigurationName() { - return "entity"; // todo : should this be "collection"? the original code used "entity"... - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/ReadOnlyTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/ReadOnlyTestCase.java deleted file mode 100644 index d56efc0233..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/ReadOnlyTestCase.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.collection; - -import static org.junit.Assert.assertTrue; - -/** - * Tests READ_ONLY access when invalidation is used. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class ReadOnlyTestCase extends AbstractReadOnlyAccessTestCase { - @Override - public void testCacheConfiguration() { - assertTrue( "Using Invalidation", isUsingInvalidation() ); - } - - @Override - protected String getConfigurationName() { - return "entity"; // todo : should this be "collection"? the original code used "entity"... - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/TransactionalExtraAPITestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/TransactionalExtraAPITestCase.java deleted file mode 100644 index 146f563ce1..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/TransactionalExtraAPITestCase.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.collection; - -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.internal.CacheDataDescriptionImpl; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.internal.util.compare.ComparableComparator; -import org.hibernate.test.cache.infinispan.AbstractNonFunctionalTestCase; -import org.hibernate.test.cache.infinispan.NodeEnvironment; -import org.hibernate.test.cache.infinispan.util.CacheTestUtil; -import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.mock; - -/** - * TransactionalExtraAPITestCase. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class TransactionalExtraAPITestCase extends AbstractNonFunctionalTestCase { - - @Rule - public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - - public static final String REGION_NAME = "test/com.foo.test"; - public static final Object KEY = TestingKeyFactory.generateCollectionCacheKey( "KEY" ); - public static final CacheDataDescription CACHE_DATA_DESCRIPTION - = new CacheDataDescriptionImpl(false, false, ComparableComparator.INSTANCE, null); - private static final SessionImplementor SESSION = mock(SessionImplementor.class); - - private NodeEnvironment environment; - private static CollectionRegionAccessStrategy accessStrategy; - - @Before - public final void prepareLocalAccessStrategy() throws Exception { - environment = new NodeEnvironment( createStandardServiceRegistryBuilder() ); - environment.prepare(); - - // Sleep a bit to avoid concurrent FLUSH problem - avoidConcurrentFlush(); - - accessStrategy = environment.getCollectionRegion( REGION_NAME, CACHE_DATA_DESCRIPTION).buildAccessStrategy( getAccessType() ); - } - - protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() { - StandardServiceRegistryBuilder ssrb = CacheTestUtil.buildBaselineStandardServiceRegistryBuilder( - REGION_PREFIX, InfinispanRegionFactory.class, true, false - ); - ssrb.applySetting( InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, getCacheConfigName() ); - return ssrb; - } - - protected String getCacheConfigName() { - return "entity"; - } - - protected AccessType getAccessType() { - return AccessType.TRANSACTIONAL; - } - - @After - public final void releaseLocalAccessStrategy() throws Exception { - if ( environment != null ) { - environment.release(); - } - } - - protected CollectionRegionAccessStrategy getCollectionAccessStrategy() { - return accessStrategy; - } - - @Test - public void testLockItem() { - assertNull( getCollectionAccessStrategy().lockItem(SESSION, KEY, new Integer( 1 ) ) ); - } - - @Test - public void testLockRegion() { - assertNull( getCollectionAccessStrategy().lockRegion() ); - } - - @Test - public void testUnlockItem() { - getCollectionAccessStrategy().unlockItem(SESSION, KEY, new MockSoftLock() ); - } - - @Test - public void testUnlockRegion() { - getCollectionAccessStrategy().unlockItem(SESSION, KEY, new MockSoftLock() ); - } - - public static class MockSoftLock implements SoftLock { - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTest.java new file mode 100644 index 0000000000..0f675c1ef3 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTest.java @@ -0,0 +1,400 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.entity; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import junit.framework.AssertionFailedError; +import org.hibernate.cache.infinispan.entity.EntityRegionImpl; +import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.test.cache.infinispan.AbstractRegionAccessStrategyTest; +import org.hibernate.test.cache.infinispan.NodeEnvironment; +import org.hibernate.test.cache.infinispan.util.TestSynchronization; +import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; +import org.infinispan.transaction.tm.BatchModeTransactionManager; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +/** + * Base class for tests of EntityRegionAccessStrategy impls. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public abstract class AbstractEntityRegionAccessStrategyTest extends + AbstractRegionAccessStrategyTest { + protected static int testCount; + + @Override + protected Object generateNextKey() { + return TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); + } + + @Override + protected EntityRegionImpl getRegion(NodeEnvironment environment) { + return environment.getEntityRegion(REGION_NAME, CACHE_DATA_DESCRIPTION); + } + + @Override + protected EntityRegionAccessStrategy getAccessStrategy(EntityRegionImpl region) { + return region.buildAccessStrategy(getAccessType()); + } + + @Test + public abstract void testCacheConfiguration(); + + @Test + public void testGetRegion() { + assertEquals("Correct region", localRegion, localAccessStrategy.getRegion()); + } + + /** + * Simulate 2 nodes, both start, tx do a get, experience a cache miss, then + * 'read from db.' First does a putFromLoad, then an update. Second tries to + * do a putFromLoad with stale data (i.e. it took longer to read from the db). + * Both commit their tx. Then both start a new tx and get. First should see + * the updated data; second should either see the updated data + * (isInvalidation() == false) or null (isInvalidation() == true). + * + * @param useMinimalAPI + * @throws Exception + */ + protected void putFromLoadTest(final boolean useMinimalAPI) throws Exception { + + final Object KEY = generateNextKey(); + + final CountDownLatch writeLatch1 = new CountDownLatch(1); + final CountDownLatch writeLatch2 = new CountDownLatch(1); + final CountDownLatch completionLatch = new CountDownLatch(2); + + Thread node1 = new Thread() { + @Override + public void run() { + try { + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, () -> { + assertNull(localAccessStrategy.get(session, KEY, txTimestamp)); + + writeLatch1.await(); + + if (useMinimalAPI) { + localAccessStrategy.putFromLoad(session, KEY, VALUE1, txTimestamp, null, true); + } else { + localAccessStrategy.putFromLoad(session, KEY, VALUE1, txTimestamp, null); + } + + doUpdate(localAccessStrategy, session, KEY, VALUE2); + return null; + }); + } catch (Exception e) { + log.error("node1 caught exception", e); + node1Exception = e; + } catch (AssertionFailedError e) { + node1Failure = e; + } finally { + // Let node2 write + writeLatch2.countDown(); + completionLatch.countDown(); + } + } + }; + + Thread node2 = new PutFromLoadNode2(KEY, writeLatch1, writeLatch2, useMinimalAPI, completionLatch); + + node1.setDaemon(true); + node2.setDaemon(true); + + node1.start(); + node2.start(); + + assertTrue("Threads completed", completionLatch.await(2, TimeUnit.SECONDS)); + + assertThreadsRanCleanly(); + + long txTimestamp = System.currentTimeMillis(); + assertEquals( VALUE2, localAccessStrategy.get(mockedSession(), KEY, txTimestamp)); + Object remoteValue = remoteAccessStrategy.get(mockedSession(), KEY, txTimestamp); + if (isUsingInvalidation()) { + // invalidation command invalidates pending put + assertNull(remoteValue); + } + else { + // The node1 update is replicated, preventing the node2 PFER + assertEquals( VALUE2, remoteValue); + } + } + + @Test + public void testInsert() throws Exception { + + final Object KEY = generateNextKey(); + + final CountDownLatch readLatch = new CountDownLatch(1); + final CountDownLatch commitLatch = new CountDownLatch(1); + final CountDownLatch completionLatch = new CountDownLatch(2); + + Thread inserter = new Thread() { + + @Override + public void run() { + try { + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, () -> { + assertNull("Correct initial value", localAccessStrategy.get(session, KEY, txTimestamp)); + + doInsert(localAccessStrategy, session, KEY, VALUE1); + + readLatch.countDown(); + commitLatch.await(); + return null; + }); + } catch (Exception e) { + log.error("node1 caught exception", e); + node1Exception = e; + } catch (AssertionFailedError e) { + node1Failure = e; + } finally { + + completionLatch.countDown(); + } + } + }; + + Thread reader = new Thread() { + @Override + public void run() { + try { + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, () -> { + readLatch.await(); + + assertNull("Correct initial value", localAccessStrategy.get(session, KEY, txTimestamp)); + return null; + }); + } catch (Exception e) { + log.error("node1 caught exception", e); + node1Exception = e; + } catch (AssertionFailedError e) { + node1Failure = e; + } finally { + commitLatch.countDown(); + completionLatch.countDown(); + } + } + }; + + inserter.setDaemon(true); + reader.setDaemon(true); + inserter.start(); + reader.start(); + + assertTrue("Threads completed", completionLatch.await(1000, TimeUnit.SECONDS)); + + assertThreadsRanCleanly(); + + long txTimestamp = System.currentTimeMillis(); + assertEquals("Correct node1 value", VALUE1, localAccessStrategy.get(mockedSession(), KEY, txTimestamp)); + Object expected = isUsingInvalidation() ? null : VALUE1; + assertEquals("Correct node2 value", expected, remoteAccessStrategy.get(mockedSession(), KEY, txTimestamp)); + } + + protected void doInsert(EntityRegionAccessStrategy strategy, SessionImplementor session, Object key, String value) { + strategy.insert(session, key, value, null); + session.getTransactionCoordinator().getLocalSynchronizations().registerSynchronization( + new TestSynchronization.AfterInsert(strategy, session, key, value)); + } + + @Test + public void testUpdate() throws Exception { + + final Object KEY = generateNextKey(); + + // Set up initial state + localAccessStrategy.putFromLoad(mockedSession(), KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); + remoteAccessStrategy.putFromLoad(mockedSession(), KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); + + // Let the async put propagate + sleep(250); + + final CountDownLatch readLatch = new CountDownLatch(1); + final CountDownLatch commitLatch = new CountDownLatch(1); + final CountDownLatch completionLatch = new CountDownLatch(2); + + Thread updater = new Thread("testUpdate-updater") { + + @Override + public void run() { + try { + long txTimestamp = System.currentTimeMillis(); + withTx(localEnvironment, mockedSession(), () -> { + log.debug("Transaction began, get initial value"); + assertEquals("Correct initial value", VALUE1, localAccessStrategy.get(mockedSession(), KEY, txTimestamp)); + log.debug("Now update value"); + doUpdate(AbstractEntityRegionAccessStrategyTest.this.localAccessStrategy, mockedSession(), KEY, VALUE2); + log.debug("Notify the read latch"); + readLatch.countDown(); + log.debug("Await commit"); + commitLatch.await(); + return null; + }); + } catch (Exception e) { + log.error("node1 caught exception", e); + node1Exception = e; + } catch (AssertionFailedError e) { + node1Failure = e; + } finally { + if (readLatch.getCount() > 0) { + readLatch.countDown(); + } + log.debug("Completion latch countdown"); + completionLatch.countDown(); + } + } + }; + + Thread reader = new Thread("testUpdate-reader") { + + @Override + public void run() { + try { + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, () -> { + log.debug("Transaction began, await read latch"); + readLatch.await(); + log.debug("Read latch acquired, verify local access strategy"); + + // This won't block w/ mvc and will read the old value + Object expected = VALUE1; + assertEquals("Correct value", expected, localAccessStrategy.get(session, KEY, txTimestamp)); + return null; + }); + } catch (Exception e) { + log.error("node1 caught exception", e); + node1Exception = e; + } catch (AssertionFailedError e) { + node1Failure = e; + } finally { + commitLatch.countDown(); + log.debug("Completion latch countdown"); + completionLatch.countDown(); + } + } + }; + + updater.setDaemon(true); + reader.setDaemon(true); + updater.start(); + reader.start(); + + // Should complete promptly + assertTrue(completionLatch.await(2, TimeUnit.SECONDS)); + + assertThreadsRanCleanly(); + + long txTimestamp = System.currentTimeMillis(); + assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(mockedSession(), KEY, txTimestamp)); + Object expected = isUsingInvalidation() ? null : VALUE2; + assertEquals("Correct node2 value", expected, remoteAccessStrategy.get(mockedSession(), KEY, txTimestamp)); + } + + protected void doUpdate(EntityRegionAccessStrategy strategy, SessionImplementor session, Object key, Object value) throws javax.transaction.RollbackException, javax.transaction.SystemException { + SoftLock softLock = strategy.lockItem(session, key, null); + strategy.update(session, key, value, null, null); + session.getTransactionCoordinator().getLocalSynchronizations().registerSynchronization( + new TestSynchronization.AfterUpdate(strategy, session, key, value, softLock)); + } + + @Test + public void testContestedPutFromLoad() throws Exception { + + final Object KEY = TestingKeyFactory.generateEntityCacheKey(KEY_BASE + testCount++); + + localAccessStrategy.putFromLoad(mockedSession(), KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); + + final CountDownLatch pferLatch = new CountDownLatch(1); + final CountDownLatch pferCompletionLatch = new CountDownLatch(1); + final CountDownLatch commitLatch = new CountDownLatch(1); + final CountDownLatch completionLatch = new CountDownLatch(1); + + Thread blocker = new Thread("Blocker") { + + @Override + public void run() { + + try { + SessionImplementor session = mockedSession(); + long txTimestamp = System.currentTimeMillis(); + withTx(localEnvironment, session, () -> { + assertEquals("Correct initial value", VALUE1, localAccessStrategy.get(session, KEY, txTimestamp)); + + doUpdate(localAccessStrategy, session, KEY, VALUE2); + + pferLatch.countDown(); + commitLatch.await(); + return null; + }); + } catch (Exception e) { + log.error("node1 caught exception", e); + node1Exception = e; + } catch (AssertionFailedError e) { + node1Failure = e; + } finally { + completionLatch.countDown(); + } + } + }; + + Thread putter = new Thread("Putter") { + + @Override + public void run() { + + try { + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, () -> { + localAccessStrategy.putFromLoad(session, KEY, VALUE1, txTimestamp, new Integer(1)); + return null; + }); + } catch (Exception e) { + log.error("node1 caught exception", e); + node1Exception = e; + } catch (AssertionFailedError e) { + node1Failure = e; + } finally { + pferCompletionLatch.countDown(); + } + } + }; + + blocker.start(); + assertTrue("Active tx has done an update", pferLatch.await(1, TimeUnit.SECONDS)); + putter.start(); + assertTrue("putFromLoadreturns promtly", pferCompletionLatch.await(10, TimeUnit.MILLISECONDS)); + + commitLatch.countDown(); + + assertTrue("Threads completed", completionLatch.await(1, TimeUnit.SECONDS)); + + assertThreadsRanCleanly(); + + long txTimestamp = System.currentTimeMillis(); + assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(null, KEY, txTimestamp)); + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTestCase.java deleted file mode 100644 index 3c18b1578b..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTestCase.java +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.entity; - -import java.util.Arrays; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import junit.framework.AssertionFailedError; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.infinispan.entity.EntityRegionImpl; -import org.hibernate.cache.infinispan.util.Caches; -import org.hibernate.cache.internal.CacheDataDescriptionImpl; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.internal.util.compare.ComparableComparator; -import org.hibernate.test.cache.infinispan.AbstractNonFunctionalTestCase; -import org.hibernate.test.cache.infinispan.NodeEnvironment; -import org.hibernate.test.cache.infinispan.util.BatchModeTransactionCoordinator; -import org.hibernate.test.cache.infinispan.util.CacheTestUtil; -import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; -import org.infinispan.Cache; -import org.infinispan.test.TestingUtil; -import org.infinispan.transaction.tm.BatchModeTransactionManager; -import org.jboss.logging.Logger; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * Base class for tests of EntityRegionAccessStrategy impls. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public abstract class AbstractEntityRegionAccessStrategyTestCase extends AbstractNonFunctionalTestCase { - - private static final Logger log = Logger.getLogger(AbstractEntityRegionAccessStrategyTestCase.class); - - @Rule - public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - - public static final String REGION_NAME = "test/com.foo.test"; - public static final String KEY_BASE = "KEY"; - public static final String VALUE1 = "VALUE1"; - public static final String VALUE2 = "VALUE2"; - - protected static int testCount; - - protected NodeEnvironment localEnvironment; - protected EntityRegionImpl localEntityRegion; - protected EntityRegionAccessStrategy localAccessStrategy; - protected SessionImplementor localSession; - - protected NodeEnvironment remoteEnvironment; - protected EntityRegionImpl remoteEntityRegion; - protected EntityRegionAccessStrategy remoteAccessStrategy; - protected SessionImplementor remoteSession; - - protected boolean invalidation; - protected boolean synchronous; - - protected Exception node1Exception; - protected Exception node2Exception; - - protected AssertionFailedError node1Failure; - protected AssertionFailedError node2Failure; - - @Before - public void prepareResources() throws Exception { - // to mimic exactly the old code results, both environments here are exactly the same... - StandardServiceRegistryBuilder ssrb = createStandardServiceRegistryBuilder( getConfigurationName() ); - localEnvironment = new NodeEnvironment( ssrb ); - localEnvironment.prepare(); - - localEntityRegion = localEnvironment.getEntityRegion(REGION_NAME, getCacheDataDescription()); - localAccessStrategy = localEntityRegion.buildAccessStrategy(getAccessType()); - localSession = mock(SessionImplementor.class); - when(localSession.getTransactionCoordinator()).thenReturn(new BatchModeTransactionCoordinator()); - remoteSession = mock(SessionImplementor.class); - when(localSession.getTransactionCoordinator()).thenReturn(new BatchModeTransactionCoordinator()); - - invalidation = Caches.isInvalidationCache(localEntityRegion.getCache()); - synchronous = Caches.isSynchronousCache(localEntityRegion.getCache()); - - // Sleep a bit to avoid concurrent FLUSH problem - avoidConcurrentFlush(); - - remoteEnvironment = new NodeEnvironment( ssrb ); - remoteEnvironment.prepare(); - - remoteEntityRegion = remoteEnvironment.getEntityRegion(REGION_NAME, getCacheDataDescription()); - remoteAccessStrategy = remoteEntityRegion.buildAccessStrategy(getAccessType()); - - waitForClusterToForm(localEntityRegion.getCache(), - remoteEntityRegion.getCache()); - } - - protected void waitForClusterToForm(Cache... caches) { - TestingUtil.blockUntilViewsReceived(10000, Arrays.asList(caches)); - } - - protected abstract String getConfigurationName(); - - protected static StandardServiceRegistryBuilder createStandardServiceRegistryBuilder(String configName) { - StandardServiceRegistryBuilder ssrb = CacheTestUtil.buildBaselineStandardServiceRegistryBuilder( - REGION_PREFIX, - InfinispanRegionFactory.class, - true, - false - ); - ssrb.applySetting( InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, configName ); - return ssrb; - } - - protected CacheDataDescription getCacheDataDescription() { - return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE, null); - } - - @After - public void releaseResources() throws Exception { - try { - if (localEnvironment != null) { - localEnvironment.release(); - } - } finally { - if (remoteEnvironment != null) { - remoteEnvironment.release(); - } - } - } - - protected abstract AccessType getAccessType(); - - protected boolean isUsingInvalidation() { - return invalidation; - } - - protected boolean isSynchronous() { - return synchronous; - } - - protected void assertThreadsRanCleanly() { - if (node1Failure != null) { - throw node1Failure; - } - if (node2Failure != null) { - throw node2Failure; - } - - if (node1Exception != null) { - log.error("node1 saw an exception", node1Exception); - assertEquals("node1 saw no exceptions", null, node1Exception); - } - - if (node2Exception != null) { - log.error("node2 saw an exception", node2Exception); - assertEquals("node2 saw no exceptions", null, node2Exception); - } - } - - @Test - public abstract void testCacheConfiguration(); - - @Test - public void testGetRegion() { - assertEquals("Correct region", localEntityRegion, localAccessStrategy.getRegion()); - } - - @Test - public void testPutFromLoad() throws Exception { - putFromLoadTest(false); - } - - @Test - public void testPutFromLoadMinimal() throws Exception { - putFromLoadTest(true); - } - - /** - * Simulate 2 nodes, both start, tx do a get, experience a cache miss, then - * 'read from db.' First does a putFromLoad, then an update. Second tries to - * do a putFromLoad with stale data (i.e. it took longer to read from the db). - * Both commit their tx. Then both start a new tx and get. First should see - * the updated data; second should either see the updated data - * (isInvalidation() == false) or null (isInvalidation() == true). - * - * @param useMinimalAPI - * @throws Exception - */ - private void putFromLoadTest(final boolean useMinimalAPI) throws Exception { - - final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); - - final CountDownLatch writeLatch1 = new CountDownLatch(1); - final CountDownLatch writeLatch2 = new CountDownLatch(1); - final CountDownLatch completionLatch = new CountDownLatch(2); - - Thread node1 = new Thread() { - - @Override - public void run() { - - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - - assertNull("node1 starts clean", localAccessStrategy.get(localSession, KEY, txTimestamp)); - - writeLatch1.await(); - - if (useMinimalAPI) { - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, txTimestamp, new Integer(1), true); - } else { - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, txTimestamp, new Integer(1)); - } - - SoftLock softLock = localAccessStrategy.lockItem(localSession, KEY, null); - localAccessStrategy.update(localSession, KEY, VALUE2, new Integer(2), new Integer(1)); - localAccessStrategy.unlockItem(localSession, KEY, softLock); - - BatchModeTransactionManager.getInstance().commit(); - } catch (Exception e) { - log.error("node1 caught exception", e); - node1Exception = e; - rollback(); - } catch (AssertionFailedError e) { - node1Failure = e; - rollback(); - } finally { - // Let node2 write - writeLatch2.countDown(); - completionLatch.countDown(); - } - } - }; - - Thread node2 = new Thread() { - - @Override - public void run() { - - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - - assertNull("node1 starts clean", remoteAccessStrategy.get(remoteSession, KEY, txTimestamp)); - - // Let node1 write - writeLatch1.countDown(); - // Wait for node1 to finish - writeLatch2.await(); - - if (useMinimalAPI) { - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, txTimestamp, new Integer(1), true); - } else { - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, txTimestamp, new Integer(1)); - } - - BatchModeTransactionManager.getInstance().commit(); - } catch (Exception e) { - log.error("node2 caught exception", e); - node2Exception = e; - rollback(); - } catch (AssertionFailedError e) { - node2Failure = e; - rollback(); - } finally { - completionLatch.countDown(); - } - } - }; - - node1.setDaemon(true); - node2.setDaemon(true); - - node1.start(); - node2.start(); - - assertTrue("Threads completed", completionLatch.await(2000, TimeUnit.SECONDS)); - - assertThreadsRanCleanly(); - - long txTimestamp = System.currentTimeMillis(); - assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(localSession, KEY, txTimestamp)); - - if (isUsingInvalidation()) { - // invalidation command invalidates pending put - assertEquals("Expected node2 value", null, remoteAccessStrategy.get(remoteSession, KEY, txTimestamp)); - } else { - // The node1 update is replicated, preventing the node2 PFER - assertEquals("Correct node2 value", VALUE2, remoteAccessStrategy.get(remoteSession, KEY, txTimestamp)); - } - } - - @Test - public void testInsert() throws Exception { - - final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); - - final CountDownLatch readLatch = new CountDownLatch(1); - final CountDownLatch commitLatch = new CountDownLatch(1); - final CountDownLatch completionLatch = new CountDownLatch(2); - - Thread inserter = new Thread() { - - @Override - public void run() { - - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - - assertNull("Correct initial value", localAccessStrategy.get(localSession, KEY, txTimestamp)); - - localAccessStrategy.insert(localSession, KEY, VALUE1, new Integer(1)); - localAccessStrategy.afterInsert(localSession, KEY, VALUE1, null); - - readLatch.countDown(); - commitLatch.await(); - - BatchModeTransactionManager.getInstance().commit(); - } catch (Exception e) { - log.error("node1 caught exception", e); - node1Exception = e; - rollback(); - } catch (AssertionFailedError e) { - node1Failure = e; - rollback(); - } finally { - completionLatch.countDown(); - } - } - }; - - Thread reader = new Thread() { - - @Override - public void run() { - - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - - readLatch.await(); -// Object expected = !isBlockingReads() ? null : VALUE1; - Object expected = null; - - assertEquals( - "Correct initial value", expected, localAccessStrategy.get( - localSession, KEY, - txTimestamp - ) - ); - - BatchModeTransactionManager.getInstance().commit(); - } catch (Exception e) { - log.error("node1 caught exception", e); - node1Exception = e; - rollback(); - } catch (AssertionFailedError e) { - node1Failure = e; - rollback(); - } finally { - commitLatch.countDown(); - completionLatch.countDown(); - } - } - }; - - inserter.setDaemon(true); - reader.setDaemon(true); - inserter.start(); - reader.start(); - - assertTrue("Threads completed", completionLatch.await(1, TimeUnit.SECONDS)); - - assertThreadsRanCleanly(); - - long txTimestamp = System.currentTimeMillis(); - assertEquals("Correct node1 value", VALUE1, localAccessStrategy.get(localSession, KEY, txTimestamp)); - Object expected = isUsingInvalidation() ? null : VALUE1; - assertEquals("Correct node2 value", expected, remoteAccessStrategy.get(remoteSession, KEY, txTimestamp)); - } - - @Test - public void testUpdate() throws Exception { - - final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); - - // Set up initial state - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); - - // Let the async put propagate - sleep(250); - - final CountDownLatch readLatch = new CountDownLatch(1); - final CountDownLatch commitLatch = new CountDownLatch(1); - final CountDownLatch completionLatch = new CountDownLatch(2); - - Thread updater = new Thread("testUpdate-updater") { - - @Override - public void run() { - boolean readerUnlocked = false; - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - log.debug("Transaction began, get initial value"); - assertEquals("Correct initial value", VALUE1, localAccessStrategy.get(localSession, KEY, txTimestamp)); - log.debug("Now update value"); - SoftLock softLock = localAccessStrategy.lockItem(localSession, KEY, null); - localAccessStrategy.update(localSession, KEY, VALUE2, new Integer(2), new Integer(1)); - localAccessStrategy.unlockItem(localSession, KEY, softLock); - log.debug("Notify the read latch"); - readLatch.countDown(); - readerUnlocked = true; - log.debug("Await commit"); - commitLatch.await(); - BatchModeTransactionManager.getInstance().commit(); - } catch (Exception e) { - log.error("node1 caught exception", e); - node1Exception = e; - rollback(); - } catch (AssertionFailedError e) { - node1Failure = e; - rollback(); - } finally { - if (!readerUnlocked) { - readLatch.countDown(); - } - log.debug("Completion latch countdown"); - completionLatch.countDown(); - } - } - }; - - Thread reader = new Thread("testUpdate-reader") { - - @Override - public void run() { - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - log.debug("Transaction began, await read latch"); - readLatch.await(); - log.debug("Read latch acquired, verify local access strategy"); - - // This won't block w/ mvc and will read the old value - Object expected = VALUE1; - assertEquals("Correct value", expected, localAccessStrategy.get(localSession, KEY, txTimestamp)); - - BatchModeTransactionManager.getInstance().commit(); - } catch (Exception e) { - log.error("node1 caught exception", e); - node1Exception = e; - rollback(); - } catch (AssertionFailedError e) { - node1Failure = e; - rollback(); - } finally { - commitLatch.countDown(); - log.debug("Completion latch countdown"); - completionLatch.countDown(); - } - } - }; - - updater.setDaemon(true); - reader.setDaemon(true); - updater.start(); - reader.start(); - - // Should complete promptly - assertTrue(completionLatch.await(2, TimeUnit.SECONDS)); - - assertThreadsRanCleanly(); - - long txTimestamp = System.currentTimeMillis(); - assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(localSession, KEY, txTimestamp)); - Object expected = isUsingInvalidation() ? null : VALUE2; - assertEquals("Correct node2 value", expected, remoteAccessStrategy.get(remoteSession, KEY, txTimestamp)); - } - - @Test - public void testRemove() throws Exception { - evictOrRemoveTest(false); - } - - @Test - public void testRemoveAll() throws Exception { - evictOrRemoveAllTest(false); - } - - @Test - public void testEvict() throws Exception { - evictOrRemoveTest(true); - } - - @Test - public void testEvictAll() throws Exception { - evictOrRemoveAllTest(true); - } - - private void evictOrRemoveTest(final boolean evict) throws Exception { - final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); - assertEquals(0, localEntityRegion.getCache().size()); - assertEquals(0, remoteEntityRegion.getCache().size()); - - assertNull("local is clean", localAccessStrategy.get(localSession, KEY, System.currentTimeMillis())); - assertNull("remote is clean", remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); - assertEquals(VALUE1, localAccessStrategy.get(localSession, KEY, System.currentTimeMillis())); - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); - assertEquals(VALUE1, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - - Caches.withinTx(localEntityRegion.getTransactionManager(), new Callable() { - @Override - public Void call() throws Exception { - if (evict) { - localAccessStrategy.evict(KEY); - } - else { - SoftLock softLock = localAccessStrategy.lockItem(localSession, KEY, null); - localAccessStrategy.remove(localSession, KEY); - localAccessStrategy.unlockItem(localSession, KEY, softLock); - } - return null; - } - }); - assertEquals(null, localAccessStrategy.get(localSession, KEY, System.currentTimeMillis())); - assertEquals(0, localEntityRegion.getCache().size()); - assertEquals(null, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - assertEquals(0, remoteEntityRegion.getCache().size()); - } - - private void evictOrRemoveAllTest(final boolean evict) throws Exception { - final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); - assertEquals(0, localEntityRegion.getCache().size()); - assertEquals(0, remoteEntityRegion.getCache().size()); - assertNull("local is clean", localAccessStrategy.get(localSession, KEY, System.currentTimeMillis())); - assertNull("remote is clean", remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); - assertEquals(VALUE1, localAccessStrategy.get(localSession, KEY, System.currentTimeMillis())); - - // Wait for async propagation - sleep(250); - - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); - assertEquals(VALUE1, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - - // Wait for async propagation - sleep(250); - - Caches.withinTx(localEntityRegion.getTransactionManager(), new Callable() { - @Override - public Void call() throws Exception { - if (evict) { - log.debug("Call evict all locally"); - localAccessStrategy.evictAll(); - } else { - SoftLock softLock = localAccessStrategy.lockRegion(); - localAccessStrategy.removeAll(); - localAccessStrategy.unlockRegion(softLock); - } - return null; - } - }); - - // This should re-establish the region root node in the optimistic case - assertNull(localAccessStrategy.get(localSession, KEY, System.currentTimeMillis())); - assertEquals(0, localEntityRegion.getCache().size()); - - // Re-establishing the region root on the local node doesn't - // propagate it to other nodes. Do a get on the remote node to re-establish - assertNull(remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - assertEquals(0, remoteEntityRegion.getCache().size()); - - // Wait for async propagation of EndInvalidationCommand before executing naked put - sleep(250); - - // Test whether the get above messes up the optimistic version - remoteAccessStrategy.putFromLoad(remoteSession, KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); - assertEquals(VALUE1, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - assertEquals(1, remoteEntityRegion.getCache().size()); - - // Wait for async propagation - sleep(250); - - assertEquals( - "local is correct", (isUsingInvalidation() ? null : VALUE1), localAccessStrategy - .get(localSession, KEY, System.currentTimeMillis()) - ); - assertEquals( - "remote is correct", VALUE1, remoteAccessStrategy.get( - remoteSession, KEY, System - .currentTimeMillis() - ) - ); - } - - protected void rollback() { - try { - BatchModeTransactionManager.getInstance().rollback(); - } catch (Exception e) { - log.error(e.getMessage(), e); - } - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractReadOnlyAccessTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractReadOnlyAccessTestCase.java deleted file mode 100644 index 06dedb6401..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractReadOnlyAccessTestCase.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.entity; - -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; -import org.infinispan.transaction.tm.BatchModeTransactionManager; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -/** - * Base class for tests of TRANSACTIONAL access. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public abstract class AbstractReadOnlyAccessTestCase extends AbstractEntityRegionAccessStrategyTestCase { - - @Override - protected AccessType getAccessType() { - return AccessType.READ_ONLY; - } - - @Test - @Override - public void testPutFromLoad() throws Exception { - putFromLoadTest(false); - } - - @Test - @Override - public void testPutFromLoadMinimal() throws Exception { - putFromLoadTest(true); - } - - private void putFromLoadTest(boolean minimal) throws Exception { - - final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); - - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - assertNull(localAccessStrategy.get(localSession, KEY, System.currentTimeMillis())); - if (minimal) - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, txTimestamp, 1, true); - else - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, txTimestamp, 1); - - sleep(250); - Object expected = isUsingInvalidation() ? null : VALUE1; - assertEquals(expected, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - - BatchModeTransactionManager.getInstance().commit(); - assertEquals(VALUE1, localAccessStrategy.get(localSession, KEY, System.currentTimeMillis())); - assertEquals(expected, remoteAccessStrategy.get(remoteSession, KEY, System.currentTimeMillis())); - } - - @Test(expected = UnsupportedOperationException.class) - @Override - public void testUpdate() throws Exception { - final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); - SoftLock softLock = localAccessStrategy.lockItem(localSession, KEY, null); - localAccessStrategy.update(localSession, KEY, VALUE2, 2, 1); - localAccessStrategy.unlockItem(localSession, KEY, softLock); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractTransactionalAccessTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractTransactionalAccessTestCase.java deleted file mode 100644 index d48faa844b..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractTransactionalAccessTestCase.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.entity; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import junit.framework.AssertionFailedError; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; -import org.infinispan.transaction.tm.BatchModeTransactionManager; -import org.jboss.logging.Logger; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -/** - * Base class for tests of TRANSACTIONAL access. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public abstract class AbstractTransactionalAccessTestCase extends AbstractEntityRegionAccessStrategyTestCase { - private static final Logger log = Logger.getLogger( AbstractTransactionalAccessTestCase.class ); - - @Override - protected AccessType getAccessType() { - return AccessType.TRANSACTIONAL; - } - - public void testContestedPutFromLoad() throws Exception { - - final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); - - localAccessStrategy.putFromLoad(localSession, KEY, VALUE1, System.currentTimeMillis(), new Integer(1)); - - final CountDownLatch pferLatch = new CountDownLatch(1); - final CountDownLatch pferCompletionLatch = new CountDownLatch(1); - final CountDownLatch commitLatch = new CountDownLatch(1); - final CountDownLatch completionLatch = new CountDownLatch(1); - - Thread blocker = new Thread("Blocker") { - - @Override - public void run() { - - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - - assertEquals("Correct initial value", VALUE1, localAccessStrategy.get(localSession, KEY, txTimestamp)); - - SoftLock softLock = localAccessStrategy.lockItem(localSession, KEY, null); - localAccessStrategy.update(localSession, KEY, VALUE2, new Integer(2), new Integer(1)); - localAccessStrategy.unlockItem(localSession, KEY, softLock); - - pferLatch.countDown(); - commitLatch.await(); - - BatchModeTransactionManager.getInstance().commit(); - } catch (Exception e) { - log.error("node1 caught exception", e); - node1Exception = e; - rollback(); - } catch (AssertionFailedError e) { - node1Failure = e; - rollback(); - } finally { - completionLatch.countDown(); - } - } - }; - - Thread putter = new Thread("Putter") { - - @Override - public void run() { - - try { - long txTimestamp = System.currentTimeMillis(); - BatchModeTransactionManager.getInstance().begin(); - - localAccessStrategy.putFromLoad(null, KEY, VALUE1, txTimestamp, new Integer(1)); - - BatchModeTransactionManager.getInstance().commit(); - } catch (Exception e) { - log.error("node1 caught exception", e); - node1Exception = e; - rollback(); - } catch (AssertionFailedError e) { - node1Failure = e; - rollback(); - } finally { - pferCompletionLatch.countDown(); - } - } - }; - - blocker.start(); - assertTrue("Active tx has done an update", pferLatch.await(1, TimeUnit.SECONDS)); - putter.start(); - assertTrue("putFromLoadreturns promtly", pferCompletionLatch.await(10, TimeUnit.MILLISECONDS)); - - commitLatch.countDown(); - - assertTrue("Threads completed", completionLatch.await(1, TimeUnit.SECONDS)); - - assertThreadsRanCleanly(); - - long txTimestamp = System.currentTimeMillis(); - assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(null, KEY, txTimestamp)); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionExtraAPITest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionExtraAPITest.java new file mode 100644 index 0000000000..d94542e9f6 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionExtraAPITest.java @@ -0,0 +1,88 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.entity; + +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; +import org.hibernate.test.cache.infinispan.AbstractExtraAPITest; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; + +/** + * Tests for the "extra API" in EntityRegionAccessStrategy;. + *

+ * By "extra API" we mean those methods that are superfluous to the + * function of the JBC integration, where the impl is a no-op or a static + * false return value, UnsupportedOperationException, etc. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public class EntityRegionExtraAPITest extends AbstractExtraAPITest { + public static final String VALUE1 = "VALUE1"; + public static final String VALUE2 = "VALUE2"; + + @Override + protected EntityRegionAccessStrategy getAccessStrategy() { + return environment.getEntityRegion( REGION_NAME, CACHE_DATA_DESCRIPTION).buildAccessStrategy( getAccessType() ); + } + + protected AccessType getAccessType() { + return AccessType.TRANSACTIONAL; + } + + @Test + @SuppressWarnings( {"UnnecessaryBoxing"}) + public void testAfterInsert() { + assertFalse("afterInsert always returns false", accessStrategy.afterInsert(SESSION, KEY, VALUE1, Integer.valueOf( 1 ))); + } + + @Test + @SuppressWarnings( {"UnnecessaryBoxing"}) + public void testAfterUpdate() { + assertFalse("afterInsert always returns false", accessStrategy.afterUpdate( + SESSION, KEY, VALUE2, Integer.valueOf( 1 ), Integer.valueOf( 2 ), new MockSoftLock())); + } + + public static class Transactional extends EntityRegionExtraAPITest { + @Override + protected AccessType getAccessType() { + return AccessType.TRANSACTIONAL; + } + + @Override + protected Class getRegionFactoryClass() { + return TestInfinispanRegionFactory.Transactional.class; + } + } + + public static class ReadWrite extends EntityRegionExtraAPITest { + @Override + protected AccessType getAccessType() { + return AccessType.READ_WRITE; + } + } + + + public static class ReadOnly extends EntityRegionExtraAPITest { + @Override + protected AccessType getAccessType() { + return AccessType.READ_ONLY; + } + + @Test(expected = UnsupportedOperationException.class) + @Override + public void testAfterUpdate() { + accessStrategy.afterUpdate(null, KEY, VALUE2, 1, 2, new MockSoftLock()); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTest.java new file mode 100644 index 0000000000..7a60a26b83 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTest.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.entity; + +import java.util.Properties; + +import org.hibernate.cache.CacheException; +import org.hibernate.cache.infinispan.InfinispanRegionFactory; +import org.hibernate.cache.spi.CacheDataDescription; +import org.hibernate.cache.spi.EntityRegion; +import org.hibernate.cache.spi.Region; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.test.cache.infinispan.AbstractEntityCollectionRegionTest; +import org.infinispan.AdvancedCache; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +/** + * Tests of EntityRegionImpl. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public class EntityRegionImplTest extends AbstractEntityCollectionRegionTest { + + @Override + protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) { + EntityRegion region = regionFactory.buildEntityRegion("test", properties, MUTABLE_NON_VERSIONED); + assertNotNull(region.buildAccessStrategy(AccessType.READ_ONLY)); + assertNotNull(region.buildAccessStrategy(AccessType.READ_WRITE)); + assertNotNull(region.buildAccessStrategy(AccessType.TRANSACTIONAL)); + try { + region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE); + fail("Incorrectly got NONSTRICT_READ_WRITE"); + } catch (CacheException good) { + } + } + + @Override + protected void putInRegion(Region region, Object key, Object value) { + ((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).insert(null, key, value, 1); + } + + @Override + protected void removeFromRegion(Region region, Object key) { + ((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).remove(null, key); + } + + @Override + protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) { + return regionFactory.buildEntityRegion(regionName, properties, cdd); + } + + @Override + protected AdvancedCache getInfinispanCache(InfinispanRegionFactory regionFactory) { + return regionFactory.getCacheManager().getCache( + InfinispanRegionFactory.DEF_ENTITY_RESOURCE).getAdvancedCache(); + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTestCase.java deleted file mode 100644 index 76023f9f81..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTestCase.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.entity; - -import java.util.Properties; - -import org.hibernate.cache.CacheException; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.EntityRegion; -import org.hibernate.cache.spi.Region; -import org.hibernate.cache.spi.RegionFactory; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.test.cache.infinispan.AbstractEntityCollectionRegionTestCase; -import org.infinispan.AdvancedCache; - -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -/** - * Tests of EntityRegionImpl. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class EntityRegionImplTestCase extends AbstractEntityCollectionRegionTestCase { - - @Override - protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) { - EntityRegion region = regionFactory.buildEntityRegion("test", properties, MUTABLE_NON_VERSIONED); - assertNull("Got TRANSACTIONAL", - region.buildAccessStrategy(AccessType.TRANSACTIONAL).lockRegion()); - try { - region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE); - fail("Incorrectly got NONSTRICT_READ_WRITE"); - } catch (CacheException good) { - } - - try { - region.buildAccessStrategy(AccessType.READ_WRITE); - fail("Incorrectly got READ_WRITE"); - } catch (CacheException good) { - } - } - - @Override - protected void putInRegion(Region region, Object key, Object value) { - ((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).insert(null, key, value, 1); - } - - @Override - protected void removeFromRegion(Region region, Object key) { - ((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).remove(null, key); - } - - @Override - protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) { - return regionFactory.buildEntityRegion(regionName, properties, cdd); - } - - @Override - protected AdvancedCache getInfinispanCache(InfinispanRegionFactory regionFactory) { - return regionFactory.getCacheManager().getCache( - InfinispanRegionFactory.DEF_ENTITY_RESOURCE).getAdvancedCache(); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionReadOnlyAccessTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionReadOnlyAccessTest.java new file mode 100644 index 0000000000..005e7797cd --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionReadOnlyAccessTest.java @@ -0,0 +1,77 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.entity; + +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; +import org.infinispan.transaction.tm.BatchModeTransactionManager; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Base class for tests of TRANSACTIONAL access. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public abstract class EntityRegionReadOnlyAccessTest extends AbstractEntityRegionAccessStrategyTest { + + @Override + protected AccessType getAccessType() { + return AccessType.READ_ONLY; + } + + + protected void putFromLoadTest(boolean minimal) throws Exception { + final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); + + Object expected = isUsingInvalidation() ? null : VALUE1; + + long txTimestamp = System.currentTimeMillis(); + SessionImplementor session = mockedSession(); + withTx(localEnvironment, session, () -> { + assertNull(localAccessStrategy.get(session, KEY, System.currentTimeMillis())); + if (minimal) + localAccessStrategy.putFromLoad(session, KEY, VALUE1, txTimestamp, 1, true); + else + localAccessStrategy.putFromLoad(session, KEY, VALUE1, txTimestamp, 1); + return null; + }); + + assertEquals(VALUE1, localAccessStrategy.get(session, KEY, System.currentTimeMillis())); + assertEquals(expected, remoteAccessStrategy.get(mockedSession(), KEY, System.currentTimeMillis())); + } + + @Test(expected = UnsupportedOperationException.class) + @Override + public void testUpdate() throws Exception { + final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ ); + SessionImplementor session = mockedSession(); + SoftLock softLock = localAccessStrategy.lockItem(session, KEY, null); + localAccessStrategy.update(session, KEY, VALUE2, 2, 1); + localAccessStrategy.unlockItem(session, KEY, softLock); + } + + @Ignore + @Override + public void testContestedPutFromLoad() throws Exception { + } + + public static class Invalidation extends EntityRegionReadOnlyAccessTest { + @Test + @Override + public void testCacheConfiguration() { + assertTrue("Using Invalidation", isUsingInvalidation()); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionTransactionalAccessTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionTransactionalAccessTest.java new file mode 100644 index 0000000000..4bb3e502a2 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionTransactionalAccessTest.java @@ -0,0 +1,57 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.entity; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import junit.framework.AssertionFailedError; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; +import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; +import org.infinispan.transaction.tm.BatchModeTransactionManager; +import org.jboss.logging.Logger; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Base class for tests of TRANSACTIONAL access. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public abstract class EntityRegionTransactionalAccessTest extends AbstractEntityRegionAccessStrategyTest { + private static final Logger log = Logger.getLogger( EntityRegionTransactionalAccessTest.class ); + + @Override + protected AccessType getAccessType() { + return AccessType.TRANSACTIONAL; + } + + @Override + protected Class getRegionFactoryClass() { + return TestInfinispanRegionFactory.Transactional.class; + } + + /** + * @author Galder Zamarreño + */ + public static class Invalidation extends EntityRegionTransactionalAccessTest { + @Test + @Override + public void testCacheConfiguration() { + assertTrue(isTransactional()); + assertTrue("Using Invalidation", isUsingInvalidation()); + assertTrue("Synchronous mode", isSynchronous()); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/InvalidatedTransactionalTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/InvalidatedTransactionalTestCase.java deleted file mode 100644 index 6065a15492..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/InvalidatedTransactionalTestCase.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.entity; - -import org.junit.Test; - -import static org.junit.Assert.assertTrue; - -/** - * InvalidatedTransactionalTestCase. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class InvalidatedTransactionalTestCase extends AbstractTransactionalAccessTestCase { - @Test - @Override - public void testCacheConfiguration() { - assertTrue("Using Invalidation", isUsingInvalidation()); - assertTrue("Synchronous mode", isSynchronous()); - } - - @Override - protected String getConfigurationName() { - return "entity"; - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/ReadOnlyExtraAPITestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/ReadOnlyExtraAPITestCase.java deleted file mode 100644 index 148cc5dbd4..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/ReadOnlyExtraAPITestCase.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.entity; - -import org.hibernate.cache.spi.access.AccessType; -import org.junit.Test; - -/** - * Tests for the "extra API" in EntityRegionAccessStrategy; - *

- * By "extra API" we mean those methods that are superfluous to the - * function of the Infinispan integration, where the impl is a no-op or a static - * false return value, UnsupportedOperationException, etc. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class ReadOnlyExtraAPITestCase extends TransactionalExtraAPITestCase { - @Override - protected AccessType getAccessType() { - return AccessType.READ_ONLY; - } - - @Test(expected = UnsupportedOperationException.class) - @Override - public void testAfterUpdate() { - getEntityAccessStrategy().afterUpdate(null, KEY, VALUE2, 1, 2, new MockSoftLock()); - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/ReadOnlyTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/ReadOnlyTestCase.java deleted file mode 100644 index 5216c4fa9d..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/ReadOnlyTestCase.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.entity; - -import org.junit.Test; - -import static org.junit.Assert.assertTrue; - -/** - * Tests READ_ONLY access when pessimistic locking and invalidation are used. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class ReadOnlyTestCase extends AbstractReadOnlyAccessTestCase { - @Override - protected String getConfigurationName() { - return "entity"; - } - - @Test - @Override - public void testCacheConfiguration() { - assertTrue("Using Invalidation", isUsingInvalidation()); - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/TransactionalExtraAPITestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/TransactionalExtraAPITestCase.java deleted file mode 100644 index 5e462fc8e7..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/TransactionalExtraAPITestCase.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.entity; - -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.internal.CacheDataDescriptionImpl; -import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; -import org.hibernate.cache.spi.access.SoftLock; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.internal.util.compare.ComparableComparator; -import org.hibernate.test.cache.infinispan.AbstractNonFunctionalTestCase; -import org.hibernate.test.cache.infinispan.NodeEnvironment; -import org.hibernate.test.cache.infinispan.util.CacheTestUtil; -import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.hibernate.test.cache.infinispan.util.TestingKeyFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.mock; - -/** - * Tests for the "extra API" in EntityRegionAccessStrategy;. - *

- * By "extra API" we mean those methods that are superfluous to the - * function of the JBC integration, where the impl is a no-op or a static - * false return value, UnsupportedOperationException, etc. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class TransactionalExtraAPITestCase extends AbstractNonFunctionalTestCase { - - @Rule - public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - - public static final String REGION_NAME = "test/com.foo.test"; - public static final Object KEY = TestingKeyFactory.generateEntityCacheKey( "KEY" ); - public static final String VALUE1 = "VALUE1"; - public static final String VALUE2 = "VALUE2"; - protected static final CacheDataDescriptionImpl CACHE_DATA_DESCRIPTION - = new CacheDataDescriptionImpl(true, false, ComparableComparator.INSTANCE, null); - private static final SessionImplementor SESSION = mock(SessionImplementor.class); - - private NodeEnvironment environment; - private EntityRegionAccessStrategy accessStrategy; - - @Before - public final void prepareLocalAccessStrategy() throws Exception { - environment = new NodeEnvironment( createStandardServiceRegistryBuilder() ); - environment.prepare(); - - // Sleep a bit to avoid concurrent FLUSH problem - avoidConcurrentFlush(); - - accessStrategy = environment.getEntityRegion( REGION_NAME, CACHE_DATA_DESCRIPTION).buildAccessStrategy( getAccessType() ); - } - - protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() { - StandardServiceRegistryBuilder ssrb = CacheTestUtil.buildBaselineStandardServiceRegistryBuilder( - REGION_PREFIX, - InfinispanRegionFactory.class, - true, - false - ); - ssrb.applySetting( InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, getCacheConfigName() ); - return ssrb; - } - - @After - public final void releaseLocalAccessStrategy() throws Exception { - if ( environment != null ) { - environment.release(); - } - } - - protected final EntityRegionAccessStrategy getEntityAccessStrategy() { - return accessStrategy; - } - - protected String getCacheConfigName() { - return "entity"; - } - - protected AccessType getAccessType() { - return AccessType.TRANSACTIONAL; - } - - @Test - @SuppressWarnings( {"UnnecessaryBoxing"}) - public void testLockItem() { - assertNull( getEntityAccessStrategy().lockItem(SESSION, KEY, Integer.valueOf( 1 ) ) ); - } - - @Test - public void testLockRegion() { - assertNull( getEntityAccessStrategy().lockRegion() ); - } - - @Test - public void testUnlockItem() { - getEntityAccessStrategy().unlockItem(SESSION, KEY, new MockSoftLock() ); - } - - @Test - public void testUnlockRegion() { - getEntityAccessStrategy().unlockItem(SESSION, KEY, new MockSoftLock() ); - } - - @Test - @SuppressWarnings( {"UnnecessaryBoxing"}) - public void testAfterInsert() { - assertFalse( - "afterInsert always returns false", - getEntityAccessStrategy().afterInsert(SESSION, - KEY, - VALUE1, - Integer.valueOf( 1 ) - ) - ); - } - - @Test - @SuppressWarnings( {"UnnecessaryBoxing"}) - public void testAfterUpdate() { - assertFalse( - "afterInsert always returns false", - getEntityAccessStrategy().afterUpdate(SESSION, - KEY, - VALUE2, - Integer.valueOf( 1 ), - Integer.valueOf( 2 ), - new MockSoftLock() - ) - ); - } - - public static class MockSoftLock implements SoftLock { - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTest.java new file mode 100644 index 0000000000..3e11e35331 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTest.java @@ -0,0 +1,122 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.hibernate.Session; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; +import org.hibernate.resource.transaction.TransactionCoordinatorBuilder; +import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl; +import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; + +import org.hibernate.test.cache.infinispan.tm.XaConnectionProvider; +import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; +import org.hibernate.test.cache.infinispan.util.TxUtil; +import org.hibernate.testing.BeforeClassOnce; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.test.cache.infinispan.tm.JtaPlatformImpl; + +import org.hibernate.testing.junit4.CustomParameterized; +import org.infinispan.util.logging.Log; +import org.infinispan.util.logging.LogFactory; +import org.junit.ClassRule; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/** + * @author Galder Zamarreño + * @since 3.5 + */ +@RunWith(CustomParameterized.class) +public abstract class AbstractFunctionalTest extends BaseNonConfigCoreFunctionalTestCase { + private static final Log log = LogFactory.getLog( AbstractFunctionalTest.class ); + + protected static final Object[] TRANSACTIONAL = new Object[]{"transactional", JtaPlatformImpl.class, JtaTransactionCoordinatorBuilderImpl.class, XaConnectionProvider.class, AccessType.TRANSACTIONAL, TestInfinispanRegionFactory.Transactional.class}; + protected static final Object[] READ_WRITE = new Object[]{"read-write", null, JdbcResourceLocalTransactionCoordinatorBuilderImpl.class, null, AccessType.READ_WRITE, TestInfinispanRegionFactory.class}; + protected static final Object[] READ_ONLY = new Object[]{"read-only", null, JdbcResourceLocalTransactionCoordinatorBuilderImpl.class, null, AccessType.READ_ONLY, TestInfinispanRegionFactory.class}; + + @ClassRule + public static final InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + + @Parameterized.Parameter(value = 0) + public String mode; + + @Parameterized.Parameter(value = 1) + public Class jtaPlatformClass; + + @Parameterized.Parameter(value = 2) + public Class transactionCoordinatorBuilderClass; + + @Parameterized.Parameter(value = 3) + public Class connectionProviderClass; + + @Parameterized.Parameter(value = 4) + public AccessType accessType; + + @Parameterized.Parameter(value = 5) + public Class regionFactoryClass; + + protected boolean useJta; + + @Parameterized.Parameters(name = "{0}") + public abstract List getParameters(); + + @BeforeClassOnce + public void setUseJta() { + useJta = jtaPlatformClass != null; + } + + @Override + public String[] getMappings() { + return new String[] { + "cache/infinispan/functional/entities/Item.hbm.xml", + "cache/infinispan/functional/entities/Customer.hbm.xml", + "cache/infinispan/functional/entities/Contact.hbm.xml" + }; + } + + @Override + public String getCacheConcurrencyStrategy() { + return accessType.getExternalName(); + } + + protected boolean getUseQueryCache() { + return true; + } + + @Override + @SuppressWarnings("unchecked") + protected void addSettings(Map settings) { + super.addSettings( settings ); + + settings.put( Environment.USE_SECOND_LEVEL_CACHE, "true" ); + settings.put( Environment.GENERATE_STATISTICS, "true" ); + settings.put( Environment.USE_QUERY_CACHE, String.valueOf( getUseQueryCache() ) ); + settings.put( Environment.CACHE_REGION_FACTORY, regionFactoryClass.getName() ); + + if ( jtaPlatformClass != null ) { + settings.put( AvailableSettings.JTA_PLATFORM, jtaPlatformClass.getName() ); + } + settings.put( Environment.TRANSACTION_COORDINATOR_STRATEGY, transactionCoordinatorBuilderClass.getName() ); + if ( connectionProviderClass != null) { + settings.put(Environment.CONNECTION_PROVIDER, connectionProviderClass.getName()); + } + } + + protected void markRollbackOnly(Session session) { + TxUtil.markRollbackOnly(useJta, session); + } +} \ No newline at end of file diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java deleted file mode 100644 index ed9436e10e..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional; - -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.Phaser; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.hibernate.PessimisticLockException; -import org.hibernate.Session; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.infinispan.entity.EntityRegionImpl; -import org.hibernate.cache.spi.Region; -import org.hibernate.stat.SecondLevelCacheStatistics; -import org.hibernate.stat.Statistics; -import org.hibernate.testing.TestForIssue; -import org.infinispan.AdvancedCache; -import org.infinispan.commands.read.GetKeyValueCommand; -import org.infinispan.context.InvocationContext; -import org.infinispan.interceptors.base.BaseCustomInterceptor; -import org.infinispan.util.logging.Log; -import org.infinispan.util.logging.LogFactory; -import org.junit.Test; - -import static org.infinispan.test.TestingUtil.withTx; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -/** - * Parent tests for both transactional and - * read-only tests are defined in this class. - * - * @author Galder Zamarreño - * @since 4.1 - */ -public abstract class AbstractFunctionalTestCase extends SingleNodeTestCase { - - static final Log log = LogFactory.getLog(AbstractFunctionalTestCase.class); - - @Test - public void testEmptySecondLevelCacheEntry() throws Exception { - sessionFactory().getCache().evictCollectionRegion( Item.class.getName() + ".items" ); - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); - Map cacheEntries = statistics.getEntries(); - assertEquals( 0, cacheEntries.size() ); - } - - @Test - public void testInsertDeleteEntity() throws Exception { - final Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - - final Item item = new Item( "chris", "Chris's Item" ); - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - s.persist(item); - s.getTransaction().commit(); - s.close(); - return null; - } - }); - - log.info("Entry persisted, let's load and delete it."); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - Item found = (Item) s.load(Item.class, item.getId()); - log.info(stats.toString()); - assertEquals(item.getDescription(), found.getDescription()); - assertEquals(0, stats.getSecondLevelCacheMissCount()); - assertEquals(1, stats.getSecondLevelCacheHitCount()); - s.delete(found); - s.getTransaction().commit(); - s.close(); - return null; - } - }); - } - - @Test - public void testInsertClearCacheDeleteEntity() throws Exception { - final Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - - final Item item = new Item( "chris", "Chris's Item" ); - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - s.persist(item); - s.getTransaction().commit(); - assertEquals(0, stats.getSecondLevelCacheMissCount()); - assertEquals(0, stats.getSecondLevelCacheHitCount()); - assertEquals(1, stats.getSecondLevelCachePutCount()); - s.close(); - return null; - } - }); - - log.info("Entry persisted, let's load and delete it."); - - cleanupCache(); - Thread.sleep(10); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - Item found = (Item) s.load(Item.class, item.getId()); - log.info(stats.toString()); - assertEquals(item.getDescription(), found.getDescription()); - assertEquals(1, stats.getSecondLevelCacheMissCount()); - assertEquals(0, stats.getSecondLevelCacheHitCount()); - assertEquals(2, stats.getSecondLevelCachePutCount()); - s.delete(found); - s.getTransaction().commit(); - s.close(); - return null; - } - }); - } - - @Test - @TestForIssue(jiraKey = "HHH-9868") - public void testConcurrentRemoveAndPutFromLoad() throws Exception { - final Item item = new Item( "chris", "Chris's Item" ); - - withTx(tm, () -> { - Session s = openSession(); - s.getTransaction().begin(); - s.persist(item); - s.getTransaction().commit(); - s.close(); - return null; - }); - Region region = sessionFactory().getSecondLevelCacheRegion(Item.class.getName()); - - Phaser deletePhaser = new Phaser(2); - Phaser getPhaser = new Phaser(2); - HookInterceptor hook = new HookInterceptor(); - - AdvancedCache entityCache = ((EntityRegionImpl) region).getCache(); - AdvancedCache pendingPutsCache = entityCache.getCacheManager().getCache( - entityCache.getName() + "-" + InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME).getAdvancedCache(); - pendingPutsCache.addInterceptor(hook, 0); - - Thread deleteThread = new Thread(() -> { - try { - withTx(tm, () -> { - Session s = openSession(); - log.trace("Session opened"); - s.getTransaction().begin(); - log.trace("TX started"); - Item loadedItem = s.get(Item.class, item.getId()); - assertNotNull(loadedItem); - arriveAndAwait(deletePhaser); - arriveAndAwait(deletePhaser); - log.trace("Item loaded"); - s.delete(loadedItem); - log.trace("Item deleted"); - s.getTransaction().commit(); - log.trace("TX committed"); - // start get-thread here - arriveAndAwait(deletePhaser); - arriveAndAwait(deletePhaser); - s.close(); - log.trace("Session closed"); - return null; - }); - } catch (Exception e) { - throw new RuntimeException(e); - } - }, "delete-thread"); - Thread getThread = new Thread(() -> { - try { - withTx(tm, () -> { - Session s = openSession(); - log.trace("Session opened"); - s.getTransaction().begin(); - log.trace("TX started"); - // DB load should happen before the record is deleted, - // putFromLoad should happen after deleteThread ends - Item loadedItem = s.get(Item.class, item.getId()); - assertNotNull(loadedItem); - s.close(); - log.trace("Session closed"); - return null; - }); - } catch (PessimisticLockException e) { - // If we end up here, database locks guard us against situation tested - // in this case and HHH-9868 cannot happen. - // (delete-thread has ITEMS table write-locked and we try to acquire read-lock) - try { - arriveAndAwait(getPhaser); - arriveAndAwait(getPhaser); - } catch (Exception e1) { - throw new RuntimeException(e1); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - }, "get-thread"); - - deleteThread.start(); - // deleteThread loads the entity - arriveAndAwait(deletePhaser); - withTx(tm, () -> { - sessionFactory().getCache().evictEntity(Item.class, item.getId()); - assertFalse(sessionFactory().getCache().containsEntity(Item.class, item.getId())); - return null; - }); - arriveAndAwait(deletePhaser); - // delete thread invalidates PFER - arriveAndAwait(deletePhaser); - // get thread gets the entity from DB - hook.block(getPhaser, getThread); - getThread.start(); - arriveAndAwait(getPhaser); - arriveAndAwait(deletePhaser); - // delete thread finishes the remove from DB and cache - deleteThread.join(); - hook.unblock(); - arriveAndAwait(getPhaser); - // get thread puts the entry into cache - getThread.join(); - - withTx(tm, () -> { - Session s = openSession(); - s.getTransaction().begin(); - Item loadedItem = s.get(Item.class, item.getId()); - assertNull(loadedItem); - s.getTransaction().commit(); - s.close(); - return null; - }); - } - - protected static void arriveAndAwait(Phaser phaser) throws TimeoutException, InterruptedException { - phaser.awaitAdvanceInterruptibly(phaser.arrive(), 10, TimeUnit.SECONDS); - } - - private static class HookInterceptor extends BaseCustomInterceptor { - Phaser phaser; - Thread thread; - - public synchronized void block(Phaser phaser, Thread thread) { - this.phaser = phaser; - this.thread = thread; - } - - public synchronized void unblock() { - phaser = null; - thread = null; - } - - @Override - public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable { - Phaser phaser; - Thread thread; - synchronized (this) { - phaser = this.phaser; - thread = this.thread; - } - if (phaser != null && Thread.currentThread() == thread) { - arriveAndAwait(phaser); - arriveAndAwait(phaser); - } - return super.visitGetKeyValueCommand(ctx, command); - } - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java deleted file mode 100644 index bf24701d19..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional; - -/** - * Functional entity read-only tests. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class BasicReadOnlyTestCase extends AbstractFunctionalTestCase { - - @Override - public String getCacheConcurrencyStrategy() { - return "read-only"; - } - -} \ No newline at end of file diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java deleted file mode 100644 index f1e5b95ffe..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java +++ /dev/null @@ -1,1141 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; - -import org.hibernate.Cache; -import org.hibernate.Criteria; -import org.hibernate.Hibernate; -import org.hibernate.NaturalIdLoadAccess; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.cache.spi.entry.CacheEntry; -import org.hibernate.criterion.Restrictions; -import org.hibernate.stat.SecondLevelCacheStatistics; -import org.hibernate.stat.Statistics; -import org.hibernate.testing.TestForIssue; -import org.junit.After; -import org.junit.Ignore; -import org.junit.Test; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static org.infinispan.test.TestingUtil.withTx; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * Functional entity transactional tests. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class BasicTransactionalTestCase extends AbstractFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Citizen.class, State.class, - NaturalIdOnManyToOne.class - }; - } - - @After - public void cleanupData() throws Exception { - super.cleanupCache(); - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = sessionFactory().openSession(); - s.beginTransaction(); - s.createQuery( "delete NaturalIdOnManyToOne" ).executeUpdate(); - s.createQuery( "delete Citizen" ).executeUpdate(); - s.createQuery( "delete State" ).executeUpdate(); - s.getTransaction().commit(); - s.close(); - return null; - } - }); - } - - @Test - public void testCollectionCache() throws Exception { - final Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - - final Item item = new Item( "chris", "Chris's Item" ); - final Item another = new Item( "another", "Owned Item" ); - item.addItem( another ); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - s.persist( item ); - s.persist( another ); - s.getTransaction().commit(); - s.close(); - return null; - } - }); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - Item loaded = (Item) s.load( Item.class, item.getId() ); - assertEquals( 1, loaded.getItems().size() ); - s.close(); - return null; - } - }); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); - Item loadedWithCachedCollection = (Item) s.load( Item.class, item.getId() ); - stats.logSummary(); - assertEquals( item.getName(), loadedWithCachedCollection.getName() ); - assertEquals( item.getItems().size(), loadedWithCachedCollection.getItems().size() ); - assertEquals( 1, cStats.getHitCount() ); - Map cacheEntries = cStats.getEntries(); - assertEquals( 1, cacheEntries.size() ); - Item itemElement = loadedWithCachedCollection.getItems().iterator().next(); - itemElement.setOwner( null ); - loadedWithCachedCollection.getItems().clear(); - s.delete( itemElement ); - s.delete( loadedWithCachedCollection ); - s.getTransaction().commit(); - s.close(); - return null; - } - }); - } - - @Test - @TestForIssue( jiraKey = "HHH-9231" ) - public void testAddNewOneToManyElementInitFlushLeaveCacheConsistent() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); - - Item item = null; - Transaction txn = null; - Session s = null; - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = new Item(); - item.setName( "steve" ); - item.setDescription( "steve's item" ); - s.save( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - // create an element for item.itsms - Item itemElement = new Item(); - itemElement.setName( "element" ); - itemElement.setDescription( "element item" ); - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = (Item) s.get( Item.class, item.getId() ); - assertFalse( Hibernate.isInitialized( item.getItems() ) ); - // Add an element to item.items (a Set); it will initialize the Set. - item.addItem( itemElement ); - assertTrue( Hibernate.isInitialized( item.getItems() ) ); - s.persist( itemElement ); - s.flush(); - setRollbackOnlyTx(); - } - catch (Exception e) { - setRollbackOnlyTxExpected(e); - } - finally { - commitOrRollbackTx(); - if ( s != null && s.isOpen() ) { - try { - s.close(); - } - catch (Throwable ignore) { - } - } - } - - beginTx(); - try { - // cleanup - s = openSession(); - txn = s.beginTransaction(); - item = (Item) s.get( Item.class, item.getId() ); - Hibernate.initialize( item.getItems() ); - assertTrue( item.getItems().isEmpty() ); - s.delete( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - @TestForIssue( jiraKey = "HHH-9231" ) - public void testAddNewOneToManyElementNoInitFlushLeaveCacheConsistent() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); - - Item item = null; - Transaction txn = null; - Session s = null; - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = new Item(); - item.setName( "steve" ); - item.setDescription( "steve's item" ); - s.save( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - // create an element for item.bagOfItems - Item itemElement = new Item(); - itemElement.setName( "element" ); - itemElement.setDescription( "element item" ); - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = (Item) s.get( Item.class, item.getId() ); - assertFalse( Hibernate.isInitialized( item.getItems() ) ); - // Add an element to item.bagOfItems (a bag); it will not initialize the bag. - item.addItemToBag( itemElement ); - assertFalse( Hibernate.isInitialized( item.getBagOfItems() ) ); - s.persist( itemElement ); - s.flush(); - setRollbackOnlyTx(); - } - catch (Exception e) { - setRollbackOnlyTxExpected(e); - } - finally { - commitOrRollbackTx(); - if ( s != null && s.isOpen() ) { - try { - s.close(); - } - catch (Throwable ignore) { - } - } - } - - beginTx(); - try { - // cleanup - s = openSession(); - txn = s.beginTransaction(); - item = (Item) s.get( Item.class, item.getId() ); - Hibernate.initialize( item.getItems() ); - assertTrue( item.getItems().isEmpty() ); - s.delete( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - public void testAddNewOneToManyElementNoInitFlushInitLeaveCacheConsistent() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); - - Item item = null; - Transaction txn = null; - Session s = null; - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = new Item(); - item.setName( "steve" ); - item.setDescription( "steve's item" ); - s.save( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - // create an element for item.bagOfItems - Item itemElement = new Item(); - itemElement.setName( "element" ); - itemElement.setDescription( "element item" ); - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = (Item) s.get( Item.class, item.getId() ); - assertFalse( Hibernate.isInitialized( item.getBagOfItems() ) ); - // Add an element to item.bagOfItems (a bag); it will not initialize the bag. - item.addItemToBag( itemElement ); - assertFalse( Hibernate.isInitialized( item.getBagOfItems() ) ); - s.persist( itemElement ); - s.flush(); - // Now initialize the collection; it will contain the uncommitted itemElement. - Hibernate.initialize( item.getBagOfItems() ); - setRollbackOnlyTx(); - } - catch (Exception e) { - setRollbackOnlyTxExpected(e); - } - finally { - commitOrRollbackTx(); - if ( s != null && s.isOpen() ) { - try { - s.close(); - } - catch (Throwable ignore) { - } - } - } - - beginTx(); - try { - // cleanup - s = openSession(); - txn = s.beginTransaction(); - item = (Item) s.get( Item.class, item.getId() ); - // Because of HHH-9231, the following will fail due to ObjectNotFoundException because the - // collection will be read from the cache and it still contains the uncommitted element, - // which cannot be found. - Hibernate.initialize( item.getBagOfItems() ); - assertTrue( item.getBagOfItems().isEmpty() ); - s.delete( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - public void testAddNewManyToManyPropertyRefNoInitFlushInitLeaveCacheConsistent() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); - - OtherItem otherItem = null; - Transaction txn = null; - Session s = null; - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - otherItem = new OtherItem(); - otherItem.setName( "steve" ); - s.save( otherItem ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - // create an element for otherItem.bagOfItems - Item item = new Item(); - item.setName( "element" ); - item.setDescription( "element Item" ); - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - otherItem = (OtherItem) s.get( OtherItem.class, otherItem.getId() ); - assertFalse( Hibernate.isInitialized( otherItem.getBagOfItems() ) ); - // Add an element to otherItem.bagOfItems (a bag); it will not initialize the bag. - otherItem.addItemToBag( item ); - assertFalse( Hibernate.isInitialized( otherItem.getBagOfItems() ) ); - s.persist( item ); - s.flush(); - // Now initialize the collection; it will contain the uncommitted itemElement. - // The many-to-many uses a property-ref - Hibernate.initialize( otherItem.getBagOfItems() ); - setRollbackOnlyTx(); - } - catch (Exception e) { - setRollbackOnlyTxExpected(e); - } - finally { - commitOrRollbackTx(); - if ( s != null && s.isOpen() ) { - try { - s.close(); - } - catch (Throwable ignore) { - } - } - } - - beginTx(); - try { - // cleanup - s = openSession(); - txn = s.beginTransaction(); - otherItem = (OtherItem) s.get( OtherItem.class, otherItem.getId() ); - // Because of HHH-9231, the following will fail due to ObjectNotFoundException because the - // collection will be read from the cache and it still contains the uncommitted element, - // which cannot be found. - Hibernate.initialize( otherItem.getBagOfItems() ); - assertTrue( otherItem.getBagOfItems().isEmpty() ); - s.delete( otherItem ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - public void testStaleWritesLeaveCacheConsistent() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - - VersionedItem item = null; - Transaction txn = null; - Session s = null; - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = new VersionedItem(); - item.setName( "steve" ); - item.setDescription( "steve's item" ); - s.save( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - Long initialVersion = item.getVersion(); - - // manually revert the version property - item.setVersion( new Long( item.getVersion().longValue() - 1 ) ); - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - s.update(item); - txn.commit(); - fail("expected stale write to fail"); - } - catch (Exception e) { - setRollbackOnlyTxExpected(e); - } - finally { - commitOrRollbackTx(); - if ( s != null && s.isOpen() ) { - try { - s.close(); - } - catch (Throwable ignore) { - } - } - } - - // check the version value in the cache... - SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( VersionedItem.class.getName() ); - - Object entry = slcs.getEntries().get( item.getId() ); - Long cachedVersionValue; - cachedVersionValue = (Long) ((CacheEntry) entry).getVersion(); - assertEquals(initialVersion.longValue(), cachedVersionValue.longValue()); - - beginTx(); - try { - // cleanup - s = openSession(); - txn = s.beginTransaction(); - item = (VersionedItem) s.load( VersionedItem.class, item.getId() ); - s.delete( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - @TestForIssue( jiraKey = "HHH-5690") - public void testPersistEntityFlushRollbackNotInEntityCache() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - - SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() ); - - Item item = null; - Transaction txn = null; - Session s = null; - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = new Item(); - item.setName( "steve" ); - item.setDescription( "steve's item" ); - s.persist( item ); - s.flush(); -// assertNotNull( slcs.getEntries().get( item.getId() ) ); - setRollbackOnlyTx(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - if ( s != null && s.isOpen() ) { - try { - s.close(); - } - catch (Throwable ignore) { - } - } - } - - // item should not be in entity cache. - assertTrue( slcs.getEntries().isEmpty() ); - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = (Item) s.get( Item.class, item.getId() ); - assertNull( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - @TestForIssue( jiraKey = "HHH-5690") - public void testPersistEntityFlushEvictGetRollbackNotInEntityCache() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() ); - - Item item = null; - Transaction txn = null; - Session s = null; - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = new Item(); - item.setName( "steve" ); - item.setDescription( "steve's item" ); - s.persist( item ); - s.flush(); - // item is cached on insert. -// assertNotNull( slcs.getEntries().get( item.getId() ) ); - s.evict( item ); - assertEquals( slcs.getHitCount(), 0 ); - item = (Item) s.get( Item.class, item.getId() ); - assertNotNull( item ); -// assertEquals( slcs.getHitCount(), 1 ); -// assertNotNull( slcs.getEntries().get( item.getId() ) ); - setRollbackOnlyTx(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - if ( s != null && s.isOpen() ) { - try { - s.close(); - } - catch (Throwable ignore) { - } - } - } - - // item should not be in entity cache. - //slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() ); - assertTrue( slcs.getEntries().isEmpty() ); - - beginTx(); - try { - s = openSession(); - txn = s.beginTransaction(); - item = (Item) s.get( Item.class, item.getId() ); - assertNull( item ); - txn.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - public void testQueryCacheInvalidation() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - - SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() ); - sessionFactory().getCache().evictEntityRegion( Item.class.getName() ); - - assertEquals(0, slcs.getPutCount()); - assertEquals( 0, slcs.getElementCountInMemory() ); - assertEquals( 0, slcs.getEntries().size() ); - - Session s = null; - Transaction t = null; - Item i = null; - - beginTx(); - try { - s = openSession(); - t = s.beginTransaction(); - i = new Item(); - i.setName( "widget" ); - i.setDescription( "A really top-quality, full-featured widget." ); - s.persist( i ); - t.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - - assertEquals( 1, slcs.getPutCount() ); - assertEquals( 1, slcs.getElementCountInMemory() ); - assertEquals( 1, slcs.getEntries().size() ); - - beginTx(); - try { - s = openSession(); - t = s.beginTransaction(); - i = (Item) s.get( Item.class, i.getId() ); - assertEquals( slcs.getHitCount(), 1 ); - assertEquals( slcs.getMissCount(), 0 ); - i.setDescription( "A bog standard item" ); - t.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - assertEquals( slcs.getPutCount(), 2 ); - - CacheEntry entry = (CacheEntry) slcs.getEntries().get( i.getId() ); - Serializable[] ser = entry.getDisassembledState(); - assertTrue( ser[0].equals( "widget" ) ); - assertTrue( ser[1].equals( "A bog standard item" ) ); - - beginTx(); - try { - // cleanup - s = openSession(); - t = s.beginTransaction(); - s.delete(i); - t.commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - public void testQueryCache() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - - Session s; - Item item = new Item( "chris", "Chris's Item" ); - - beginTx(); - try { - s = openSession(); - s.getTransaction().begin(); - s.persist( item ); - s.getTransaction().commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - // Delay added to guarantee that query cache results won't be considered - // as not up to date due to persist session and query results from first - // query happening within same 100ms gap. - Thread.sleep( 100 ); - - beginTx(); - try { - s = openSession(); - s.createQuery( "from Item" ).setCacheable( true ).list(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - beginTx(); - try { - s = openSession(); - s.createQuery( "from Item" ).setCacheable( true ).list(); - assertEquals( 1, stats.getQueryCacheHitCount() ); - s.createQuery( "delete from Item" ).executeUpdate(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - public void testQueryCacheHitInSameTransaction() throws Exception { - Statistics stats = sessionFactory().getStatistics(); - stats.clear(); - - Session s = null; - Item item = new Item( "galder", "Galder's Item" ); - - beginTx(); - try { - s = openSession(); - s.getTransaction().begin(); - s.persist( item ); - s.getTransaction().commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - // Delay added to guarantee that query cache results won't be considered - // as not up to date due to persist session and query results from first - // query happening within same 100ms gap. - Thread.sleep( 100 ); - - beginTx(); - try { - s = openSession(); - s.createQuery( "from Item" ).setCacheable( true ).list(); - s.createQuery( "from Item" ).setCacheable( true ).list(); - assertEquals( 1, stats.getQueryCacheHitCount() ); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - - beginTx(); - try { - s = openSession(); - s.createQuery( "delete from Item" ).executeUpdate(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - } - - @Test - public void testNaturalIdCached() throws Exception { - saveSomeCitizens(); - - // Clear the cache before the transaction begins - BasicTransactionalTestCase.this.cleanupCache(); - Thread.sleep(10); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - State france = BasicTransactionalTestCase.this.getState(s, "Ile de France"); - Criteria criteria = s.createCriteria( Citizen.class ); - criteria.add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", france ) ); - criteria.setCacheable( true ); - - Statistics stats = sessionFactory().getStatistics(); - stats.setStatisticsEnabled( true ); - stats.clear(); - assertEquals( - "Cache hits should be empty", 0, stats - .getNaturalIdCacheHitCount() - ); - - // first query - List results = criteria.list(); - assertEquals( 1, results.size() ); - assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); - assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() ); - assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() ); - assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() ); - - // query a second time - result should be cached in session - criteria.list(); - assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); - assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() ); - assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() ); - assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() ); - - // cleanup - tx.rollback(); - s.close(); - return null; - } - }); - } - - @Test - public void testNaturalIdLoaderCached() throws Exception { - final Statistics stats = sessionFactory().getStatistics(); - stats.setStatisticsEnabled( true ); - stats.clear(); - - assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); - assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() ); - assertEquals( "NaturalId Cache Puts", 0, stats.getNaturalIdCachePutCount() ); - assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() ); - - saveSomeCitizens(); - - assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); - assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() ); - assertEquals( "NaturalId Cache Puts", 2, stats.getNaturalIdCachePutCount() ); - assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() ); - - //Try NaturalIdLoadAccess after insert - final Citizen citizen = withTx(tm, new Callable() { - @Override - public Citizen call() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - State france = BasicTransactionalTestCase.this.getState(s, "Ile de France"); - NaturalIdLoadAccess naturalIdLoader = s.byNaturalId(Citizen.class); - naturalIdLoader.using("ssn", "1234").using("state", france); - - //Not clearing naturalId caches, should be warm from entity loading - stats.clear(); - - // first query - Citizen citizen = (Citizen) naturalIdLoader.load(); - assertNotNull(citizen); - assertEquals("NaturalId Cache Hits", 1, stats.getNaturalIdCacheHitCount()); - assertEquals("NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount()); - assertEquals("NaturalId Cache Puts", 0, stats.getNaturalIdCachePutCount()); - assertEquals("NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount()); - - // cleanup - tx.rollback(); - s.close(); - return citizen; - } - }); - - // TODO: Clear caches manually via cache manager (it's faster!!) - this.cleanupCache(); - Thread.sleep(10); - stats.setStatisticsEnabled( true ); - stats.clear(); - - //Try NaturalIdLoadAccess - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - - // first query - Citizen loadedCitizen = (Citizen) s.get( Citizen.class, citizen.getId() ); - assertNotNull( loadedCitizen ); - assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); - assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() ); - assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() ); - assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() ); - - // cleanup - tx.rollback(); - s.close(); - return null; - } - }); - - // Try NaturalIdLoadAccess after load - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - State france = BasicTransactionalTestCase.this.getState(s, "Ile de France"); - NaturalIdLoadAccess naturalIdLoader = s.byNaturalId(Citizen.class); - naturalIdLoader.using( "ssn", "1234" ).using( "state", france ); - - //Not clearing naturalId caches, should be warm from entity loading - stats.setStatisticsEnabled( true ); - stats.clear(); - - // first query - Citizen loadedCitizen = (Citizen) naturalIdLoader.load(); - assertNotNull( loadedCitizen ); - assertEquals( "NaturalId Cache Hits", 1, stats.getNaturalIdCacheHitCount() ); - assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() ); - assertEquals( "NaturalId Cache Puts", 0, stats.getNaturalIdCachePutCount() ); - assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() ); - - // cleanup - tx.rollback(); - s.close(); - return null; - } - }); - - } - - @Test - public void testEntityCacheContentsAfterEvictAll() throws Exception { - final List citizens = saveSomeCitizens(); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - Cache cache = s.getSessionFactory().getCache(); - - Statistics stats = sessionFactory().getStatistics(); - SecondLevelCacheStatistics slcStats = stats.getSecondLevelCacheStatistics(Citizen.class.getName()); - - assertTrue("2lc entity cache is expected to contain Citizen id = " + citizens.get(0).getId(), - cache.containsEntity(Citizen.class, citizens.get(0).getId())); - assertTrue("2lc entity cache is expected to contain Citizen id = " + citizens.get(1).getId(), - cache.containsEntity(Citizen.class, citizens.get(1).getId())); - assertEquals(2, slcStats.getPutCount()); - - cache.evictEntityRegions(); - Thread.sleep(10); - - assertEquals(0, slcStats.getElementCountInMemory()); - assertFalse("2lc entity cache is expected to not contain Citizen id = " + citizens.get(0).getId(), - cache.containsEntity(Citizen.class, citizens.get(0).getId())); - assertFalse("2lc entity cache is expected to not contain Citizen id = " + citizens.get(1).getId(), - cache.containsEntity(Citizen.class, citizens.get(1).getId())); - - Citizen citizen = (Citizen) s.load(Citizen.class, citizens.get(0).getId()); - assertNotNull(citizen); - assertNotNull(citizen.getFirstname()); // proxy gets resolved - assertEquals(1, slcStats.getMissCount()); - - // cleanup - tx.rollback(); - s.close(); - return null; - } - }); - } - - @Test - public void testMultipleEvictAll() throws Exception { - final List citizens = saveSomeCitizens(); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - Cache cache = s.getSessionFactory().getCache(); - - cache.evictEntityRegions(); - cache.evictEntityRegions(); - - // cleanup - tx.commit(); - s.close(); - return null; - } - }); - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - Cache cache = s.getSessionFactory().getCache(); - - cache.evictEntityRegions(); - - s.delete(s.load(Citizen.class, citizens.get(0).getId())); - s.delete(s.load(Citizen.class, citizens.get(1).getId())); - - // cleanup - tx.commit(); - s.close(); - return null; - } - }); - } - - private List saveSomeCitizens() throws Exception { - final Citizen c1 = new Citizen(); - c1.setFirstname( "Emmanuel" ); - c1.setLastname( "Bernard" ); - c1.setSsn( "1234" ); - - final State france = new State(); - france.setName( "Ile de France" ); - c1.setState( france ); - - final Citizen c2 = new Citizen(); - c2.setFirstname( "Gavin" ); - c2.setLastname( "King" ); - c2.setSsn( "000" ); - final State australia = new State(); - australia.setName( "Australia" ); - c2.setState( australia ); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - s.persist( australia ); - s.persist( france ); - s.persist( c1 ); - s.persist( c2 ); - tx.commit(); - s.close(); - return null; - } - }); - - List citizens = new ArrayList(2); - citizens.add(c1); - citizens.add(c2); - return citizens; - } - - private State getState(Session s, String name) { - Criteria criteria = s.createCriteria( State.class ); - criteria.add( Restrictions.eq("name", name) ); - criteria.setCacheable(true); - return (State) criteria.list().get( 0 ); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BulkOperationsTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BulkOperationsTest.java new file mode 100644 index 0000000000..f22217d57d --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BulkOperationsTest.java @@ -0,0 +1,233 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.hibernate.FlushMode; +import org.hibernate.Session; +import org.hibernate.cache.spi.access.AccessType; +import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl; +import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; +import org.hibernate.stat.SecondLevelCacheStatistics; + +import org.hibernate.test.cache.infinispan.tm.JtaPlatformImpl; +import org.hibernate.test.cache.infinispan.tm.XaConnectionProvider; +import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; +import org.hibernate.test.cache.infinispan.functional.entities.Contact; +import org.hibernate.test.cache.infinispan.functional.entities.Customer; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runners.Parameterized; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +/** + * BulkOperationsTestCase. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public class BulkOperationsTest extends SingleNodeTest { + @Override + public List getParameters() { + return Arrays.asList(TRANSACTIONAL, READ_WRITE); + } + + @ClassRule + public static final InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + + @Override + public String[] getMappings() { + return new String[] { + "cache/infinispan/functional/entities/Contact.hbm.xml", + "cache/infinispan/functional/entities/Customer.hbm.xml" + }; + } + + @Test + public void testBulkOperations() throws Throwable { + boolean cleanedUp = false; + try { + createContacts(); + + List rhContacts = getContactsByCustomer( "Red Hat" ); + assertNotNull( "Red Hat contacts exist", rhContacts ); + assertEquals( "Created expected number of Red Hat contacts", 10, rhContacts.size() ); + + SecondLevelCacheStatistics contactSlcs = sessionFactory() + .getStatistics() + .getSecondLevelCacheStatistics( Contact.class.getName() ); + assertEquals( 20, contactSlcs.getElementCountInMemory() ); + + assertEquals( "Deleted all Red Hat contacts", 10, deleteContacts() ); + assertEquals( 0, contactSlcs.getElementCountInMemory() ); + + List jbContacts = getContactsByCustomer( "JBoss" ); + assertNotNull( "JBoss contacts exist", jbContacts ); + assertEquals( "JBoss contacts remain", 10, jbContacts.size() ); + + for ( Integer id : rhContacts ) { + assertNull( "Red Hat contact " + id + " cannot be retrieved", getContact( id ) ); + } + rhContacts = getContactsByCustomer( "Red Hat" ); + if ( rhContacts != null ) { + assertEquals( "No Red Hat contacts remain", 0, rhContacts.size() ); + } + + updateContacts( "Kabir", "Updated" ); + assertEquals( 0, contactSlcs.getElementCountInMemory() ); + for ( Integer id : jbContacts ) { + Contact contact = getContact( id ); + assertNotNull( "JBoss contact " + id + " exists", contact ); + String expected = ("Kabir".equals( contact.getName() )) ? "Updated" : "2222"; + assertEquals( "JBoss contact " + id + " has correct TLF", expected, contact.getTlf() ); + } + + List updated = getContactsByTLF( "Updated" ); + assertNotNull( "Got updated contacts", updated ); + assertEquals("Updated contacts", 5, updated.size()); + + assertEquals( 10, contactSlcs.getElementCountInMemory() ); + updateContactsWithOneManual( "Kabir", "UpdatedAgain" ); + assertEquals( 0, contactSlcs.getElementCountInMemory()); + for ( Integer id : jbContacts ) { + Contact contact = getContact( id ); + assertNotNull( "JBoss contact " + id + " exists", contact ); + String expected = ("Kabir".equals( contact.getName() )) ? "UpdatedAgain" : "2222"; + assertEquals( "JBoss contact " + id + " has correct TLF", expected, contact.getTlf() ); + } + + updated = getContactsByTLF( "UpdatedAgain" ); + assertNotNull( "Got updated contacts", updated ); + assertEquals( "Updated contacts", 5, updated.size() ); + } + catch (Throwable t) { + cleanedUp = true; + cleanup( true ); + throw t; + } + finally { + // cleanup the db so we can run this test multiple times w/o restarting the cluster + if ( !cleanedUp ) { + cleanup( false ); + } + } + } + + public void createContacts() throws Exception { + withTxSession(s -> { + for ( int i = 0; i < 10; i++ ) { + Customer c = createCustomer( i ); + s.persist(c); + } + }); + } + + public int deleteContacts() throws Exception { + String deleteHQL = "delete Contact where customer in " + + " (select customer FROM Customer as customer where customer.name = :cName)"; + + int rowsAffected = withTxSessionApply(s -> + s.createQuery( deleteHQL ).setFlushMode( FlushMode.AUTO ) + .setParameter( "cName", "Red Hat" ).executeUpdate()); + return rowsAffected; + } + + @SuppressWarnings( {"unchecked"}) + public List getContactsByCustomer(String customerName) throws Exception { + String selectHQL = "select contact.id from Contact contact" + + " where contact.customer.name = :cName"; + + return (List) withTxSessionApply(s -> s.createQuery(selectHQL) + .setFlushMode(FlushMode.AUTO) + .setParameter("cName", customerName) + .list()); + } + + @SuppressWarnings( {"unchecked"}) + public List getContactsByTLF(String tlf) throws Exception { + String selectHQL = "select contact.id from Contact contact" + + " where contact.tlf = :cTLF"; + + return (List) withTxSessionApply(s -> s.createQuery(selectHQL) + .setFlushMode(FlushMode.AUTO) + .setParameter("cTLF", tlf) + .list()); + } + + public int updateContacts(String name, String newTLF) throws Exception { + String updateHQL = "update Contact set tlf = :cNewTLF where name = :cName"; + return withTxSessionApply(s -> s.createQuery( updateHQL ) + .setFlushMode( FlushMode.AUTO ) + .setParameter( "cNewTLF", newTLF ) + .setParameter( "cName", name ) + .executeUpdate()); + } + + public int updateContactsWithOneManual(String name, String newTLF) throws Exception { + String queryHQL = "from Contact c where c.name = :cName"; + String updateHQL = "update Contact set tlf = :cNewTLF where name = :cName"; + return withTxSessionApply(s -> { + List list = s.createQuery(queryHQL).setParameter("cName", name).list(); + list.get(0).setTlf(newTLF); + return s.createQuery(updateHQL) + .setFlushMode(FlushMode.AUTO) + .setParameter("cNewTLF", newTLF) + .setParameter("cName", name) + .executeUpdate(); + }); + } + + public Contact getContact(Integer id) throws Exception { + return withTxSessionApply(s -> s.get( Contact.class, id )); + } + + public void cleanup(boolean ignore) throws Exception { + String deleteContactHQL = "delete from Contact"; + String deleteCustomerHQL = "delete from Customer"; + withTxSession(s -> { + s.createQuery(deleteContactHQL).setFlushMode(FlushMode.AUTO).executeUpdate(); + s.createQuery(deleteCustomerHQL).setFlushMode(FlushMode.AUTO).executeUpdate(); + }); + } + + private Customer createCustomer(int id) throws Exception { + System.out.println( "CREATE CUSTOMER " + id ); + try { + Customer customer = new Customer(); + customer.setName( (id % 2 == 0) ? "JBoss" : "Red Hat" ); + Set contacts = new HashSet(); + + Contact kabir = new Contact(); + kabir.setCustomer( customer ); + kabir.setName( "Kabir" ); + kabir.setTlf( "1111" ); + contacts.add( kabir ); + + Contact bill = new Contact(); + bill.setCustomer( customer ); + bill.setName( "Bill" ); + bill.setTlf( "2222" ); + contacts.add( bill ); + + customer.setContacts( contacts ); + + return customer; + } + finally { + System.out.println( "CREATE CUSTOMER " + id + " - END" ); + } + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ConcurrentWriteTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ConcurrentWriteTest.java index 9421a2dcdf..20ced9fe23 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ConcurrentWriteTest.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ConcurrentWriteTest.java @@ -9,9 +9,9 @@ package org.hibernate.test.cache.infinispan.functional; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.Callable; @@ -20,18 +20,12 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import javax.transaction.TransactionManager; import org.hibernate.FlushMode; -import org.hibernate.Session; -import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; -import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.stat.SecondLevelCacheStatistics; -import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeConnectionProviderImpl; -import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaPlatformImpl; -import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl; -import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeTestCase; +import org.hibernate.test.cache.infinispan.functional.entities.Contact; +import org.hibernate.test.cache.infinispan.functional.entities.Customer; import org.junit.Test; import org.infinispan.util.logging.Log; @@ -45,7 +39,7 @@ import static org.junit.Assert.assertNull; * @author nikita_tovstoles@mba.berkeley.edu * @author Galder Zamarreño */ -public class ConcurrentWriteTest extends SingleNodeTestCase { +public class ConcurrentWriteTest extends SingleNodeTest { private static final Log log = LogFactory.getLog( ConcurrentWriteTest.class ); private static final boolean trace = log.isTraceEnabled(); /** @@ -67,35 +61,9 @@ public class ConcurrentWriteTest extends SingleNodeTestCase { */ private Set customerIDs = new HashSet(); - private TransactionManager tm; - @Override - @SuppressWarnings("unchecked") - protected void addSettings(Map settings) { - super.addSettings( settings ); - - settings.put( DualNodeTestCase.NODE_ID_PROP, DualNodeTestCase.LOCAL ); - settings.put( DualNodeTestCase.NODE_ID_FIELD, DualNodeTestCase.LOCAL ); - } - - @Override - protected boolean getUseQueryCache() { - return true; - } - - @Override - protected TransactionManager getTransactionManager() { - return DualNodeJtaTransactionManagerImpl.getInstance( DualNodeTestCase.LOCAL ); - } - - @Override - protected Class getConnectionProviderClass() { - return DualNodeConnectionProviderImpl.class; - } - - @Override - protected Class getJtaPlatform() { - return DualNodeJtaPlatformImpl.class; + public List getParameters() { + return Arrays.asList(TRANSACTIONAL, READ_WRITE); } @Override @@ -111,34 +79,18 @@ public class ConcurrentWriteTest extends SingleNodeTestCase { } finally { cleanup(); - // DualNodeJtaTransactionManagerImpl.cleanupTransactions(); - // DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers(); } } @Test public void testPingDb() throws Exception { - try { - beginTx(); - sessionFactory() - .getCurrentSession() - .createQuery( "from " + Customer.class.getName() ) - .list(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); -// setRollbackOnly(); -// fail("failed to query DB; exception=" + e); - } - finally { - commitOrRollbackTx(); - } + withTxSession(s -> s.createQuery( "from " + Customer.class.getName() ).list()); } @Test public void testSingleUser() throws Exception { // setup -sessionFactory().getStatistics().clear(); + sessionFactory().getStatistics().clear(); Customer customer = createCustomer( 0 ); final Integer customerId = customer.getId(); getCustomerIDs().add( customerId ); @@ -215,36 +167,20 @@ sessionFactory().getStatistics().clear(); getCustomerIDs().clear(); String deleteContactHQL = "delete from Contact"; String deleteCustomerHQL = "delete from Customer"; - beginTx(); - try { - Session session = sessionFactory().getCurrentSession(); - session.createQuery( deleteContactHQL ).setFlushMode( FlushMode.AUTO ).executeUpdate(); - session.createQuery( deleteCustomerHQL ).setFlushMode( FlushMode.AUTO ).executeUpdate(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } + withTxSession(s -> { + s.createQuery(deleteContactHQL).setFlushMode(FlushMode.AUTO).executeUpdate(); + s.createQuery(deleteCustomerHQL).setFlushMode(FlushMode.AUTO).executeUpdate(); + }); } private Customer createCustomer(int nameSuffix) throws Exception { - Customer customer = null; - beginTx(); - try { - customer = new Customer(); + return withTxSessionApply(s -> { + Customer customer = new Customer(); customer.setName( "customer_" + nameSuffix ); customer.setContacts( new HashSet() ); - sessionFactory().getCurrentSession().persist( customer ); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - return customer; + s.persist( customer ); + return customer; + }); } /** @@ -255,101 +191,75 @@ sessionFactory().getStatistics().clear(); * @throws java.lang.Exception */ private void readEveryonesFirstContact() throws Exception { - beginTx(); - try { + withTxSession(s -> { for ( Integer customerId : getCustomerIDs() ) { if ( TERMINATE_ALL_USERS ) { - setRollbackOnlyTx(); + markRollbackOnly(s); return; } - Customer customer = (Customer) sessionFactory() - .getCurrentSession() - .load( Customer.class, customerId ); + Customer customer = s.load( Customer.class, customerId ); Set contacts = customer.getContacts(); if ( !contacts.isEmpty() ) { contacts.iterator().next(); } } - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } + }); } - /** - * -load existing Customer -get customer's contacts; return 1st one - * - * @param customerId - * @return first Contact or null if customer has none - */ - private Contact getFirstContact(Integer customerId) throws Exception { - assert customerId != null; - Contact firstContact = null; - beginTx(); - try { - final Customer customer = (Customer) sessionFactory() - .getCurrentSession() - .load(Customer.class, customerId); - Set contacts = customer.getContacts(); - firstContact = contacts.isEmpty() ? null : contacts.iterator().next(); - if (TERMINATE_ALL_USERS) - setRollbackOnlyTx(); - } catch (Exception e) { - setRollbackOnlyTx(e); - } finally { - commitOrRollbackTx(); - } - return firstContact; - } + /** + * -load existing Customer -get customer's contacts; return 1st one + * + * @param customerId + * @return first Contact or null if customer has none + */ + private Contact getFirstContact(Integer customerId) throws Exception { + assert customerId != null; + return withTxSessionApply(s -> { + Customer customer = s.load(Customer.class, customerId); + Set contacts = customer.getContacts(); + Contact firstContact = contacts.isEmpty() ? null : contacts.iterator().next(); + if (TERMINATE_ALL_USERS) { + markRollbackOnly(s); + } + return firstContact; + }); + } - /** - * -load existing Customer -create a new Contact and add to customer's contacts - * - * @param customerId - * @return added Contact - */ - private Contact addContact(Integer customerId) throws Exception { - assert customerId != null; - Contact contact = null; - beginTx(); - try { - final Customer customer = (Customer) sessionFactory() - .getCurrentSession() - .load(Customer.class, customerId); - contact = new Contact(); - contact.setName("contact name"); - contact.setTlf("wtf is tlf?"); - contact.setCustomer(customer); - customer.getContacts().add(contact); - // assuming contact is persisted via cascade from customer - if (TERMINATE_ALL_USERS) - setRollbackOnlyTx(); - } catch (Exception e) { - setRollbackOnlyTx(e); - } finally { - commitOrRollbackTx(); - } - return contact; - } + /** + * -load existing Customer -create a new Contact and add to customer's contacts + * + * @param customerId + * @return added Contact + */ + private Contact addContact(Integer customerId) throws Exception { + assert customerId != null; + return withTxSessionApply(s -> { + final Customer customer = s.load(Customer.class, customerId); + Contact contact = new Contact(); + contact.setName("contact name"); + contact.setTlf("wtf is tlf?"); + contact.setCustomer(customer); + customer.getContacts().add(contact); + // assuming contact is persisted via cascade from customer + if (TERMINATE_ALL_USERS) { + markRollbackOnly(s); + } + return contact; + }); + } - /** - * remove existing 'contact' from customer's list of contacts - * - * @param customerId - * @throws IllegalStateException - * if customer does not own a contact - */ - private void removeContact(Integer customerId) throws Exception { - assert customerId != null; + /** + * remove existing 'contact' from customer's list of contacts + * + * @param customerId + * @throws IllegalStateException + * if customer does not own a contact + */ + private void removeContact(Integer customerId) throws Exception { + assert customerId != null; - beginTx(); - try { - Customer customer = (Customer) sessionFactory() - .getCurrentSession() - .load( Customer.class, customerId ); + withTxSession(s -> { + Customer customer = s.load( Customer.class, customerId ); Set contacts = customer.getContacts(); if ( contacts.size() != 1 ) { throw new IllegalStateException( @@ -369,15 +279,9 @@ sessionFactory().getStatistics().clear(); // assuming contact is persisted via cascade from customer if ( TERMINATE_ALL_USERS ) { - setRollbackOnlyTx(); + markRollbackOnly(s); } - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } + }); } /** @@ -423,7 +327,6 @@ sessionFactory().getStatistics().clear(); Thread.currentThread().setName( "UserRunnerThread-" + getCustomerId() ); log.info( "Wait for all executions paths to be ready to perform calls" ); try { -// barrier.await(); for ( int i = 0; i < ITERATION_COUNT && !TERMINATE_ALL_USERS; i++ ) { contactExists(); if ( trace ) { @@ -464,17 +367,6 @@ sessionFactory().getStatistics().clear(); TERMINATE_ALL_USERS = true; log.error( "Error", t ); throw new Exception( t ); - // rollback current transaction if any - // really should not happen since above methods all follow begin-commit-rollback pattern - // try { - // if - // (DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestUtil.LOCAL).getTransaction() - // != null) { - // DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestUtil.LOCAL).rollback(); - // } - // } catch (SystemException ex) { - // throw new RuntimeException("failed to rollback tx", ex); - // } } finally { log.info( "Wait for all execution paths to finish" ); diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Contact.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Contact.java deleted file mode 100755 index 2b0f6f9535..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Contact.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional; -import java.io.Serializable; - -/** - * Entity that has a many-to-one relationship to a Customer - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class Contact implements Serializable { - Integer id; - String name; - String tlf; - Customer customer; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getTlf() { - return tlf; - } - - public void setTlf(String tlf) { - this.tlf = tlf; - } - - public Customer getCustomer() { - return customer; - } - - public void setCustomer(Customer customer) { - this.customer = customer; - } - - @Override - public boolean equals(Object o) { - if (o == this) - return true; - if (!(o instanceof Contact)) - return false; - Contact c = (Contact) o; - return c.id.equals(id) && c.name.equals(name) && c.tlf.equals(tlf); - } - - @Override - public int hashCode() { - int result = 17; - result = 31 * result + (id == null ? 0 : id.hashCode()); - result = 31 * result + name.hashCode(); - result = 31 * result + tlf.hashCode(); - return result; - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Customer.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Customer.java deleted file mode 100755 index 055afc7972..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Customer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional; -import java.io.Serializable; -import java.util.Set; - -/** - * Company customer - * - * @author Emmanuel Bernard - * @author Kabir Khan - */ -public class Customer implements Serializable { - Integer id; - String name; - - private transient Set contacts; - - public Customer() { - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String string) { - name = string; - } - - public Set getContacts() { - return contacts; - } - - public void setContacts(Set contacts) { - this.contacts = contacts; - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/EqualityTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/EqualityTest.java index 6046c331bc..2e3e6c4fc6 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/EqualityTest.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/EqualityTest.java @@ -1,12 +1,13 @@ package org.hibernate.test.cache.infinispan.functional; -import java.util.concurrent.Callable; - -import org.hibernate.Session; import org.hibernate.stat.Statistics; +import org.hibernate.test.cache.infinispan.functional.entities.Name; +import org.hibernate.test.cache.infinispan.functional.entities.Person; import org.junit.Test; -import static org.infinispan.test.TestingUtil.withTx; +import java.util.Arrays; +import java.util.List; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -17,61 +18,50 @@ import static org.junit.Assert.assertTrue; * * @author Radim Vansa <rvansa@redhat.com> */ -public class EqualityTest extends SingleNodeTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Person.class }; - } +public class EqualityTest extends SingleNodeTest { + @Override + public List getParameters() { + return Arrays.asList(TRANSACTIONAL, READ_WRITE, READ_ONLY); + } - @Test - public void testEqualityFromType() throws Exception { - Person john = new Person("John", "Black", 26); - Person peter = new Person("Peter", "White", 32); + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Person.class }; + } - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session session = openSession(); - session.getTransaction().begin(); - session.persist(john); - session.persist(peter); - session.getTransaction().commit(); - session.close(); - return null; - } - }); + @Test + public void testEqualityFromType() throws Exception { + Person john = new Person("John", "Black", 26); + Person peter = new Person("Peter", "White", 32); - Statistics statistics = sessionFactory().getStatistics(); - statistics.clear(); + withTxSession(s -> { + s.persist(john); + s.persist(peter); + }); - for (int i = 0; i < 5; ++i) { - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session session = openSession(); - session.getTransaction().begin(); - Person p1 = session.get(Person.class, john.name); - assertPersonEquals(john, p1); - Person p2 = session.get(Person.class, peter.name); - assertPersonEquals(peter, p2); - Person p3 = session.get(Person.class, new Name("Foo", "Bar")); - assertNull(p3); - session.getTransaction().commit(); - session.close(); - return null; - } - }); - } + Statistics statistics = sessionFactory().getStatistics(); + statistics.clear(); - assertTrue(statistics.getSecondLevelCacheHitCount() > 0); - assertTrue(statistics.getSecondLevelCacheMissCount() > 0); - } + for (int i = 0; i < 5; ++i) { + withTxSession(s -> { + Person p1 = s.get(Person.class, john.getName()); + assertPersonEquals(john, p1); + Person p2 = s.get(Person.class, peter.getName()); + assertPersonEquals(peter, p2); + Person p3 = s.get(Person.class, new Name("Foo", "Bar")); + assertNull(p3); + }); + } - private static void assertPersonEquals(Person expected, Person person) { - assertNotNull(person); - assertNotNull(person.getName()); - assertEquals(expected.getName().getFirstName(), person.getName().getFirstName()); - assertEquals(expected.getName().getLastName(), person.getName().getLastName()); - assertEquals(expected.getAge(), person.getAge()); - } + assertTrue(statistics.getSecondLevelCacheHitCount() > 0); + assertTrue(statistics.getSecondLevelCacheMissCount() > 0); + } + + private static void assertPersonEquals(Person expected, Person person) { + assertNotNull(person); + assertNotNull(person.getName()); + assertEquals(expected.getName().getFirstName(), person.getName().getFirstName()); + assertEquals(expected.getName().getLastName(), person.getName().getLastName()); + assertEquals(expected.getAge(), person.getAge()); + } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/JndiRegionFactoryTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/JndiRegionFactoryTest.java similarity index 82% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/JndiRegionFactoryTestCase.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/JndiRegionFactoryTest.java index 1c075767ef..99d0285df0 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/JndiRegionFactoryTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/JndiRegionFactoryTest.java @@ -6,6 +6,8 @@ */ package org.hibernate.test.cache.infinispan.functional; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Properties; import javax.naming.Context; @@ -15,16 +17,17 @@ import javax.naming.NameNotFoundException; import javax.naming.Reference; import javax.naming.StringRefAddr; -import org.hibernate.Session; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.cache.infinispan.InfinispanRegionFactory; import org.hibernate.cache.infinispan.JndiInfinispanRegionFactory; -import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cfg.Environment; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl; import org.hibernate.stat.Statistics; +import org.hibernate.test.cache.infinispan.functional.entities.Item; import org.junit.Test; import org.infinispan.Cache; @@ -38,17 +41,15 @@ import org.jboss.util.naming.NonSerializableFactory; import org.jnp.server.Main; import org.jnp.server.SingletonNamingServer; +import org.junit.runners.Parameterized; import static org.junit.Assert.assertEquals; /** - * // TODO: Document this - * * @author Galder Zamarreño - * @since // TODO */ -public class JndiRegionFactoryTestCase extends SingleNodeTestCase { - private static final Log log = LogFactory.getLog( JndiRegionFactoryTestCase.class ); +public class JndiRegionFactoryTest extends SingleNodeTest { + private static final Log log = LogFactory.getLog( JndiRegionFactoryTest.class ); private static final String JNDI_NAME = "java:CacheManager"; private Main namingMain; private SingletonNamingServer namingServer; @@ -56,6 +57,11 @@ public class JndiRegionFactoryTestCase extends SingleNodeTestCase { private boolean bindToJndi = true; private EmbeddedCacheManager manager; + @Override + public List getParameters() { + return Collections.singletonList(new Object[]{"read-write", null, JdbcResourceLocalTransactionCoordinatorBuilderImpl.class, null, AccessType.READ_WRITE, JndiInfinispanRegionFactory.class}); + } + @Override protected void cleanupTest() throws Exception { Context ctx = new InitialContext( props ); @@ -65,11 +71,6 @@ public class JndiRegionFactoryTestCase extends SingleNodeTestCase { manager.stop(); // Need to stop cos JNDI region factory does not stop it. } - @Override - protected Class getCacheRegionFactory() { - return JndiInfinispanRegionFactory.class; - } - @Override protected void afterStandardServiceRegistryBuilt(StandardServiceRegistry ssr) { if ( bindToJndi ) { @@ -118,46 +119,23 @@ public class JndiRegionFactoryTestCase extends SingleNodeTestCase { addEntityCheckCache( sessionFactory() ); JndiInfinispanRegionFactory regionFactory = (JndiInfinispanRegionFactory) sessionFactory().getSettings().getRegionFactory(); - Cache cache = regionFactory.getCacheManager().getCache( "org.hibernate.test.cache.infinispan.functional.Item" ); + Cache cache = regionFactory.getCacheManager().getCache( Item.class.getName() ); assertEquals( ComponentStatus.RUNNING, cache.getStatus() ); } private void addEntityCheckCache(SessionFactoryImplementor sessionFactory) throws Exception { Item item = new Item( "chris", "Chris's Item" ); - beginTx(); - try { - Session s = sessionFactory.openSession(); - s.getTransaction().begin(); - s.persist( item ); - s.getTransaction().commit(); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } + withTxSession(s -> s.persist( item )); - beginTx(); - try { - Session s = sessionFactory.openSession(); - Item found = (Item) s.load( Item.class, item.getId() ); + withTxSession(s -> { + Item found = s.load(Item.class, item.getId()); Statistics stats = sessionFactory.getStatistics(); - log.info( stats.toString() ); - assertEquals( item.getDescription(), found.getDescription() ); - assertEquals( 0, stats.getSecondLevelCacheMissCount() ); - assertEquals( 1, stats.getSecondLevelCacheHitCount() ); - s.delete( found ); - s.close(); - } - catch (Exception e) { - setRollbackOnlyTx( e ); - } - finally { - commitOrRollbackTx(); - } - + log.info(stats.toString()); + assertEquals(item.getDescription(), found.getDescription()); + assertEquals(0, stats.getSecondLevelCacheMissCount()); + assertEquals(1, stats.getSecondLevelCacheHitCount()); + s.delete(found); + }); } /** diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/MultiTenancyTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/MultiTenancyTest.java new file mode 100644 index 0000000000..f4756c0462 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/MultiTenancyTest.java @@ -0,0 +1,108 @@ +package org.hibernate.test.cache.infinispan.functional; + +import org.hibernate.MultiTenancyStrategy; +import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cache.infinispan.entity.EntityRegionImpl; +import org.hibernate.cache.infinispan.util.Caches; +import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider; +import org.hibernate.test.cache.infinispan.functional.entities.Item; +import org.hibernate.test.cache.infinispan.tm.XaConnectionProvider; +import org.hibernate.testing.env.ConnectionProviderBuilder; +import org.infinispan.AdvancedCache; +import org.infinispan.commons.util.CloseableIterable; +import org.infinispan.context.Flag; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * @author Radim Vansa <rvansa@redhat.com> + */ +public class MultiTenancyTest extends SingleNodeTest { + + private static final String DB1 = "db1"; + private static final String DB2 = "db2"; + private final ConnectionProvider db1 + = new XaConnectionProvider(ConnectionProviderBuilder.buildConnectionProvider(DB1)); + private final ConnectionProvider db2 + = new XaConnectionProvider(ConnectionProviderBuilder.buildConnectionProvider(DB2)); + + @Override + public List getParameters() { + return Collections.singletonList(READ_ONLY); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder(ssrb); + ssrb.addService(MultiTenantConnectionProvider.class, new AbstractMultiTenantConnectionProvider() { + + @Override + protected ConnectionProvider getAnyConnectionProvider() { + return db1; + } + + @Override + protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) { + if (DB1.equals(tenantIdentifier)) return db1; + if (DB2.equals(tenantIdentifier)) return db2; + throw new IllegalArgumentException(); + } + }); + } + + @Override + protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { + super.configureSessionFactoryBuilder(sfb); + sfb.applyMultiTenancyStrategy(MultiTenancyStrategy.DATABASE); + } + + @Override + protected void cleanupTest() throws Exception { + db1.getConnection().close(); + db2.getConnection().close(); + } + + @Test + public void testMultiTenancy() throws Exception { + final Item item = new Item("my item", "description" ); + + withTxSession(sessionFactory().withOptions().tenantIdentifier(DB1), s -> s.persist(item)); + + for (int i = 0; i < 5; ++i) { // make sure we get something cached + withTxSession(sessionFactory().withOptions().tenantIdentifier(DB1), s -> { + Item item2 = s.get(Item.class, item.getId()); + assertNotNull(item2); + assertEquals(item.getName(), item2.getName()); + }); + + } + // The table ITEMS is not created in DB2 - we would get just an exception +// for (int i = 0; i < 5; ++i) { // make sure we get something cached +// withTx(tm, new Callable() { +// @Override +// public Void call() throws Exception { +// Session s = sessionFactory().withOptions().tenantIdentifier(DB2).openSession(); +// s.getTransaction().begin(); +// Item item2 = s.get(Item.class, id); +// s.getTransaction().commit(); +// s.close(); +// assertNull(item2); +// return null; +// } +// }); +// } + EntityRegionImpl region = (EntityRegionImpl) sessionFactory().getSecondLevelCacheRegion(Item.class.getName()); + AdvancedCache localCache = region.getCache().withFlags(Flag.CACHE_MODE_LOCAL); + CloseableIterable keys = Caches.keys(localCache); + assertEquals(1, localCache.size()); + assertEquals("OldCacheKeyImplementation", keys.iterator().next().getClass().getSimpleName()); + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/MultiTenancyTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/MultiTenancyTestCase.java deleted file mode 100644 index 28f7653f5e..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/MultiTenancyTestCase.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.hibernate.test.cache.infinispan.functional; - -import java.util.concurrent.Callable; - -import org.hibernate.MultiTenancyStrategy; -import org.hibernate.Session; -import org.hibernate.boot.SessionFactoryBuilder; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cache.infinispan.entity.EntityRegionImpl; -import org.hibernate.cache.infinispan.util.Caches; -import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider; -import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; -import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider; -import org.hibernate.test.cache.infinispan.tm.XaConnectionProvider; -import org.hibernate.testing.env.ConnectionProviderBuilder; -import org.infinispan.AdvancedCache; -import org.infinispan.commons.util.CloseableIterable; -import org.infinispan.commons.util.CloseableIteratorSet; -import org.infinispan.context.Flag; -import org.junit.Test; - -import static org.infinispan.test.TestingUtil.withTx; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -/** - * @author Radim Vansa <rvansa@redhat.com> - */ -public class MultiTenancyTestCase extends SingleNodeTestCase { - - private static final String DB1 = "db1"; - private static final String DB2 = "db2"; - private final ConnectionProvider db1 - = new XaConnectionProvider(ConnectionProviderBuilder.buildConnectionProvider(DB1)); - private final ConnectionProvider db2 - = new XaConnectionProvider(ConnectionProviderBuilder.buildConnectionProvider(DB2)); - - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder(ssrb); - ssrb.addService(MultiTenantConnectionProvider.class, new AbstractMultiTenantConnectionProvider() { - - @Override - protected ConnectionProvider getAnyConnectionProvider() { - return db1; - } - - @Override - protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) { - if (DB1.equals(tenantIdentifier)) return db1; - if (DB2.equals(tenantIdentifier)) return db2; - throw new IllegalArgumentException(); - } - }); - } - - @Override - protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { - super.configureSessionFactoryBuilder(sfb); - sfb.applyMultiTenancyStrategy(MultiTenancyStrategy.DATABASE); - } - - @Override - protected void cleanupTest() throws Exception { - db1.getConnection().close(); - db2.getConnection().close(); - } - - @Test - public void testMultiTenancy() throws Exception { - final Item item = new Item("my item", "description" ); - - long id = withTx(tm, new Callable() { - @Override - public Long call() throws Exception { - Session s = sessionFactory().withOptions().tenantIdentifier(DB1).openSession(); - s.getTransaction().begin(); - s.persist(item); - s.getTransaction().commit(); - s.close(); - return item.getId(); - } - }); - for (int i = 0; i < 5; ++i) { // make sure we get something cached - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = sessionFactory().withOptions().tenantIdentifier(DB1).openSession(); - s.getTransaction().begin(); - Item item2 = s.get(Item.class, id); - s.getTransaction().commit(); - s.close(); - assertNotNull(item2); - assertEquals(item.getName(), item2.getName()); - return null; - } - }); - - } - // The table ITEMS is not created in DB2 - we would get just an exception -// for (int i = 0; i < 5; ++i) { // make sure we get something cached -// withTx(tm, new Callable() { -// @Override -// public Void call() throws Exception { -// Session s = sessionFactory().withOptions().tenantIdentifier(DB2).openSession(); -// s.getTransaction().begin(); -// Item item2 = s.get(Item.class, id); -// s.getTransaction().commit(); -// s.close(); -// assertNull(item2); -// return null; -// } -// }); -// } - EntityRegionImpl region = (EntityRegionImpl) sessionFactory().getSecondLevelCacheRegion(Item.class.getName()); - AdvancedCache localCache = region.getCache().withFlags(Flag.CACHE_MODE_LOCAL); - CloseableIterable keys = Caches.keys(localCache); - assertEquals(1, localCache.size()); - assertEquals("OldCacheKeyImplementation", keys.iterator().next().getClass().getSimpleName()); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NoTenancyTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NoTenancyTest.java new file mode 100644 index 0000000000..5d53d7fc92 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NoTenancyTest.java @@ -0,0 +1,46 @@ +package org.hibernate.test.cache.infinispan.functional; + +import org.hibernate.cache.infinispan.entity.EntityRegionImpl; +import org.hibernate.cache.infinispan.util.Caches; +import org.hibernate.test.cache.infinispan.functional.entities.Item; +import org.infinispan.AdvancedCache; +import org.infinispan.commons.util.CloseableIterable; +import org.infinispan.context.Flag; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * @author Radim Vansa <rvansa@redhat.com> + */ +public class NoTenancyTest extends SingleNodeTest { + @Override + public List getParameters() { + return Collections.singletonList(READ_ONLY); + } + + @Test + public void testNoTenancy() throws Exception { + final Item item = new Item("my item", "description" ); + + withTxSession(s -> s.persist(item)); + for (int i = 0; i < 5; ++i) { // make sure we get something cached + withTxSession(s -> { + Item item2 = s.get(Item.class, item.getId()); + assertNotNull(item2); + assertEquals(item.getName(), item2.getName()); + }); + + } + EntityRegionImpl region = (EntityRegionImpl) sessionFactory().getSecondLevelCacheRegion(Item.class.getName()); + AdvancedCache localCache = region.getCache().withFlags(Flag.CACHE_MODE_LOCAL); + CloseableIterable keys = Caches.keys(localCache); + assertEquals(1, localCache.size()); + assertEquals(sessionFactory().getClassMetadata(Item.class).getIdentifierType().getReturnedClass(), keys.iterator().next().getClass()); + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NoTenancyTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NoTenancyTestCase.java deleted file mode 100644 index d92f901aea..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NoTenancyTestCase.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.hibernate.test.cache.infinispan.functional; - -import java.util.concurrent.Callable; - -import org.hibernate.Session; -import org.hibernate.cache.infinispan.entity.EntityRegionImpl; -import org.hibernate.cache.infinispan.util.Caches; -import org.infinispan.AdvancedCache; -import org.infinispan.commons.util.CloseableIterable; -import org.infinispan.commons.util.CloseableIteratorSet; -import org.infinispan.context.Flag; -import org.junit.Test; - -import static org.infinispan.test.TestingUtil.withTx; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -/** - * @author Radim Vansa <rvansa@redhat.com> - */ -public class NoTenancyTestCase extends SingleNodeTestCase { - @Test - public void testNoTenancy() throws Exception { - final Item item = new Item("my item", "description" ); - - long id = withTx(tm, new Callable() { - @Override - public Long call() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - s.persist(item); - s.getTransaction().commit(); - s.close(); - return item.getId(); - } - }); - for (int i = 0; i < 5; ++i) { // make sure we get something cached - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - Item item2 = s.get(Item.class, id); - s.getTransaction().commit(); - s.close(); - assertNotNull(item2); - assertEquals(item.getName(), item2.getName()); - return null; - } - }); - - } - EntityRegionImpl region = (EntityRegionImpl) sessionFactory().getSecondLevelCacheRegion(Item.class.getName()); - AdvancedCache localCache = region.getCache().withFlags(Flag.CACHE_MODE_LOCAL); - CloseableIterable keys = Caches.keys(localCache); - assertEquals(1, localCache.size()); - assertEquals(sessionFactory().getClassMetadata(Item.class).getIdentifierType().getReturnedClass(), keys.iterator().next().getClass()); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ReadOnlyTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ReadOnlyTest.java new file mode 100644 index 0000000000..0bc67b8e9a --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ReadOnlyTest.java @@ -0,0 +1,232 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.hibernate.PessimisticLockException; +import org.hibernate.cache.infinispan.InfinispanRegionFactory; +import org.hibernate.cache.infinispan.entity.EntityRegionImpl; +import org.hibernate.cache.spi.Region; +import org.hibernate.stat.SecondLevelCacheStatistics; +import org.hibernate.stat.Statistics; +import org.hibernate.test.cache.infinispan.functional.entities.Item; +import org.hibernate.testing.TestForIssue; +import org.infinispan.AdvancedCache; +import org.infinispan.commands.read.GetKeyValueCommand; +import org.infinispan.context.InvocationContext; +import org.infinispan.interceptors.base.BaseCustomInterceptor; +import org.infinispan.util.logging.Log; +import org.infinispan.util.logging.LogFactory; +import org.junit.Test; +import org.junit.runners.Parameterized; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +/** + * Parent tests for both transactional and + * read-only tests are defined in this class. + * + * @author Galder Zamarreño + * @since 4.1 + */ +public class ReadOnlyTest extends SingleNodeTest { + static final Log log = LogFactory.getLog(ReadOnlyTest.class); + + @Override + public List getParameters() { + return Collections.singletonList(READ_ONLY); + } + + @Test + public void testEmptySecondLevelCacheEntry() throws Exception { + sessionFactory().getCache().evictCollectionRegion( Item.class.getName() + ".items" ); + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); + Map cacheEntries = statistics.getEntries(); + assertEquals( 0, cacheEntries.size() ); + } + + @Test + public void testInsertDeleteEntity() throws Exception { + final Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + final Item item = new Item( "chris", "Chris's Item" ); + withTxSession(s -> s.persist(item)); + + log.info("Entry persisted, let's load and delete it."); + + withTxSession(s -> { + Item found = s.load(Item.class, item.getId()); + log.info(stats.toString()); + assertEquals(item.getDescription(), found.getDescription()); + assertEquals(0, stats.getSecondLevelCacheMissCount()); + assertEquals(1, stats.getSecondLevelCacheHitCount()); + s.delete(found); + }); + } + + @Test + public void testInsertClearCacheDeleteEntity() throws Exception { + final Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + final Item item = new Item( "chris", "Chris's Item" ); + withTxSession(s -> s.persist(item)); + assertEquals(0, stats.getSecondLevelCacheMissCount()); + assertEquals(0, stats.getSecondLevelCacheHitCount()); + assertEquals(1, stats.getSecondLevelCachePutCount()); + + log.info("Entry persisted, let's load and delete it."); + + cleanupCache(); + Thread.sleep(10); + + withTxSession(s -> { + Item found = s.load(Item.class, item.getId()); + log.info(stats.toString()); + assertEquals(item.getDescription(), found.getDescription()); + assertEquals(1, stats.getSecondLevelCacheMissCount()); + assertEquals(0, stats.getSecondLevelCacheHitCount()); + assertEquals(2, stats.getSecondLevelCachePutCount()); + s.delete(found); + }); + } + + @Test + @TestForIssue(jiraKey = "HHH-9868") + public void testConcurrentRemoveAndPutFromLoad() throws Exception { + final Item item = new Item( "chris", "Chris's Item" ); + withTxSession(s -> { + s.persist(item); + }); + Region region = sessionFactory().getSecondLevelCacheRegion(Item.class.getName()); + + Phaser deletePhaser = new Phaser(2); + Phaser getPhaser = new Phaser(2); + HookInterceptor hook = new HookInterceptor(); + + AdvancedCache entityCache = ((EntityRegionImpl) region).getCache(); + AdvancedCache pendingPutsCache = entityCache.getCacheManager().getCache( + entityCache.getName() + "-" + InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME).getAdvancedCache(); + pendingPutsCache.addInterceptor(hook, 0); + + Thread deleteThread = new Thread(() -> { + try { + withTxSession(s -> { + Item loadedItem = s.get(Item.class, item.getId()); + assertNotNull(loadedItem); + arriveAndAwait(deletePhaser); + arriveAndAwait(deletePhaser); + log.trace("Item loaded"); + s.delete(loadedItem); + s.flush(); + log.trace("Item deleted"); + // start get-thread here + arriveAndAwait(deletePhaser); + arriveAndAwait(deletePhaser); + }); + } catch (Exception e) { + throw new RuntimeException(e); + } + }, "delete-thread"); + Thread getThread = new Thread(() -> { + try { + withTxSession(s -> { + // DB load should happen before the record is deleted, + // putFromLoad should happen after deleteThread ends + Item loadedItem = s.get(Item.class, item.getId()); + assertNotNull(loadedItem); + }); + } catch (PessimisticLockException e) { + // If we end up here, database locks guard us against situation tested + // in this case and HHH-9868 cannot happen. + // (delete-thread has ITEMS table write-locked and we try to acquire read-lock) + try { + arriveAndAwait(getPhaser); + arriveAndAwait(getPhaser); + } catch (Exception e1) { + throw new RuntimeException(e1); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + }, "get-thread"); + + deleteThread.start(); + // deleteThread loads the entity + arriveAndAwait(deletePhaser); + withTx(() -> { + sessionFactory().getCache().evictEntity(Item.class, item.getId()); + assertFalse(sessionFactory().getCache().containsEntity(Item.class, item.getId())); + return null; + }); + arriveAndAwait(deletePhaser); + // delete thread invalidates PFER + arriveAndAwait(deletePhaser); + // get thread gets the entity from DB + hook.block(getPhaser, getThread); + getThread.start(); + arriveAndAwait(getPhaser); + arriveAndAwait(deletePhaser); + // delete thread finishes the remove from DB and cache + deleteThread.join(); + hook.unblock(); + arriveAndAwait(getPhaser); + // get thread puts the entry into cache + getThread.join(); + + withTxSession(s -> { + Item loadedItem = s.get(Item.class, item.getId()); + assertNull(loadedItem); + }); + } + + protected static void arriveAndAwait(Phaser phaser) throws TimeoutException, InterruptedException { + phaser.awaitAdvanceInterruptibly(phaser.arrive(), 1000, TimeUnit.SECONDS); + } + + private static class HookInterceptor extends BaseCustomInterceptor { + Phaser phaser; + Thread thread; + + public synchronized void block(Phaser phaser, Thread thread) { + this.phaser = phaser; + this.thread = thread; + } + + public synchronized void unblock() { + phaser = null; + thread = null; + } + + @Override + public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable { + Phaser phaser; + Thread thread; + synchronized (this) { + phaser = this.phaser; + thread = this.thread; + } + if (phaser != null && Thread.currentThread() == thread) { + arriveAndAwait(phaser); + arriveAndAwait(phaser); + } + return super.visitGetKeyValueCommand(ctx, command); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ReadWriteTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ReadWriteTest.java new file mode 100644 index 0000000000..bdf24158d3 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ReadWriteTest.java @@ -0,0 +1,687 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.hibernate.Cache; +import org.hibernate.Criteria; +import org.hibernate.Hibernate; +import org.hibernate.NaturalIdLoadAccess; +import org.hibernate.Session; +import org.hibernate.cache.spi.entry.CacheEntry; +import org.hibernate.criterion.Restrictions; +import org.hibernate.stat.SecondLevelCacheStatistics; +import org.hibernate.stat.Statistics; +import org.hibernate.test.cache.infinispan.functional.entities.Citizen; +import org.hibernate.test.cache.infinispan.functional.entities.Item; +import org.hibernate.test.cache.infinispan.functional.entities.NaturalIdOnManyToOne; +import org.hibernate.test.cache.infinispan.functional.entities.OtherItem; +import org.hibernate.test.cache.infinispan.functional.entities.State; +import org.hibernate.test.cache.infinispan.functional.entities.VersionedItem; +import org.hibernate.testing.TestForIssue; +import org.infinispan.commons.util.ByRef; +import org.junit.After; +import org.junit.Test; +import org.junit.runners.Parameterized; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static org.hibernate.test.cache.infinispan.util.TxUtil.markRollbackOnly; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Functional entity transactional tests. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public class ReadWriteTest extends ReadOnlyTest { + @Override + public List getParameters() { + return Arrays.asList(TRANSACTIONAL, READ_WRITE); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Citizen.class, State.class, + NaturalIdOnManyToOne.class + }; + } + + @After + public void cleanupData() throws Exception { + super.cleanupCache(); + withTxSession(s -> { + s.createQuery( "delete NaturalIdOnManyToOne" ).executeUpdate(); + s.createQuery( "delete Citizen" ).executeUpdate(); + s.createQuery( "delete State" ).executeUpdate(); + }); + } + + @Test + public void testCollectionCache() throws Exception { + final Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + final Item item = new Item( "chris", "Chris's Item" ); + final Item another = new Item( "another", "Owned Item" ); + item.addItem( another ); + + withTxSession(s -> { + s.persist( item ); + s.persist( another ); + }); + + withTxSession(s -> { + Item loaded = s.load( Item.class, item.getId() ); + assertEquals( 1, loaded.getItems().size() ); + }); + + withTxSession(s -> { + SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); + Item loadedWithCachedCollection = (Item) s.load( Item.class, item.getId() ); + stats.logSummary(); + assertEquals( item.getName(), loadedWithCachedCollection.getName() ); + assertEquals( item.getItems().size(), loadedWithCachedCollection.getItems().size() ); + assertEquals( 1, cStats.getHitCount() ); + Map cacheEntries = cStats.getEntries(); + assertEquals( 1, cacheEntries.size() ); + Item itemElement = loadedWithCachedCollection.getItems().iterator().next(); + itemElement.setOwner( null ); + loadedWithCachedCollection.getItems().clear(); + s.delete( itemElement ); + s.delete( loadedWithCachedCollection ); + }); + } + + @Test + @TestForIssue( jiraKey = "HHH-9231" ) + public void testAddNewOneToManyElementInitFlushLeaveCacheConsistent() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); + + ByRef itemId = new ByRef<>(null); + saveItem(itemId); + + // create an element for item.itsms + Item itemElement = new Item(); + itemElement.setName( "element" ); + itemElement.setDescription( "element item" ); + + withTxSession(s -> { + Item item = s.get( Item.class, itemId.get() ); + assertFalse( Hibernate.isInitialized( item.getItems() ) ); + // Add an element to item.items (a Set); it will initialize the Set. + item.addItem( itemElement ); + assertTrue( Hibernate.isInitialized( item.getItems() ) ); + s.persist( itemElement ); + s.flush(); + markRollbackOnly(s); + }); + + withTxSession(s -> { + Item item = s.get( Item.class, itemId.get() ); + Hibernate.initialize( item.getItems() ); + assertTrue( item.getItems().isEmpty() ); + s.delete( item ); + }); + } + + @Test + @TestForIssue( jiraKey = "HHH-9231" ) + public void testAddNewOneToManyElementNoInitFlushLeaveCacheConsistent() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); + + ByRef itemId = new ByRef<>(null); + + saveItem(itemId); + + // create an element for item.bagOfItems + Item itemElement = new Item(); + itemElement.setName( "element" ); + itemElement.setDescription( "element item" ); + + withTxSession(s -> { + Item item = s.get( Item.class, itemId.get() ); + assertFalse( Hibernate.isInitialized( item.getItems() ) ); + // Add an element to item.bagOfItems (a bag); it will not initialize the bag. + item.addItemToBag( itemElement ); + assertFalse( Hibernate.isInitialized( item.getBagOfItems() ) ); + s.persist( itemElement ); + s.flush(); + markRollbackOnly(s); + }); + + withTxSession(s -> { + Item item = s.get( Item.class, itemId.get() ); + Hibernate.initialize( item.getItems() ); + assertTrue( item.getItems().isEmpty() ); + s.delete( item ); + }); + } + + @Test + public void testAddNewOneToManyElementNoInitFlushInitLeaveCacheConsistent() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); + + ByRef itemId = new ByRef<>(null); + + saveItem(itemId); + + // create an element for item.bagOfItems + Item itemElement = new Item(); + itemElement.setName( "element" ); + itemElement.setDescription( "element item" ); + + withTxSession(s -> { + Item item = s.get(Item.class, itemId.get()); + assertFalse(Hibernate.isInitialized(item.getBagOfItems())); + // Add an element to item.bagOfItems (a bag); it will not initialize the bag. + item.addItemToBag(itemElement); + assertFalse(Hibernate.isInitialized(item.getBagOfItems())); + s.persist(itemElement); + s.flush(); + // Now initialize the collection; it will contain the uncommitted itemElement. + Hibernate.initialize(item.getBagOfItems()); + markRollbackOnly(s); + }); + + withTxSession(s -> { + Item item = s.get(Item.class, itemId.get()); + // Because of HHH-9231, the following will fail due to ObjectNotFoundException because the + // collection will be read from the cache and it still contains the uncommitted element, + // which cannot be found. + Hibernate.initialize(item.getBagOfItems()); + assertTrue(item.getBagOfItems().isEmpty()); + s.delete(item); + }); + } + + protected void saveItem(ByRef itemId) throws Exception { + withTxSession(s -> { + Item item = new Item(); + item.setName( "steve" ); + item.setDescription( "steve's item" ); + s.save( item ); + itemId.set(item.getId()); + }); + } + + @Test + public void testAddNewManyToManyPropertyRefNoInitFlushInitLeaveCacheConsistent() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics( Item.class.getName() + ".items" ); + + ByRef otherItemId = new ByRef<>(null); + withTxSession(s -> { + OtherItem otherItem = new OtherItem(); + otherItem.setName( "steve" ); + s.save( otherItem ); + otherItemId.set(otherItem.getId()); + }); + + // create an element for otherItem.bagOfItems + Item item = new Item(); + item.setName( "element" ); + item.setDescription( "element Item" ); + + withTxSession(s -> { + OtherItem otherItem = s.get( OtherItem.class, otherItemId.get() ); + assertFalse( Hibernate.isInitialized( otherItem.getBagOfItems() ) ); + // Add an element to otherItem.bagOfItems (a bag); it will not initialize the bag. + otherItem.addItemToBag( item ); + assertFalse( Hibernate.isInitialized( otherItem.getBagOfItems() ) ); + s.persist( item ); + s.flush(); + // Now initialize the collection; it will contain the uncommitted itemElement. + // The many-to-many uses a property-ref + Hibernate.initialize( otherItem.getBagOfItems() ); + markRollbackOnly(s); + }); + + withTxSession(s -> { + OtherItem otherItem = s.get( OtherItem.class, otherItemId.get() ); + // Because of HHH-9231, the following will fail due to ObjectNotFoundException because the + // collection will be read from the cache and it still contains the uncommitted element, + // which cannot be found. + Hibernate.initialize( otherItem.getBagOfItems() ); + assertTrue( otherItem.getBagOfItems().isEmpty() ); + s.delete( otherItem ); + }); + } + + @Test + public void testStaleWritesLeaveCacheConsistent() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + ByRef itemRef = new ByRef<>(null); + withTxSession(s -> { + VersionedItem item = new VersionedItem(); + item.setName( "steve" ); + item.setDescription( "steve's item" ); + s.save( item ); + itemRef.set(item); + }); + + final VersionedItem item = itemRef.get(); + Long initialVersion = item.getVersion(); + + // manually revert the version property + item.setVersion( new Long( item.getVersion().longValue() - 1 ) ); + + try { + withTxSession(s -> s.update(item)); + fail("expected stale write to fail"); + } + catch (Exception e) { + log.debug("Rollback was expected", e); + } + + // check the version value in the cache... + SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( VersionedItem.class.getName() ); + + Object entry = slcs.getEntries().get( item.getId() ); + Long cachedVersionValue; + cachedVersionValue = (Long) ((CacheEntry) entry).getVersion(); + assertEquals(initialVersion.longValue(), cachedVersionValue.longValue()); + + withTxSession(s -> { + VersionedItem item2 = s.load( VersionedItem.class, item.getId() ); + s.delete( item2 ); + }); + } + + @Test + @TestForIssue( jiraKey = "HHH-5690") + public void testPersistEntityFlushRollbackNotInEntityCache() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() ); + + ByRef itemId = new ByRef<>(null); + withTxSession(s -> { + Item item = new Item(); + item.setName("steve"); + item.setDescription("steve's item"); + s.persist(item); + s.flush(); + itemId.set(item.getId()); +// assertNotNull( slcs.getEntries().get( item.getId() ) ); + markRollbackOnly(s); + }); + + // item should not be in entity cache. + assertEquals( Collections.EMPTY_MAP, slcs.getEntries() ); + + withTxSession(s -> { + Item item = s.get( Item.class, itemId.get() ); + assertNull( item ); + }); + } + + @Test + @TestForIssue( jiraKey = "HHH-5690") + public void testPersistEntityFlushEvictGetRollbackNotInEntityCache() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() ); + + ByRef itemId = new ByRef<>(null); + withTxSession(s -> { + Item item = new Item(); + item.setName("steve"); + item.setDescription("steve's item"); + s.persist(item); + s.flush(); + itemId.set(item.getId()); + // item is cached on insert. +// assertNotNull( slcs.getEntries().get( item.getId() ) ); + s.evict(item); + assertEquals(slcs.getHitCount(), 0); + item = s.get(Item.class, item.getId()); + assertNotNull(item); +// assertEquals( slcs.getHitCount(), 1 ); +// assertNotNull( slcs.getEntries().get( item.getId() ) ); + markRollbackOnly(s); + }); + + // item should not be in entity cache. + //slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() ); + assertEquals(Collections.EMPTY_MAP, slcs.getEntries() ); + + withTxSession(s -> { + Item item = s.get(Item.class, itemId.get()); + assertNull(item); + }); + } + + @Test + public void testQueryCacheInvalidation() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() ); + sessionFactory().getCache().evictEntityRegion( Item.class.getName() ); + + assertEquals(0, slcs.getPutCount()); + assertEquals( 0, slcs.getElementCountInMemory() ); + assertEquals( 0, slcs.getEntries().size() ); + + ByRef itemRef = new ByRef<>(null); + withTxSession(s -> { + Item item = new Item(); + item.setName( "widget" ); + item.setDescription( "A really top-quality, full-featured widget." ); + s.persist( item ); + itemRef.set(item); + }); + + assertEquals( 1, slcs.getPutCount() ); + assertEquals( 1, slcs.getElementCountInMemory() ); + assertEquals( 1, slcs.getEntries().size() ); + + withTxSession(s -> { + Item item = s.get( Item.class, itemRef.get().getId() ); + assertEquals( slcs.getHitCount(), 1 ); + assertEquals( slcs.getMissCount(), 0 ); + item.setDescription( "A bog standard item" ); + }); + + assertEquals( slcs.getPutCount(), 2 ); + + CacheEntry entry = (CacheEntry) slcs.getEntries().get( itemRef.get().getId() ); + Serializable[] ser = entry.getDisassembledState(); + assertTrue( ser[0].equals( "widget" ) ); + assertTrue( ser[1].equals( "A bog standard item" ) ); + + withTxSession(s -> s.delete(itemRef.get())); + } + + @Test + public void testQueryCache() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + Item item = new Item( "chris", "Chris's Item" ); + + withTxSession(s -> s.persist( item )); + + // Delay added to guarantee that query cache results won't be considered + // as not up to date due to persist session and query results from first + // query happening within same 100ms gap. + Thread.sleep( 100 ); + + withTxSession(s -> s.createQuery( "from Item" ).setCacheable( true ).list()); + + withTxSession(s -> { + s.createQuery( "from Item" ).setCacheable( true ).list(); + assertEquals( 1, stats.getQueryCacheHitCount() ); + s.createQuery( "delete from Item" ).executeUpdate(); + }); + } + + @Test + public void testQueryCacheHitInSameTransaction() throws Exception { + Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + Item item = new Item( "galder", "Galder's Item" ); + + withTxSession(s -> s.persist( item )); + + // Delay added to guarantee that query cache results won't be considered + // as not up to date due to persist session and query results from first + // query happening within same 100ms gap. + Thread.sleep( 100 ); + + withTxSession(s -> { + s.createQuery("from Item").setCacheable(true).list(); + s.createQuery("from Item").setCacheable(true).list(); + assertEquals(1, stats.getQueryCacheHitCount()); + }); + + withTxSession(s -> s.createQuery( "delete from Item" ).executeUpdate()); + } + + @Test + public void testNaturalIdCached() throws Exception { + saveSomeCitizens(); + + // Clear the cache before the transaction begins + ReadWriteTest.this.cleanupCache(); + Thread.sleep(10); + + withTxSession(s -> { + State france = ReadWriteTest.this.getState(s, "Ile de France"); + Criteria criteria = s.createCriteria( Citizen.class ); + criteria.add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", france ) ); + criteria.setCacheable( true ); + + Statistics stats = sessionFactory().getStatistics(); + stats.setStatisticsEnabled( true ); + stats.clear(); + assertEquals( + "Cache hits should be empty", 0, stats + .getNaturalIdCacheHitCount() + ); + + // first query + List results = criteria.list(); + assertEquals( 1, results.size() ); + assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); + assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() ); + assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() ); + assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() ); + + // query a second time - result should be cached in session + criteria.list(); + assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); + assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() ); + assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() ); + assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() ); + + // cleanup + markRollbackOnly(s); + }); + } + + @Test + public void testNaturalIdLoaderCached() throws Exception { + final Statistics stats = sessionFactory().getStatistics(); + stats.setStatisticsEnabled( true ); + stats.clear(); + + assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); + assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() ); + assertEquals( "NaturalId Cache Puts", 0, stats.getNaturalIdCachePutCount() ); + assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() ); + + saveSomeCitizens(); + + assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); + assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() ); + assertEquals( "NaturalId Cache Puts", 2, stats.getNaturalIdCachePutCount() ); + assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() ); + + //Try NaturalIdLoadAccess after insert + final Citizen citizen = withTxSessionApply(s -> { + State france = ReadWriteTest.this.getState(s, "Ile de France"); + NaturalIdLoadAccess naturalIdLoader = s.byNaturalId(Citizen.class); + naturalIdLoader.using("ssn", "1234").using("state", france); + + //Not clearing naturalId caches, should be warm from entity loading + stats.clear(); + + // first query + Citizen c = naturalIdLoader.load(); + assertNotNull(c); + assertEquals("NaturalId Cache Hits", 1, stats.getNaturalIdCacheHitCount()); + assertEquals("NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount()); + assertEquals("NaturalId Cache Puts", 0, stats.getNaturalIdCachePutCount()); + assertEquals("NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount()); + + // cleanup + markRollbackOnly(s); + return c; + }); + + // TODO: Clear caches manually via cache manager (it's faster!!) + this.cleanupCache(); + Thread.sleep(10); + stats.setStatisticsEnabled( true ); + stats.clear(); + + //Try NaturalIdLoadAccess + withTxSession(s -> { + // first query + Citizen loadedCitizen = (Citizen) s.get( Citizen.class, citizen.getId() ); + assertNotNull( loadedCitizen ); + assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() ); + assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() ); + assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() ); + assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() ); + + // cleanup + markRollbackOnly(s); + }); + + // Try NaturalIdLoadAccess after load + withTxSession(s -> { + State france = ReadWriteTest.this.getState(s, "Ile de France"); + NaturalIdLoadAccess naturalIdLoader = s.byNaturalId(Citizen.class); + naturalIdLoader.using( "ssn", "1234" ).using( "state", france ); + + //Not clearing naturalId caches, should be warm from entity loading + stats.setStatisticsEnabled( true ); + stats.clear(); + + // first query + Citizen loadedCitizen = (Citizen) naturalIdLoader.load(); + assertNotNull( loadedCitizen ); + assertEquals( "NaturalId Cache Hits", 1, stats.getNaturalIdCacheHitCount() ); + assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() ); + assertEquals( "NaturalId Cache Puts", 0, stats.getNaturalIdCachePutCount() ); + assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() ); + + // cleanup + markRollbackOnly(s); + }); + + } + + @Test + public void testEntityCacheContentsAfterEvictAll() throws Exception { + final List citizens = saveSomeCitizens(); + + withTxSession(s -> { + Cache cache = s.getSessionFactory().getCache(); + + Statistics stats = sessionFactory().getStatistics(); + SecondLevelCacheStatistics slcStats = stats.getSecondLevelCacheStatistics(Citizen.class.getName()); + + assertTrue("2lc entity cache is expected to contain Citizen id = " + citizens.get(0).getId(), + cache.containsEntity(Citizen.class, citizens.get(0).getId())); + assertTrue("2lc entity cache is expected to contain Citizen id = " + citizens.get(1).getId(), + cache.containsEntity(Citizen.class, citizens.get(1).getId())); + assertEquals(2, slcStats.getPutCount()); + + cache.evictEntityRegions(); + Thread.sleep(10); + + assertEquals(0, slcStats.getElementCountInMemory()); + assertFalse("2lc entity cache is expected to not contain Citizen id = " + citizens.get(0).getId(), + cache.containsEntity(Citizen.class, citizens.get(0).getId())); + assertFalse("2lc entity cache is expected to not contain Citizen id = " + citizens.get(1).getId(), + cache.containsEntity(Citizen.class, citizens.get(1).getId())); + + Citizen citizen = s.load(Citizen.class, citizens.get(0).getId()); + assertNotNull(citizen); + assertNotNull(citizen.getFirstname()); // proxy gets resolved + assertEquals(1, slcStats.getMissCount()); + + // cleanup + markRollbackOnly(s); + }); + } + + @Test + public void testMultipleEvictAll() throws Exception { + final List citizens = saveSomeCitizens(); + + withTxSession(s -> { + Cache cache = s.getSessionFactory().getCache(); + + cache.evictEntityRegions(); + cache.evictEntityRegions(); + }); + withTxSession(s -> { + Cache cache = s.getSessionFactory().getCache(); + + cache.evictEntityRegions(); + + s.delete(s.load(Citizen.class, citizens.get(0).getId())); + s.delete(s.load(Citizen.class, citizens.get(1).getId())); + }); + } + + private List saveSomeCitizens() throws Exception { + final Citizen c1 = new Citizen(); + c1.setFirstname( "Emmanuel" ); + c1.setLastname( "Bernard" ); + c1.setSsn( "1234" ); + + final State france = new State(); + france.setName( "Ile de France" ); + c1.setState( france ); + + final Citizen c2 = new Citizen(); + c2.setFirstname( "Gavin" ); + c2.setLastname( "King" ); + c2.setSsn( "000" ); + final State australia = new State(); + australia.setName( "Australia" ); + c2.setState( australia ); + + withTxSession(s -> { + s.persist( australia ); + s.persist( france ); + s.persist( c1 ); + s.persist( c2 ); + }); + + List citizens = new ArrayList<>(2); + citizens.add(c1); + citizens.add(c2); + return citizens; + } + + private State getState(Session s, String name) { + Criteria criteria = s.createCriteria( State.class ); + criteria.add( Restrictions.eq("name", name) ); + criteria.setCacheable(true); + return (State) criteria.list().get( 0 ); + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTest.java new file mode 100644 index 0000000000..c265894189 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTest.java @@ -0,0 +1,64 @@ +package org.hibernate.test.cache.infinispan.functional; + +import org.hibernate.Session; +import org.hibernate.SessionBuilder; +import org.hibernate.cache.infinispan.util.Caches; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; +import org.hibernate.test.cache.infinispan.util.TxUtil; + +import javax.transaction.TransactionManager; + +import java.util.concurrent.Callable; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +/** + * @author Radim Vansa <rvansa@redhat.com> + */ +public abstract class SingleNodeTest extends AbstractFunctionalTest { + @Override + protected void afterSessionFactoryBuilt(SessionFactoryImplementor sessionFactory) { + super.afterSessionFactoryBuilt(sessionFactory); + JtaPlatform jtaPlatform = sessionFactory().getServiceRegistry().getService(JtaPlatform.class); + if (jtaPlatformClass != null) { + assertNotNull(jtaPlatform); + assertEquals(jtaPlatformClass, jtaPlatform.getClass()); + } + } + + protected void withTxSession(TxUtil.ThrowingConsumer consumer) throws Exception { + withTxSession(sessionFactory().withOptions(), consumer); + } + + protected void withTxSession(SessionBuilder sessionBuilder, TxUtil.ThrowingConsumer consumer) throws Exception { + JtaPlatform jtaPlatform = useJta ? sessionFactory().getServiceRegistry().getService(JtaPlatform.class) : null; + TxUtil.withTxSession(jtaPlatform, sessionBuilder, consumer); + } + + protected T withTxSessionApply(TxUtil.ThrowingFunction function) throws Exception { + JtaPlatform jtaPlatform = useJta ? sessionFactory().getServiceRegistry().getService(JtaPlatform.class) : null; + return TxUtil.withTxSessionApply(jtaPlatform, sessionFactory().withOptions(), function); + } + + protected T withTx(Callable callable) throws Exception { + if (useJta) { + TransactionManager tm = sessionFactory().getServiceRegistry().getService(JtaPlatform.class).retrieveTransactionManager(); + return Caches.withinTx(tm, () -> callable.call()); + } else { + return callable.call(); + } + } + + public void withSession(TxUtil.ThrowingConsumer consumer) throws E { + TxUtil.withSession(sessionFactory().withOptions(), consumer); + } + + + public R withSessionApply(TxUtil.ThrowingFunction function) throws E { + return TxUtil.withSessionApply(sessionFactory().withOptions(), function); + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTestCase.java deleted file mode 100644 index 4b5d12481b..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTestCase.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional; - -import java.util.Map; -import javax.transaction.Status; -import javax.transaction.TransactionManager; - -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.spi.RegionFactory; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.Environment; -import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; -import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; -import org.hibernate.resource.transaction.TransactionCoordinatorBuilder; -import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; - -import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.hibernate.test.cache.infinispan.tm.JtaPlatformImpl; -import org.junit.Before; - -import org.infinispan.configuration.parsing.ConfigurationBuilderHolder; -import org.infinispan.manager.EmbeddedCacheManager; -import org.infinispan.test.fwk.TestCacheManagerFactory; -import org.infinispan.util.logging.Log; -import org.infinispan.util.logging.LogFactory; -import org.junit.ClassRule; - -/** - * @author Galder Zamarreño - * @since 3.5 - */ -public abstract class SingleNodeTestCase extends BaseNonConfigCoreFunctionalTestCase { - private static final Log log = LogFactory.getLog( SingleNodeTestCase.class ); - protected TransactionManager tm; - - @ClassRule - public static final InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - - @Before - public void prepare() { - tm = getTransactionManager(); - } - - protected TransactionManager getTransactionManager() { - try { - Class jtaPlatformClass = getJtaPlatform(); - if ( jtaPlatformClass == null ) { - return null; - } - else { - return jtaPlatformClass.newInstance().retrieveTransactionManager(); - } - } - catch (Exception e) { - log.error( "Error", e ); - throw new RuntimeException( e ); - } - } - - @Override - public String[] getMappings() { - return new String[] { - "cache/infinispan/functional/Item.hbm.xml", - "cache/infinispan/functional/Customer.hbm.xml", - "cache/infinispan/functional/Contact.hbm.xml" - }; - } - - @Override - public String getCacheConcurrencyStrategy() { - return "transactional"; - } - - protected Class getCacheRegionFactory() { - return TestInfinispanRegionFactory.class; - } - - protected Class getTransactionCoordinatorBuilder() { - return JtaTransactionCoordinatorBuilderImpl.class; - } - - protected Class getConnectionProviderClass() { - return org.hibernate.test.cache.infinispan.tm.XaConnectionProvider.class; - } - - protected Class getJtaPlatform() { - return JtaPlatformImpl.class; - } - - protected boolean getUseQueryCache() { - return true; - } - - @Override - @SuppressWarnings("unchecked") - protected void addSettings(Map settings) { - super.addSettings( settings ); - - settings.put( Environment.USE_SECOND_LEVEL_CACHE, "true" ); - settings.put( Environment.GENERATE_STATISTICS, "true" ); - settings.put( Environment.USE_QUERY_CACHE, String.valueOf( getUseQueryCache() ) ); - settings.put( Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName() ); - - if ( getJtaPlatform() != null ) { - settings.put( AvailableSettings.JTA_PLATFORM, getJtaPlatform() ); - } - settings.put( Environment.TRANSACTION_COORDINATOR_STRATEGY, getTransactionCoordinatorBuilder().getName() ); - settings.put( Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName() ); - } - - protected void beginTx() throws Exception { - tm.begin(); - } - - protected void setRollbackOnlyTx() throws Exception { - tm.setRollbackOnly(); - } - - protected void setRollbackOnlyTx(Exception e) throws Exception { - log.error( "Error", e ); - tm.setRollbackOnly(); - throw e; - } - - protected void setRollbackOnlyTxExpected(Exception e) throws Exception { - log.debug( "Expected behaivour", e ); - tm.setRollbackOnly(); - } - - protected void commitOrRollbackTx() throws Exception { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - tm.rollback(); - } - } - - public static class TestInfinispanRegionFactory extends InfinispanRegionFactory { - - public TestInfinispanRegionFactory() { - super(); // For reflection-based instantiation - } - - @Override - protected EmbeddedCacheManager createCacheManager(ConfigurationBuilderHolder holder) { - return TestCacheManagerFactory.createClusteredCacheManager(holder); - } - - } - -} \ No newline at end of file diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java deleted file mode 100644 index 63dac18200..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional.bulk; - -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.transaction.Status; -import javax.transaction.TransactionManager; - -import org.hibernate.FlushMode; -import org.hibernate.Session; -import org.hibernate.cache.spi.RegionFactory; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.Environment; -import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; -import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; -import org.hibernate.resource.transaction.TransactionCoordinatorBuilder; -import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; -import org.hibernate.stat.SecondLevelCacheStatistics; - -import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.hibernate.test.cache.infinispan.functional.Contact; -import org.hibernate.test.cache.infinispan.functional.Customer; -import org.hibernate.test.cache.infinispan.functional.SingleNodeTestCase; -import org.hibernate.test.cache.infinispan.tm.JtaPlatformImpl; -import org.junit.ClassRule; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -/** - * BulkOperationsTestCase. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class BulkOperationsTestCase extends BaseNonConfigCoreFunctionalTestCase { - - @ClassRule - public static final InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - - private TransactionManager tm; - - @Override - public String[] getMappings() { - return new String[] { - "cache/infinispan/functional/Contact.hbm.xml", - "cache/infinispan/functional/Customer.hbm.xml" - }; - } - - @Override - public String getCacheConcurrencyStrategy() { - return "transactional"; - } - - protected Class getCacheRegionFactory() { - return SingleNodeTestCase.TestInfinispanRegionFactory.class; - } - - - protected Class getTransactionCoordinatorBuilder() { - return JtaTransactionCoordinatorBuilderImpl.class; - } - - protected Class getConnectionProviderClass() { - return org.hibernate.test.cache.infinispan.tm.XaConnectionProvider.class; - } - - protected JtaPlatform getJtaPlatform() { - return new JtaPlatformImpl(); - } - - @Override - @SuppressWarnings("unchecked") - protected void addSettings(Map settings) { - super.addSettings( settings ); - - settings.put( Environment.USE_SECOND_LEVEL_CACHE, "true" ); - settings.put( Environment.USE_QUERY_CACHE, "false" ); - settings.put( Environment.GENERATE_STATISTICS, "true" ); - settings.put( Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName() ); - settings.put( Environment.TRANSACTION_COORDINATOR_STRATEGY, getTransactionCoordinatorBuilder().getName() ); - settings.put( AvailableSettings.JTA_PLATFORM, getJtaPlatform() ); - settings.put( Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName() ); - } - - @Test - public void testBulkOperations() throws Throwable { - boolean cleanedUp = false; - try { - tm = getJtaPlatform().retrieveTransactionManager(); - - createContacts(); - - List rhContacts = getContactsByCustomer( "Red Hat" ); - assertNotNull( "Red Hat contacts exist", rhContacts ); - assertEquals( "Created expected number of Red Hat contacts", 10, rhContacts.size() ); - - SecondLevelCacheStatistics contactSlcs = sessionFactory() - .getStatistics() - .getSecondLevelCacheStatistics( Contact.class.getName() ); - assertEquals( 20, contactSlcs.getElementCountInMemory() ); - - assertEquals( "Deleted all Red Hat contacts", 10, deleteContacts() ); - assertEquals( 0, contactSlcs.getElementCountInMemory() ); - - List jbContacts = getContactsByCustomer( "JBoss" ); - assertNotNull( "JBoss contacts exist", jbContacts ); - assertEquals( "JBoss contacts remain", 10, jbContacts.size() ); - - for ( Integer id : rhContacts ) { - assertNull( "Red Hat contact " + id + " cannot be retrieved", getContact( id ) ); - } - rhContacts = getContactsByCustomer( "Red Hat" ); - if ( rhContacts != null ) { - assertEquals( "No Red Hat contacts remain", 0, rhContacts.size() ); - } - - updateContacts( "Kabir", "Updated" ); - assertEquals( 0, contactSlcs.getElementCountInMemory() ); - for ( Integer id : jbContacts ) { - Contact contact = getContact( id ); - assertNotNull( "JBoss contact " + id + " exists", contact ); - String expected = ("Kabir".equals( contact.getName() )) ? "Updated" : "2222"; - assertEquals( "JBoss contact " + id + " has correct TLF", expected, contact.getTlf() ); - } - - List updated = getContactsByTLF( "Updated" ); - assertNotNull( "Got updated contacts", updated ); - assertEquals("Updated contacts", 5, updated.size()); - - assertEquals( 10, contactSlcs.getElementCountInMemory() ); - updateContactsWithOneManual( "Kabir", "UpdatedAgain" ); - assertEquals( 0, contactSlcs.getElementCountInMemory()); - for ( Integer id : jbContacts ) { - Contact contact = getContact( id ); - assertNotNull( "JBoss contact " + id + " exists", contact ); - String expected = ("Kabir".equals( contact.getName() )) ? "UpdatedAgain" : "2222"; - assertEquals( "JBoss contact " + id + " has correct TLF", expected, contact.getTlf() ); - } - - updated = getContactsByTLF( "UpdatedAgain" ); - assertNotNull( "Got updated contacts", updated ); - assertEquals( "Updated contacts", 5, updated.size() ); - } - catch (Throwable t) { - cleanedUp = true; - cleanup( true ); - throw t; - } - finally { - // cleanup the db so we can run this test multiple times w/o restarting the cluster - if ( !cleanedUp ) { - cleanup( false ); - } - } - } - - public void createContacts() throws Exception { - tm.begin(); - try { - for ( int i = 0; i < 10; i++ ) { - createCustomer( i ); - } - } - catch (Exception e) { - tm.setRollbackOnly(); - throw e; - } - finally { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - tm.rollback(); - } - } - } - - public int deleteContacts() throws Exception { - String deleteHQL = "delete Contact where customer in "; - deleteHQL += " (select customer FROM Customer as customer "; - deleteHQL += " where customer.name = :cName)"; - - tm.begin(); - try { - Session session = sessionFactory().getCurrentSession(); - int rowsAffected = session.createQuery( deleteHQL ).setFlushMode( FlushMode.AUTO ) - .setParameter( "cName", "Red Hat" ).executeUpdate(); - tm.commit(); - return rowsAffected; - } - catch (Exception e) { - tm.setRollbackOnly(); - throw e; - } - finally { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - try { - tm.rollback(); - } - catch (Exception ee) { - // ignored - } - } - } - } - - @SuppressWarnings( {"unchecked"}) - public List getContactsByCustomer(String customerName) throws Exception { - String selectHQL = "select contact.id from Contact contact"; - selectHQL += " where contact.customer.name = :cName"; - - tm.begin(); - try { - - Session session = sessionFactory().getCurrentSession(); - return session.createQuery( selectHQL ) - .setFlushMode( FlushMode.AUTO ) - .setParameter( "cName", customerName ) - .list(); - } - catch (Exception e) { - tm.setRollbackOnly(); - throw e; - } - finally { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - tm.rollback(); - } - } - } - - @SuppressWarnings( {"unchecked"}) - public List getContactsByTLF(String tlf) throws Exception { - String selectHQL = "select contact.id from Contact contact"; - selectHQL += " where contact.tlf = :cTLF"; - - tm.begin(); - try { - Session session = sessionFactory().getCurrentSession(); - return session.createQuery( selectHQL ) - .setFlushMode( FlushMode.AUTO ) - .setParameter( "cTLF", tlf ) - .list(); - } - catch (Exception e) { - tm.setRollbackOnly(); - throw e; - } - finally { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - tm.rollback(); - } - } - } - - public int updateContacts(String name, String newTLF) throws Exception { - String updateHQL = "update Contact set tlf = :cNewTLF where name = :cName"; - tm.begin(); - try { - Session session = sessionFactory().getCurrentSession(); - return session.createQuery( updateHQL ) - .setFlushMode( FlushMode.AUTO ) - .setParameter( "cNewTLF", newTLF ) - .setParameter( "cName", name ) - .executeUpdate(); - } - catch (Exception e) { - tm.setRollbackOnly(); - throw e; - } - finally { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - tm.rollback(); - } - } - } - - public int updateContactsWithOneManual(String name, String newTLF) throws Exception { - String queryHQL = "from Contact c where c.name = :cName"; - String updateHQL = "update Contact set tlf = :cNewTLF where name = :cName"; - tm.begin(); - try { - Session session = sessionFactory().getCurrentSession(); - @SuppressWarnings("unchecked") - List list = session.createQuery( queryHQL ).setParameter( "cName", name ).list(); - list.get( 0 ).setTlf( newTLF ); - return session.createQuery( updateHQL ) - .setFlushMode( FlushMode.AUTO ) - .setParameter( "cNewTLF", newTLF ) - .setParameter( "cName", name ) - .executeUpdate(); - } - catch (Exception e) { - tm.setRollbackOnly(); - throw e; - } - finally { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - tm.rollback(); - } - } - } - - public Contact getContact(Integer id) throws Exception { - tm.begin(); - try { - Session session = sessionFactory().getCurrentSession(); - return (Contact) session.get( Contact.class, id ); - } - catch (Exception e) { - tm.setRollbackOnly(); - throw e; - } - finally { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - tm.rollback(); - } - } - } - - public void cleanup(boolean ignore) throws Exception { - String deleteContactHQL = "delete from Contact"; - String deleteCustomerHQL = "delete from Customer"; - tm.begin(); - try { - Session session = sessionFactory().getCurrentSession(); - session.createQuery( deleteContactHQL ).setFlushMode( FlushMode.AUTO ).executeUpdate(); - session.createQuery( deleteCustomerHQL ).setFlushMode( FlushMode.AUTO ).executeUpdate(); - } - catch (Exception e) { - tm.setRollbackOnly(); - throw e; - } - finally { - if ( tm.getStatus() == Status.STATUS_ACTIVE ) { - tm.commit(); - } - else { - if ( !ignore ) { - try { - tm.rollback(); - } - catch (Exception ee) { - // ignored - } - } - } - } - } - - private Customer createCustomer(int id) throws Exception { - System.out.println( "CREATE CUSTOMER " + id ); - try { - Customer customer = new Customer(); - customer.setName( (id % 2 == 0) ? "JBoss" : "Red Hat" ); - Set contacts = new HashSet(); - - Contact kabir = new Contact(); - kabir.setCustomer( customer ); - kabir.setName( "Kabir" ); - kabir.setTlf( "1111" ); - contacts.add( kabir ); - - Contact bill = new Contact(); - bill.setCustomer( customer ); - bill.setName( "Bill" ); - bill.setTlf( "2222" ); - contacts.add( bill ); - - customer.setContacts( contacts ); - - Session s = openSession(); - s.getTransaction().begin(); - s.persist( customer ); - s.getTransaction().commit(); - s.close(); - - return customer; - } - finally { - System.out.println( "CREATE CUSTOMER " + id + " - END" ); - } - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/Account.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/Account.java deleted file mode 100644 index f0de895477..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/Account.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional.classloader; -import java.io.Serializable; - -/** - * Comment - * - * @author Brian Stansberry - */ -public class Account implements Serializable { - - private static final long serialVersionUID = 1L; - - private Integer id; - private AccountHolder accountHolder; - private Integer balance; - private String branch; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public AccountHolder getAccountHolder() { - return accountHolder; - } - - public void setAccountHolder(AccountHolder accountHolder) { - this.accountHolder = accountHolder; - } - - public Integer getBalance() { - return balance; - } - - public void setBalance(Integer balance) { - this.balance = balance; - } - - public String getBranch() { - return branch; - } - - public void setBranch(String branch) { - this.branch = branch; - } - - public boolean equals(Object obj) { - if (obj == this) - return true; - if (!(obj instanceof Account)) - return false; - Account acct = (Account) obj; - if (!safeEquals(id, acct.id)) - return false; - if (!safeEquals(branch, acct.branch)) - return false; - if (!safeEquals(balance, acct.balance)) - return false; - if (!safeEquals(accountHolder, acct.accountHolder)) - return false; - return true; - } - - @Override - public int hashCode() { - int result = 17; - result = result * 31 + safeHashCode(id); - result = result * 31 + safeHashCode(branch); - result = result * 31 + safeHashCode(balance); - result = result * 31 + safeHashCode(accountHolder); - return result; - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(getClass().getName()); - sb.append("[id="); - sb.append(id); - sb.append(",branch="); - sb.append(branch); - sb.append(",balance="); - sb.append(balance); - sb.append(",accountHolder="); - sb.append(accountHolder); - sb.append("]"); - return sb.toString(); - } - - private static int safeHashCode(Object obj) { - return obj == null ? 0 : obj.hashCode(); - } - - private static boolean safeEquals(Object a, Object b) { - return (a == b || (a != null && a.equals(b))); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/AccountHolder.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/AccountHolder.java deleted file mode 100644 index 09682fe9cd..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/AccountHolder.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional.classloader; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; - -/** - * Comment - * - * @author Brian Stansberry - */ -public class AccountHolder implements Serializable { - private static final long serialVersionUID = 1L; - - private String lastName; - private String ssn; - private transient boolean deserialized; - - public AccountHolder() { - this("Stansberry", "123-456-7890"); - } - - public AccountHolder(String lastName, String ssn) { - this.lastName = lastName; - this.ssn = ssn; - } - - public String getLastName() { - return this.lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getSsn() { - return ssn; - } - - public void setSsn(String ssn) { - this.ssn = ssn; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) - return true; - if (!(obj instanceof AccountHolder)) - return false; - AccountHolder pk = (AccountHolder) obj; - if (!lastName.equals(pk.lastName)) - return false; - if (!ssn.equals(pk.ssn)) - return false; - return true; - } - - @Override - public int hashCode() { - int result = 17; - result = result * 31 + lastName.hashCode(); - result = result * 31 + ssn.hashCode(); - return result; - } - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(getClass().getName()); - sb.append("[lastName="); - sb.append(lastName); - sb.append(",ssn="); - sb.append(ssn); - sb.append(",deserialized="); - sb.append(deserialized); - sb.append("]"); - return sb.toString(); - } - - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - ois.defaultReadObject(); - deserialized = true; - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/CacheAccessListener.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/CacheAccessListener.java deleted file mode 100644 index 9e26134ac6..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/CacheAccessListener.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional.classloader; - -import java.util.HashSet; -import java.util.Set; - -import org.infinispan.notifications.Listener; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited; -import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent; -import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent; -import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent; -import org.jboss.logging.Logger; - -@Listener -public class CacheAccessListener { - private static final Logger log = Logger.getLogger( CacheAccessListener.class ); - - HashSet modified = new HashSet(); - HashSet accessed = new HashSet(); - - public void clear() { - modified.clear(); - accessed.clear(); - } - - @CacheEntryModified - public void nodeModified( CacheEntryModifiedEvent event ) { - if (!event.isPre()) { - Object key = event.getKey(); - log.info("Modified node " + key); - modified.add(key.toString()); - } - } - - @CacheEntryCreated - public void nodeCreated( CacheEntryCreatedEvent event ) { - if (!event.isPre()) { - Object key = event.getKey(); - log.info("Created node " + key); - modified.add(key.toString()); - } - } - - @CacheEntryVisited - public void nodeVisited( CacheEntryVisitedEvent event ) { - if (!event.isPre()) { - Object key = event.getKey(); - log.info("Visited node " + key); - accessed.add(key.toString()); - } - } - - public boolean getSawRegionModification( Object key ) { - return getSawRegion(key, modified); - } - - public int getSawRegionModificationCount() { - return modified.size(); - } - - public void clearSawRegionModification() { - modified.clear(); - } - - public boolean getSawRegionAccess( Object key ) { - return getSawRegion(key, accessed); - } - - public int getSawRegionAccessCount() { - return accessed.size(); - } - - public void clearSawRegionAccess() { - accessed.clear(); - } - - private boolean getSawRegion( Object key, - Set sawEvents ) { - if (sawEvents.contains(key)) { - sawEvents.remove(key); - return true; - } - return false; - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/ClassLoaderTestDAO.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/ClassLoaderTestDAO.java deleted file mode 100644 index e35f7fb3d2..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/ClassLoaderTestDAO.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional.classloader; - -import java.lang.reflect.Method; -import java.util.Iterator; -import java.util.List; -import javax.transaction.TransactionManager; - -import org.infinispan.util.logging.Log; -import org.infinispan.util.logging.LogFactory; - -import org.hibernate.Query; -import org.hibernate.Session; -import org.hibernate.SessionFactory; - -/** - * Comment - * - * @author Brian Stansberry - */ -public class ClassLoaderTestDAO { - private static final Log log = LogFactory.getLog(ClassLoaderTestDAO.class); - - private SessionFactory sessionFactory; - private TransactionManager tm; - - private Class acctClass; - private Class holderClass; - private Method setId; - private Method setBalance; - private Method setBranch; - private Method setHolder; - private Object smith; - private Object jones; - private Object barney; - private Method setName; - private Method setSsn; - - public ClassLoaderTestDAO(SessionFactory factory, TransactionManager tm) throws Exception { - this.sessionFactory = factory; - this.tm = tm; - - acctClass = Thread.currentThread().getContextClassLoader().loadClass( - getClass().getPackage().getName() + ".Account"); - holderClass = Thread.currentThread().getContextClassLoader().loadClass( - getClass().getPackage().getName() + ".AccountHolder"); - setId = acctClass.getMethod("setId", Integer.class); - setBalance = acctClass.getMethod("setBalance", Integer.class); - setBranch = acctClass.getMethod("setBranch", String.class); - setHolder = acctClass.getMethod("setAccountHolder", holderClass); - - setName = holderClass.getMethod("setLastName", String.class); - setSsn = holderClass.getMethod("setSsn", String.class); - - smith = holderClass.newInstance(); - setName.invoke(smith, "Smith"); - setSsn.invoke(smith, "1000"); - - jones = holderClass.newInstance(); - setName.invoke(jones, "Jones"); - setSsn.invoke(jones, "2000"); - - barney = holderClass.newInstance(); - setName.invoke(barney, "Barney"); - setSsn.invoke(barney, "3000"); - } - - public Object getSmith() { - return smith; - } - - public Object getJones() { - return jones; - } - - public Object getBarney() { - return barney; - } - - public void updateAccountBranch(Integer id, String branch) throws Exception { - log.debug("Updating account " + id + " to branch " + branch); - tm.begin(); - try { - Session session = sessionFactory.getCurrentSession(); - Object account = session.get(acctClass, id); - log.debug("Set branch " + branch); - setBranch.invoke(account, branch); - session.update(account); - tm.commit(); - } catch (Exception e) { - log.error("rolling back", e); - tm.rollback(); - throw e; - } - log.debug("Updated account " + id + " to branch " + branch); - } - - public int getCountForBranch(String branch, boolean useRegion) throws Exception { - tm.begin(); - try { - Query query = sessionFactory.getCurrentSession().createQuery( - "select account from Account as account where account.branch = :branch"); - query.setString("branch", branch); - if (useRegion) { - query.setCacheRegion("AccountRegion"); - } - query.setCacheable(true); - int result = query.list().size(); - tm.commit(); - return result; - } catch (Exception e) { - log.error("rolling back", e); - tm.rollback(); - throw e; - } - - } - - public void createAccount(Object holder, Integer id, Integer openingBalance, String branch) throws Exception { - log.debug("Creating account " + id); - tm.begin(); - try { - Object account = acctClass.newInstance(); - setId.invoke(account, id); - setHolder.invoke(account, holder); - setBalance.invoke(account, openingBalance); - log.debug("Set branch " + branch); - setBranch.invoke(account, branch); - sessionFactory.getCurrentSession().persist(account); - tm.commit(); - } catch (Exception e) { - log.error("rolling back", e); - tm.rollback(); - throw e; - } - - log.debug("Created account " + id); - } - - public Account getAccount(Integer id) throws Exception { - log.debug("Getting account " + id); - Session session = sessionFactory.openSession(); - try { - return (Account) session.get(acctClass, id); - } finally { - session.close(); - } - } - - public Account getAccountWithRefresh(Integer id) throws Exception { - log.debug("Getting account " + id + " with refresh"); - tm.begin(); - try { - Session session = sessionFactory.getCurrentSession(); - Account acct = (Account) session.get(acctClass, id); - session.refresh(acct); - acct = (Account) session.get(acctClass, id); - tm.commit(); - return acct; - } catch (Exception e) { - log.error("rolling back", e); - tm.rollback(); - throw e; - } - } - - public void updateAccountBalance(Integer id, Integer newBalance) throws Exception { - log.debug("Updating account " + id + " to balance " + newBalance); - tm.begin(); - try { - Session session = sessionFactory.getCurrentSession(); - Object account = session.get(acctClass, id); - setBalance.invoke(account, newBalance); - session.update(account); - tm.commit(); - } catch (Exception e) { - log.error("rolling back", e); - tm.rollback(); - throw e; - } - log.debug("Updated account " + id + " to balance " + newBalance); - } - - public String getBranch(Object holder, boolean useRegion) throws Exception { - tm.begin(); - try { - Query query = sessionFactory.getCurrentSession().createQuery( - "select account.branch from Account as account where account.accountHolder = ?"); - query.setParameter(0, holder); - if (useRegion) { - query.setCacheRegion("AccountRegion"); - } - query.setCacheable(true); - String result = (String) query.list().get(0); - tm.commit(); - return result; - } catch (Exception e) { - log.error("rolling back", e); - tm.rollback(); - throw e; - } - } - - public int getTotalBalance(Object holder, boolean useRegion) throws Exception { - List results = null; - tm.begin(); - try { - Query query = sessionFactory.getCurrentSession().createQuery( - "select account.balance from Account as account where account.accountHolder = ?"); - query.setParameter(0, holder); - if (useRegion) { - query.setCacheRegion("AccountRegion"); - } - query.setCacheable(true); - results = query.list(); - tm.commit(); - } catch (Exception e) { - log.error("rolling back", e); - tm.rollback(); - throw e; - } - - int total = 0; - if (results != null) { - for (Iterator it = results.iterator(); it.hasNext();) { - total += ((Integer) it.next()).intValue(); - System.out.println("Total = " + total); - } - } - return total; - } - - public void cleanup() throws Exception { - internalCleanup(); - } - - private void internalCleanup() throws Exception { - if (sessionFactory != null) { - tm.begin(); - try { - - Session session = sessionFactory.getCurrentSession(); - Query query = session.createQuery("select account from Account as account"); - List accts = query.list(); - if (accts != null) { - for (Iterator it = accts.iterator(); it.hasNext();) { - try { - Object acct = it.next(); - log.info("Removing " + acct); - session.delete(acct); - } catch (Exception ignored) { - } - } - } - tm.commit(); - } catch (Exception e) { - tm.rollback(); - throw e; - } - } - } - - public void remove() { - try { - internalCleanup(); - } catch (Exception e) { - log.error("Caught exception in remove", e); - } - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedCacheTestSetup.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedCacheTestSetup.java deleted file mode 100644 index 7d7b97667c..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedCacheTestSetup.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ - -package org.hibernate.test.cache.infinispan.functional.classloader; - -import junit.framework.Test; - -import org.hibernate.test.cache.infinispan.functional.cluster.ClusterAwareRegionFactory; -import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl; - -/** - * A TestSetup that uses SelectedClassnameClassLoader to ensure that certain classes are not visible - * to Infinispan or JGroups' classloader. - * - * @author Galder Zamarreño - */ -public class IsolatedCacheTestSetup extends SelectedClassnameClassLoaderTestSetup { - - private String[] isolatedClasses; - private String cacheConfig; - - /** - * Create a new IsolatedCacheTestSetup. - */ - public IsolatedCacheTestSetup(Test test, String[] isolatedClasses) { - super(test, null, null, isolatedClasses); - this.isolatedClasses = isolatedClasses; - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - // At this point the TCCL cannot see the isolatedClasses - // We want the caches to use this CL as their default classloader - ClassLoader tccl = Thread.currentThread().getContextClassLoader(); - - // Now make the isolatedClasses visible to the test driver itself - SelectedClassnameClassLoader visible = new SelectedClassnameClassLoader(isolatedClasses, null, null, tccl); - Thread.currentThread().setContextClassLoader(visible); - } - - @Override - protected void tearDown() throws Exception { - try { - super.tearDown(); - } finally { - ClusterAwareRegionFactory.clearCacheManagers(); - DualNodeJtaTransactionManagerImpl.cleanupTransactions(); - DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers(); - } - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedClassLoaderTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedClassLoaderTest.java deleted file mode 100644 index d67fa6cdfd..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedClassLoaderTest.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional.classloader; - -import java.util.Map; -import javax.transaction.TransactionManager; - -import org.hibernate.SessionFactory; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.internal.StandardQueryCache; - -import org.hibernate.test.cache.infinispan.functional.cluster.ClusterAwareRegionFactory; -import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl; -import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeTestCase; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -import org.infinispan.Cache; -import org.infinispan.manager.CacheContainer; -import org.infinispan.manager.EmbeddedCacheManager; - -import org.jboss.logging.Logger; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -/** - * Tests entity and query caching when class of objects being cached are not visible to Infinispan's classloader. Also serves as a - * general integration test. - *

- * This test stores an object (AccountHolder) that isn't visible to the Infinispan classloader in the cache in two places: 1) As - * part of the value tuple in an Account entity 2) As part of the FQN in a query cache entry (see query in - * ClassLoaderTestDAO.getBranch()) - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class IsolatedClassLoaderTest extends DualNodeTestCase { - private static final Logger log = Logger.getLogger( IsolatedClassLoaderTest.class ); - - protected static final long SLEEP_TIME = 300L; - - private Cache localQueryCache; - private CacheAccessListener localQueryListener; - - private Cache remoteQueryCache; - private CacheAccessListener remoteQueryListener; - - private static ClassLoader originalTCCL; - -// private static ClassLoader visibleClassesCl; - - @BeforeClass - public static void prepareClassLoader() { - final String packageName = IsolatedClassLoaderTest.class.getPackage().getName(); - final String[] classes = new String[] {packageName + ".Account", packageName + ".AccountHolder"}; - originalTCCL = Thread.currentThread().getContextClassLoader(); - // Most likely, it will point to system classloader - ClassLoader parent = originalTCCL == null ? IsolatedClassLoaderTest.class.getClassLoader() : originalTCCL; - - // First, create a classloader where classes won't be found - ClassLoader selectedTCCL = new SelectedClassnameClassLoader( null, null, classes, parent ); - - // Now, make the class visible to the test driver - SelectedClassnameClassLoader visible = new SelectedClassnameClassLoader( classes, null, null, selectedTCCL ); - Thread.currentThread().setContextClassLoader( visible ); -// visibleClassesCl = new SelectedClassnameClassLoader(classes, null, null, selectedTCCL); -// Thread.currentThread().setContextClassLoader(selectedTCCL); - } - - @AfterClass - public static void resetClassLoader() { - ClusterAwareRegionFactory.clearCacheManagers(); - DualNodeJtaTransactionManagerImpl.cleanupTransactions(); - DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers(); - Thread.currentThread().setContextClassLoader( originalTCCL ); - } - - @Override - public String[] getMappings() { - return new String[] {"cache/infinispan/functional/classloader/Account.hbm.xml"}; - } - - @Override - @SuppressWarnings("unchecked") - protected void applyStandardSettings(Map settings) { - super.applyStandardSettings( settings ); - - settings.put( InfinispanRegionFactory.QUERY_CACHE_RESOURCE_PROP, "replicated-query" ); - settings.put( "hibernate.cache.infinispan.AccountRegion.cfg", "replicated-query" ); - } - - @Override - protected void cleanupTransactionManagement() { - // Don't clean up the managers, just the transactions - // Managers are still needed by the long-lived caches - DualNodeJtaTransactionManagerImpl.cleanupTransactions(); - } - - @Override - protected void cleanupTest() throws Exception { - try { - // Clear the local account cache - sessionFactory().getCache().evictEntityRegion( Account.class.getName() ); - if ( localQueryCache != null && localQueryListener != null ) { - localQueryCache.removeListener( localQueryListener ); - } - if ( remoteQueryCache != null && remoteQueryListener != null ) { - remoteQueryCache.removeListener( remoteQueryListener ); - } - } - finally { - super.cleanupTest(); - } - } - - @Ignore("Infinispan caches now use whichever classloader is associated on " + - "construction, i.e. deployment JPA app, so does not rely on TCCL.") - @Test - public void testIsolatedSetup() throws Exception { - // Bind a listener to the "local" cache - // Our region factory makes its CacheManager available to us - CacheContainer localManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTestCase.LOCAL ); - Cache localReplicatedCache = localManager.getCache( "replicated-entity" ); - - // Bind a listener to the "remote" cache - CacheContainer remoteManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTestCase.REMOTE ); - Cache remoteReplicatedCache = remoteManager.getCache( "replicated-entity" ); - - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader( cl.getParent() ); - log.info( "TCCL is " + cl.getParent() ); - - Account acct = new Account(); - acct.setAccountHolder( new AccountHolder() ); - - try { - localReplicatedCache.put( "isolated1", acct ); - // With lazy deserialization, retrieval in remote forces class resolution - remoteReplicatedCache.get( "isolated1" ); - fail( "Should not have succeeded in putting acct -- classloader not isolated" ); - } - catch (Exception e) { - if ( e.getCause() instanceof ClassNotFoundException ) { - log.info( "Caught exception as desired", e ); - } - else { - throw new IllegalStateException( "Unexpected exception", e ); - } - } - - Thread.currentThread().setContextClassLoader( cl ); - log.info( "TCCL is " + cl ); - localReplicatedCache.put( "isolated2", acct ); - assertEquals( acct.getClass().getName(), remoteReplicatedCache.get( "isolated2" ).getClass().getName() ); - } - - @Ignore("Infinispan caches now use whichever classloader is associated on " + - "construction, i.e. deployment JPA app, so does not rely on TCCL.") - @Test - public void testClassLoaderHandlingNamedQueryRegion() throws Exception { - rebuildSessionFactory(); - queryTest( true ); - } - - @Ignore("Infinispan caches now use whichever classloader is associated on " + - "construction, i.e. deployment JPA app, so does not rely on TCCL.") - @Test - public void testClassLoaderHandlingStandardQueryCache() throws Exception { - rebuildSessionFactory(); - queryTest( false ); - } - - protected void queryTest(boolean useNamedRegion) throws Exception { - // Bind a listener to the "local" cache - // Our region factory makes its CacheManager available to us - EmbeddedCacheManager localManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTestCase.LOCAL ); - // Bind a listener to the "remote" cache - EmbeddedCacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTestCase.REMOTE ); - String cacheName; - if ( useNamedRegion ) { - cacheName = "AccountRegion"; // As defined by ClassLoaderTestDAO via calls to query.setCacheRegion - // Define cache configurations for region early to avoid ending up with local caches for this region - localManager.defineConfiguration( - cacheName, - localManager.getCacheConfiguration( "replicated-query" ) - ); - remoteManager.defineConfiguration( - cacheName, - remoteManager.getCacheConfiguration( "replicated-query" ) - ); - } - else { - cacheName = "replicated-query"; - } - - localQueryCache = localManager.getCache( cacheName ); - localQueryListener = new CacheAccessListener(); - localQueryCache.addListener( localQueryListener ); - - TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance( DualNodeTestCase.LOCAL ); - - remoteQueryCache = remoteManager.getCache( cacheName ); - remoteQueryListener = new CacheAccessListener(); - remoteQueryCache.addListener( remoteQueryListener ); - - TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance( DualNodeTestCase.REMOTE ); - - SessionFactory localFactory = sessionFactory(); - SessionFactory remoteFactory = secondNodeEnvironment().getSessionFactory(); - - ClassLoaderTestDAO dao0 = new ClassLoaderTestDAO( localFactory, localTM ); - ClassLoaderTestDAO dao1 = new ClassLoaderTestDAO( remoteFactory, remoteTM ); - - // Initial ops on node 0 - setupEntities( dao0 ); - - String branch = "63088"; - // Query on post code count - assertEquals( branch + " has correct # of accounts", 6, dao0.getCountForBranch( branch, useNamedRegion ) ); - - assertEquals( "Query cache used", 1, localQueryListener.getSawRegionModificationCount() ); - localQueryListener.clearSawRegionModification(); - -// log.info("First query (get count for branch + " + branch + " ) on node0 done, contents of local query cache are: " + TestingUtil.printCache(localQueryCache)); - - // Sleep a bit to allow async repl to happen - sleep( SLEEP_TIME ); - - assertEquals( "Query cache used", 1, remoteQueryListener.getSawRegionModificationCount() ); - remoteQueryListener.clearSawRegionModification(); - - // Do query again from node 1 - log.info( "Repeat first query (get count for branch + " + branch + " ) on remote node" ); - assertEquals( "63088 has correct # of accounts", 6, dao1.getCountForBranch( branch, useNamedRegion ) ); - assertEquals( "Query cache used", 1, remoteQueryListener.getSawRegionModificationCount() ); - remoteQueryListener.clearSawRegionModification(); - - sleep( SLEEP_TIME ); - - assertEquals( "Query cache used", 1, localQueryListener.getSawRegionModificationCount() ); - localQueryListener.clearSawRegionModification(); - - log.info( "First query on node 1 done" ); - - // Sleep a bit to allow async repl to happen - sleep( SLEEP_TIME ); - - // Do some more queries on node 0 - log.info( "Do query Smith's branch" ); - assertEquals( "Correct branch for Smith", "94536", dao0.getBranch( dao0.getSmith(), useNamedRegion ) ); - log.info( "Do query Jone's balance" ); - assertEquals( "Correct high balances for Jones", 40, dao0.getTotalBalance( dao0.getJones(), useNamedRegion ) ); - - assertEquals( "Query cache used", 2, localQueryListener.getSawRegionModificationCount() ); - localQueryListener.clearSawRegionModification(); -// // Clear the access state -// localQueryListener.getSawRegionAccess("???"); - - log.info( "Second set of queries on node0 done" ); - - // Sleep a bit to allow async repl to happen - sleep( SLEEP_TIME ); - - // Check if the previous queries replicated - assertEquals( "Query cache remotely modified", 2, remoteQueryListener.getSawRegionModificationCount() ); - remoteQueryListener.clearSawRegionModification(); - - log.info( "Repeat second set of queries on node1" ); - - // Do queries again from node 1 - log.info( "Again query Smith's branch" ); - assertEquals( "Correct branch for Smith", "94536", dao1.getBranch( dao1.getSmith(), useNamedRegion ) ); - log.info( "Again query Jone's balance" ); - assertEquals( "Correct high balances for Jones", 40, dao1.getTotalBalance( dao1.getJones(), useNamedRegion ) ); - - // Should be no change; query was already there - assertEquals( "Query cache modified", 0, remoteQueryListener.getSawRegionModificationCount() ); - assertEquals( "Query cache accessed", 2, remoteQueryListener.getSawRegionAccessCount() ); - remoteQueryListener.clearSawRegionAccess(); - - log.info( "Second set of queries on node1 done" ); - - // allow async to propagate - sleep( SLEEP_TIME ); - - // Modify underlying data on node 1 - modifyEntities( dao1 ); - - // allow async timestamp change to propagate - sleep( SLEEP_TIME ); - - // Confirm query results are correct on node 0 - assertEquals( "63088 has correct # of accounts", 7, dao0.getCountForBranch( "63088", useNamedRegion ) ); - assertEquals( "Correct branch for Smith", "63088", dao0.getBranch( dao0.getSmith(), useNamedRegion ) ); - assertEquals( "Correct high balances for Jones", 50, dao0.getTotalBalance( dao0.getJones(), useNamedRegion ) ); - log.info( "Third set of queries on node0 done" ); - } - - protected void setupEntities(ClassLoaderTestDAO dao) throws Exception { - dao.cleanup(); - - dao.createAccount( dao.getSmith(), new Integer( 1001 ), new Integer( 5 ), "94536" ); - dao.createAccount( dao.getSmith(), new Integer( 1002 ), new Integer( 15 ), "94536" ); - dao.createAccount( dao.getSmith(), new Integer( 1003 ), new Integer( 20 ), "94536" ); - - dao.createAccount( dao.getJones(), new Integer( 2001 ), new Integer( 5 ), "63088" ); - dao.createAccount( dao.getJones(), new Integer( 2002 ), new Integer( 15 ), "63088" ); - dao.createAccount( dao.getJones(), new Integer( 2003 ), new Integer( 20 ), "63088" ); - - dao.createAccount( dao.getBarney(), new Integer( 3001 ), new Integer( 5 ), "63088" ); - dao.createAccount( dao.getBarney(), new Integer( 3002 ), new Integer( 15 ), "63088" ); - dao.createAccount( dao.getBarney(), new Integer( 3003 ), new Integer( 20 ), "63088" ); - - log.info( "Standard entities created" ); - } - - protected void resetRegionUsageState(CacheAccessListener localListener, CacheAccessListener remoteListener) { - String stdName = StandardQueryCache.class.getName(); - String acctName = Account.class.getName(); - - localListener.getSawRegionModification( stdName ); - localListener.getSawRegionModification( acctName ); - - localListener.getSawRegionAccess( stdName ); - localListener.getSawRegionAccess( acctName ); - - remoteListener.getSawRegionModification( stdName ); - remoteListener.getSawRegionModification( acctName ); - - remoteListener.getSawRegionAccess( stdName ); - remoteListener.getSawRegionAccess( acctName ); - - log.info( "Region usage state cleared" ); - } - - protected void modifyEntities(ClassLoaderTestDAO dao) throws Exception { - dao.updateAccountBranch( 1001, "63088" ); - dao.updateAccountBalance( 2001, 15 ); - - log.info( "Entities modified" ); - } -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/SelectedClassnameClassLoaderTestSetup.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/SelectedClassnameClassLoaderTestSetup.java deleted file mode 100644 index f0d02b9425..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/SelectedClassnameClassLoaderTestSetup.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ - -package org.hibernate.test.cache.infinispan.functional.classloader; -import junit.extensions.TestSetup; -import junit.framework.Test; - -/** - * A TestSetup that makes SelectedClassnameClassLoader the thread context classloader for the - * duration of the test. - * - * @author Brian Stansberry - * @version $Revision: 1 $ - */ -public class SelectedClassnameClassLoaderTestSetup extends TestSetup { - private ClassLoader originalTCCL; - private String[] includedClasses; - private String[] excludedClasses; - private String[] notFoundClasses; - - /** - * Create a new SelectedClassnameClassLoaderTestSetup. - * - * @param test - */ - public SelectedClassnameClassLoaderTestSetup(Test test, String[] includedClasses, String[] excludedClasses, String[] notFoundClasses) { - super(test); - this.includedClasses = includedClasses; - this.excludedClasses = excludedClasses; - this.notFoundClasses = notFoundClasses; - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - - originalTCCL = Thread.currentThread().getContextClassLoader(); - ClassLoader parent = originalTCCL == null ? getClass().getClassLoader() : originalTCCL; - ClassLoader selectedTCCL = new SelectedClassnameClassLoader(includedClasses, excludedClasses, notFoundClasses, parent); - Thread.currentThread().setContextClassLoader(selectedTCCL); - } - - @Override - protected void tearDown() throws Exception { - Thread.currentThread().setContextClassLoader(originalTCCL); - super.tearDown(); - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/AccountDAO.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/AccountDAO.java new file mode 100644 index 0000000000..c53f0e6433 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/AccountDAO.java @@ -0,0 +1,179 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional.cluster; + +import java.util.Iterator; +import java.util.List; + +import org.hibernate.test.cache.infinispan.functional.entities.Account; +import org.hibernate.test.cache.infinispan.functional.entities.AccountHolder; +import org.infinispan.util.logging.Log; +import org.infinispan.util.logging.LogFactory; + +import org.hibernate.Query; +import org.hibernate.SessionFactory; + +import static org.hibernate.test.cache.infinispan.util.TxUtil.withTxSession; +import static org.hibernate.test.cache.infinispan.util.TxUtil.withTxSessionApply; + +/** + * @author Brian Stansberry + */ +public class AccountDAO { + private static final Log log = LogFactory.getLog(AccountDAO.class); + + private final boolean useJta; + private final SessionFactory sessionFactory; + + private AccountHolder smith = new AccountHolder("Smith", "1000"); + private AccountHolder jones = new AccountHolder("Jones", "2000"); + private AccountHolder barney = new AccountHolder("Barney", "3000"); + + public AccountDAO(boolean useJta, SessionFactory sessionFactory) throws Exception { + this.useJta = useJta; + this.sessionFactory = sessionFactory; + } + + public AccountHolder getSmith() { + return smith; + } + + public AccountHolder getJones() { + return jones; + } + + public AccountHolder getBarney() { + return barney; + } + + public void updateAccountBranch(Integer id, String branch) throws Exception { + withTxSession(useJta, sessionFactory, session -> { + log.debug("Updating account " + id + " to branch " + branch); + Account account = session.get(Account.class, id); + log.debug("Set branch " + branch); + account.setBranch(branch); + session.update(account); + log.debug("Updated account " + id + " to branch " + branch); + }); + } + + public int getCountForBranch(String branch, boolean useRegion) throws Exception { + return withTxSessionApply(useJta, sessionFactory, session -> { + Query query = session.createQuery( + "select account from Account as account where account.branch = :branch"); + query.setString("branch", branch); + if (useRegion) { + query.setCacheRegion("AccountRegion"); + } + query.setCacheable(true); + return query.list().size(); + }); + } + + public void createAccount(AccountHolder holder, Integer id, Integer openingBalance, String branch) throws Exception { + withTxSession(useJta, sessionFactory, session -> { + log.debug("Creating account " + id); + Account account = new Account(); + account.setId(id); + account.setAccountHolder(holder); + account.setBalance(openingBalance); + log.debug("Set branch " + branch); + account.setBranch(branch); + session.persist(account); + log.debug("Created account " + id); + }); + } + + public Account getAccount(Integer id) throws Exception { + return withTxSessionApply(useJta, sessionFactory, session -> { + log.debug("Getting account " + id); + return session.get(Account.class, id); + }); + } + + public Account getAccountWithRefresh(Integer id) throws Exception { + return withTxSessionApply(useJta, sessionFactory, session -> { + log.debug("Getting account " + id + " with refresh"); + Account acct = session.get(Account.class, id); + session.refresh(acct); + return session.get(Account.class, id); + }); + } + + public void updateAccountBalance(Integer id, Integer newBalance) throws Exception { + withTxSession(useJta, sessionFactory, session -> { + log.debug("Updating account " + id + " to balance " + newBalance); + Account account = session.get(Account.class, id); + account.setBalance(newBalance); + session.update(account); + log.debug("Updated account " + id + " to balance " + newBalance); + }); + } + + public String getBranch(Object holder, boolean useRegion) throws Exception { + return withTxSessionApply(useJta, sessionFactory, session -> { + Query query = session.createQuery( + "select account.branch from Account as account where account.accountHolder = ?"); + query.setParameter(0, holder); + if (useRegion) { + query.setCacheRegion("AccountRegion"); + } + query.setCacheable(true); + return (String) query.list().get(0); + }); + } + + public int getTotalBalance(AccountHolder holder, boolean useRegion) throws Exception { + List results = (List) withTxSessionApply(useJta, sessionFactory, session -> { + Query query = session.createQuery( + "select account.balance from Account as account where account.accountHolder = ?"); + query.setParameter(0, holder); + if (useRegion) { + query.setCacheRegion("AccountRegion"); + } + query.setCacheable(true); + return query.list(); + }); + int total = 0; + if (results != null) { + for (Iterator it = results.iterator(); it.hasNext();) { + total += ((Integer) it.next()).intValue(); + System.out.println("Total = " + total); + } + } + return total; + } + + public void cleanup() throws Exception { + internalCleanup(); + } + + private void internalCleanup() throws Exception { + withTxSession(useJta, sessionFactory, session -> { + Query query = session.createQuery("select account from Account as account"); + List accts = query.list(); + if (accts != null) { + for (Iterator it = accts.iterator(); it.hasNext(); ) { + try { + Object acct = it.next(); + log.info("Removing " + acct); + session.delete(acct); + } catch (Exception ignored) { + } + } + } + }); + } + + public void remove() { + try { + internalCleanup(); + } catch (Exception e) { + log.error("Caught exception in remove", e); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/ClusterAwareRegionFactory.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/ClusterAwareRegionFactory.java index f56ae2fc7e..f7ac97d3a2 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/ClusterAwareRegionFactory.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/ClusterAwareRegionFactory.java @@ -21,8 +21,7 @@ import org.hibernate.cache.spi.RegionFactory; import org.hibernate.cache.spi.TimestampsRegion; import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.test.cache.infinispan.functional.SingleNodeTestCase; - +import org.hibernate.internal.util.ReflectHelper; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; @@ -34,85 +33,89 @@ import org.infinispan.util.logging.LogFactory; * @since 3.5 */ public class ClusterAwareRegionFactory implements RegionFactory { - - private static final Log log = LogFactory.getLog(ClusterAwareRegionFactory.class); - private static final Hashtable cacheManagers = new Hashtable(); - private final InfinispanRegionFactory delegate = - new SingleNodeTestCase.TestInfinispanRegionFactory(); - private String cacheManagerName; - private boolean locallyAdded; - - public ClusterAwareRegionFactory(Properties props) { - } - - public static EmbeddedCacheManager getCacheManager(String name) { - return cacheManagers.get(name); - } - - public static void addCacheManager(String name, EmbeddedCacheManager manager) { - cacheManagers.put(name, manager); - } - - public static void clearCacheManagers() { - for (EmbeddedCacheManager manager : cacheManagers.values()) { - try { - manager.stop(); - } catch (Exception e) { - log.error("Exception cleaning up CacheManager " + manager, e); - } - } - cacheManagers.clear(); - } + private static final Log log = LogFactory.getLog(ClusterAwareRegionFactory.class); + private static final Hashtable cacheManagers = new Hashtable(); - public void start(SessionFactoryOptions settings, Properties properties) throws CacheException { - cacheManagerName = properties.getProperty(DualNodeTestCase.NODE_ID_PROP); - - EmbeddedCacheManager existing = getCacheManager(cacheManagerName); - locallyAdded = (existing == null); - - if (locallyAdded) { - delegate.start(settings, properties); - cacheManagers.put(cacheManagerName, delegate.getCacheManager()); - } else { - delegate.setCacheManager(existing); - } - } + private InfinispanRegionFactory delegate; + private String cacheManagerName; + private boolean locallyAdded; - public void stop() { - if (locallyAdded) cacheManagers.remove(cacheManagerName); - delegate.stop(); - } + public ClusterAwareRegionFactory(Properties props) { + try { + delegate = (InfinispanRegionFactory) ReflectHelper.classForName(props.getProperty(DualNodeTest.REGION_FACTORY_DELEGATE)).newInstance(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } - public CollectionRegion buildCollectionRegion(String regionName, Properties properties, - CacheDataDescription metadata) throws CacheException { - return delegate.buildCollectionRegion(regionName, properties, metadata); - } + public static EmbeddedCacheManager getCacheManager(String name) { + return cacheManagers.get(name); + } - public EntityRegion buildEntityRegion(String regionName, Properties properties, - CacheDataDescription metadata) throws CacheException { - return delegate.buildEntityRegion(regionName, properties, metadata); - } - - @Override + public static void addCacheManager(String name, EmbeddedCacheManager manager) { + cacheManagers.put(name, manager); + } + + public static void clearCacheManagers() { + for (EmbeddedCacheManager manager : cacheManagers.values()) { + try { + manager.stop(); + } catch (Exception e) { + log.error("Exception cleaning up CacheManager " + manager, e); + } + } + cacheManagers.clear(); + } + + public void start(SessionFactoryOptions settings, Properties properties) throws CacheException { + cacheManagerName = properties.getProperty(DualNodeTest.NODE_ID_PROP); + + EmbeddedCacheManager existing = getCacheManager(cacheManagerName); + locallyAdded = (existing == null); + + if (locallyAdded) { + delegate.start(settings, properties); + cacheManagers.put(cacheManagerName, delegate.getCacheManager()); + } else { + delegate.setCacheManager(existing); + } + } + + public void stop() { + if (locallyAdded) cacheManagers.remove(cacheManagerName); + delegate.stop(); + } + + public CollectionRegion buildCollectionRegion(String regionName, Properties properties, + CacheDataDescription metadata) throws CacheException { + return delegate.buildCollectionRegion(regionName, properties, metadata); + } + + public EntityRegion buildEntityRegion(String regionName, Properties properties, + CacheDataDescription metadata) throws CacheException { + return delegate.buildEntityRegion(regionName, properties, metadata); + } + + @Override public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException { return delegate.buildNaturalIdRegion( regionName, properties, metadata ); } - public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) - throws CacheException { - return delegate.buildQueryResultsRegion(regionName, properties); - } + public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) + throws CacheException { + return delegate.buildQueryResultsRegion(regionName, properties); + } - public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) - throws CacheException { - return delegate.buildTimestampsRegion(regionName, properties); - } + public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) + throws CacheException { + return delegate.buildTimestampsRegion(regionName, properties); + } - public boolean isMinimalPutsEnabledByDefault() { - return delegate.isMinimalPutsEnabledByDefault(); - } + public boolean isMinimalPutsEnabledByDefault() { + return delegate.isMinimalPutsEnabledByDefault(); + } @Override public AccessType getDefaultAccessType() { @@ -120,6 +123,6 @@ public class ClusterAwareRegionFactory implements RegionFactory { } public long nextTimestamp() { - return delegate.nextTimestamp(); - } + return delegate.nextTimestamp(); + } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaPlatformImpl.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaPlatformImpl.java index a15121de18..f3defacfb2 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaPlatformImpl.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaPlatformImpl.java @@ -30,9 +30,9 @@ public class DualNodeJtaPlatformImpl implements JtaPlatform, Configurable { @Override public void configure(Map configurationValues) { - nodeId = (String) configurationValues.get( DualNodeTestCase.NODE_ID_PROP ); - if ( nodeId == null ) { - throw new HibernateException(DualNodeTestCase.NODE_ID_PROP + " not configured"); + nodeId = (String) configurationValues.get( DualNodeTest.NODE_ID_PROP ); + if ( nodeId == null ) { + throw new HibernateException(DualNodeTest.NODE_ID_PROP + " not configured"); } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTest.java similarity index 77% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTestCase.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTest.java index 886e240426..9a90b06d1b 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTest.java @@ -6,37 +6,42 @@ */ package org.hibernate.test.cache.infinispan.functional.cluster; + import java.util.Map; +import org.hibernate.Session; +import org.hibernate.SessionFactory; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.resource.transaction.TransactionCoordinatorBuilder; +import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl; import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; +import org.hibernate.test.cache.infinispan.functional.AbstractFunctionalTest; import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.test.cache.infinispan.util.TxUtil; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; -import org.junit.Before; import org.junit.ClassRule; +import org.junit.runners.Parameterized; /** * @author Galder Zamarreño * @since 3.5 */ -public abstract class DualNodeTestCase extends BaseNonConfigCoreFunctionalTestCase { +public abstract class DualNodeTest extends AbstractFunctionalTest { - private static final Log log = LogFactory.getLog( DualNodeTestCase.class ); + private static final Log log = LogFactory.getLog( DualNodeTest.class ); @ClassRule public static final InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + public static final String REGION_FACTORY_DELEGATE = "hibernate.cache.region.factory_delegate"; public static final String NODE_ID_PROP = "hibernate.test.cluster.node.id"; public static final String NODE_ID_FIELD = "nodeId"; public static final String LOCAL = "local"; @@ -44,16 +49,20 @@ public abstract class DualNodeTestCase extends BaseNonConfigCoreFunctionalTestCa private SecondNodeEnvironment secondNodeEnvironment; - @Override - public String[] getMappings() { - return new String[] { - "cache/infinispan/functional/Contact.hbm.xml", "cache/infinispan/functional/Customer.hbm.xml" - }; + protected void withTxSession(SessionFactory sessionFactory, TxUtil.ThrowingConsumer consumer) throws Exception { + TxUtil.withTxSession(useJta, sessionFactory, consumer); + } + + protected T withTxSessionApply(SessionFactory sessionFactory, TxUtil.ThrowingFunction consumer) throws Exception { + return TxUtil.withTxSessionApply(useJta, sessionFactory, consumer); } @Override - public String getCacheConcurrencyStrategy() { - return "transactional"; + public String[] getMappings() { + return new String[] { + "cache/infinispan/functional/entities/Contact.hbm.xml", + "cache/infinispan/functional/entities/Customer.hbm.xml" + }; } @Override @@ -65,6 +74,7 @@ public abstract class DualNodeTestCase extends BaseNonConfigCoreFunctionalTestCa settings.put( NODE_ID_PROP, LOCAL ); settings.put( NODE_ID_FIELD, LOCAL ); + settings.put( REGION_FACTORY_DELEGATE, regionFactoryClass.getName() ); } @Override @@ -101,10 +111,6 @@ public abstract class DualNodeTestCase extends BaseNonConfigCoreFunctionalTestCa return ClusterAwareRegionFactory.class; } - protected Class getConnectionProviderClass() { - return DualNodeConnectionProviderImpl.class; - } - protected Class getJtaPlatformClass() { return DualNodeJtaPlatformImpl.class; } @@ -122,20 +128,12 @@ public abstract class DualNodeTestCase extends BaseNonConfigCoreFunctionalTestCa } } - protected boolean getUseQueryCache() { - return true; - } - protected void configureSecondNode(StandardServiceRegistryBuilder ssrb) { } @SuppressWarnings("unchecked") protected void applyStandardSettings(Map settings) { - settings.put( Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName() ); - settings.put( AvailableSettings.JTA_PLATFORM, getJtaPlatformClass().getName() ); - settings.put( Environment.TRANSACTION_COORDINATOR_STRATEGY, getTransactionCoordinatorBuilder().getName() ); - settings.put( Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName() ); - settings.put( Environment.USE_QUERY_CACHE, String.valueOf( getUseQueryCache() ) ); + settings.put( Environment.CACHE_REGION_FACTORY, ClusterAwareRegionFactory.class.getName() ); } public class SecondNodeEnvironment { diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTest.java similarity index 73% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTest.java index 64a22cf7b1..26808dac69 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTest.java @@ -6,9 +6,10 @@ */ package org.hibernate.test.cache.infinispan.functional.cluster; -import javax.transaction.TransactionManager; +import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Set; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; @@ -18,8 +19,8 @@ import java.util.concurrent.atomic.AtomicReference; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.test.cache.infinispan.functional.Contact; -import org.hibernate.test.cache.infinispan.functional.Customer; +import org.hibernate.test.cache.infinispan.functional.entities.Contact; +import org.hibernate.test.cache.infinispan.functional.entities.Customer; import org.hibernate.testing.TestForIssue; import org.infinispan.AdvancedCache; import org.infinispan.Cache; @@ -36,7 +37,6 @@ import org.infinispan.util.logging.LogFactory; import org.jboss.util.collection.ConcurrentSet; import org.junit.Test; -import static org.infinispan.test.TestingUtil.withTx; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -47,28 +47,30 @@ import static org.junit.Assert.assertTrue; * @author Galder Zamarreño * @since 3.5 */ -public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { - private static final Log log = LogFactory.getLog( EntityCollectionInvalidationTestCase.class ); +public class EntityCollectionInvalidationTest extends DualNodeTest { + private static final Log log = LogFactory.getLog( EntityCollectionInvalidationTest.class ); private static final long SLEEP_TIME = 50l; private static final Integer CUSTOMER_ID = new Integer( 1 ); - static int test = 0; - private EmbeddedCacheManager localManager, remoteManager; private Cache localCustomerCache, remoteCustomerCache; private Cache localContactCache, remoteContactCache; private Cache localCollectionCache, remoteCollectionCache; private MyListener localListener, remoteListener; - private TransactionManager localTM, remoteTM; private SessionFactory localFactory, remoteFactory; + @Override + public List getParameters() { + return Arrays.asList(TRANSACTIONAL, READ_WRITE); + } + @Override public void startUp() { super.startUp(); // Bind a listener to the "local" cache // Our region factory makes its CacheManager available to us - localManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTestCase.LOCAL ); + localManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTest.LOCAL ); // Cache localCache = localManager.getCache("entity"); localCustomerCache = localManager.getCache( Customer.class.getName() ); localContactCache = localManager.getCache( Contact.class.getName() ); @@ -79,7 +81,7 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { localCollectionCache.addListener( localListener ); // Bind a listener to the "remote" cache - remoteManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTestCase.REMOTE ); + remoteManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTest.REMOTE ); remoteCustomerCache = remoteManager.getCache( Customer.class.getName() ); remoteContactCache = remoteManager.getCache( Contact.class.getName() ); remoteCollectionCache = remoteManager.getCache( Customer.class.getName() + ".contacts" ); @@ -90,9 +92,6 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { localFactory = sessionFactory(); remoteFactory = secondNodeEnvironment().getSessionFactory(); - - localTM = DualNodeJtaTransactionManagerImpl.getInstance( DualNodeTestCase.LOCAL ); - remoteTM = DualNodeJtaTransactionManagerImpl.getInstance( DualNodeTestCase.REMOTE ); } @Override @@ -102,9 +101,9 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { @Override protected void cleanupTest() throws Exception { - cleanup(localFactory, localTM); - localListener.clear(); - remoteListener.clear(); + cleanup(localFactory); + localListener.clear(); + remoteListener.clear(); // do not call super.cleanupTest becasue we would clean transaction managers } @@ -115,7 +114,7 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { assertTrue( localListener.isEmpty() ); log.debug( "Create node 0" ); - IdContainer ids = createCustomer( localFactory, localTM ); + IdContainer ids = createCustomer( localFactory ); assertTrue( remoteListener.isEmpty() ); assertTrue( localListener.isEmpty() ); @@ -126,7 +125,7 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { log.debug( "Find node 0" ); // This actually brings the collection into the cache - getCustomer( ids.customerId, localFactory, localTM ); + getCustomer( ids.customerId, localFactory ); sleep( SLEEP_TIME ); @@ -134,7 +133,7 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { // should read everything from the cache log.debug( "Find(2) node 0" ); localListener.clear(); - getCustomer( ids.customerId, localFactory, localTM ); + getCustomer( ids.customerId, localFactory ); // Check the read came from the cache log.debug( "Check cache 0" ); @@ -142,13 +141,13 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { log.debug( "Find node 1" ); // This actually brings the collection into the cache since invalidation is in use - getCustomer( ids.customerId, remoteFactory, remoteTM ); + getCustomer( ids.customerId, remoteFactory ); // Now the collection is in the cache so, the 2nd "get" // should read everything from the cache log.debug( "Find(2) node 1" ); remoteListener.clear(); - getCustomer( ids.customerId, remoteFactory, remoteTM ); + getCustomer( ids.customerId, remoteFactory ); // Check the read came from the cache log.debug( "Check cache 1" ); @@ -156,7 +155,7 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { // Modify customer in remote remoteListener.clear(); - ids = modifyCustomer( ids.customerId, remoteFactory, remoteTM ); + ids = modifyCustomer( ids.customerId, remoteFactory ); sleep( 250 ); assertLoadedFromCache( remoteListener, ids.customerId, ids.contactIds ); @@ -178,28 +177,18 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { remotePPCache.getAdvancedCache().addInterceptor(hookInterceptor, 0); IdContainer idContainer = new IdContainer(); - withTx(localTM, () -> { - Session s = localFactory.getCurrentSession(); - s.getTransaction().begin(); + withTxSession(localFactory, s -> { Customer customer = new Customer(); customer.setName( "JBoss" ); s.persist(customer); - s.getTransaction().commit(); - s.close(); idContainer.customerId = customer.getId(); - return null; }); // start loading Thread getThread = new Thread(() -> { try { - withTx(remoteTM, () -> { - Session s = remoteFactory.getCurrentSession(); - s.getTransaction().begin(); + withTxSession(remoteFactory, s -> { s.get(Customer.class, idContainer.customerId); - s.getTransaction().commit(); - s.close(); - return null; }); } catch (Exception e) { log.error("Failure to get customer", e); @@ -208,13 +197,9 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { }, "get-thread"); Thread deleteThread = new Thread(() -> { try { - withTx(localTM, () -> { - Session s = localFactory.getCurrentSession(); - s.getTransaction().begin(); + withTxSession(localFactory, s -> { Customer customer = s.get(Customer.class, idContainer.customerId); s.delete(customer); - s.getTransaction().commit(); - return null; }); } catch (Exception e) { log.error("Failure to delete customer", e); @@ -239,9 +224,9 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { throw new IllegalStateException("delete-thread failed", deleteException.get()); } - Customer localCustomer = getCustomer(idContainer.customerId, localFactory, localTM); + Customer localCustomer = getCustomer(idContainer.customerId, localFactory); assertNull(localCustomer); - Customer remoteCustomer = getCustomer(idContainer.customerId, remoteFactory, remoteTM); + Customer remoteCustomer = getCustomer(idContainer.customerId, remoteFactory); assertNull(remoteCustomer); assertTrue(remoteCustomerCache.isEmpty()); } @@ -255,83 +240,47 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { assertTrue( remoteCollectionCache.isEmpty() ); } - private IdContainer createCustomer(SessionFactory sessionFactory, TransactionManager tm) + private IdContainer createCustomer(SessionFactory sessionFactory) throws Exception { log.debug( "CREATE CUSTOMER" ); - tm.begin(); + Customer customer = new Customer(); + customer.setName("JBoss"); + Set contacts = new HashSet(); - try { - Session session = sessionFactory.getCurrentSession(); - Customer customer = new Customer(); - customer.setName( "JBoss" ); - Set contacts = new HashSet(); + Contact kabir = new Contact(); + kabir.setCustomer(customer); + kabir.setName("Kabir"); + kabir.setTlf("1111"); + contacts.add(kabir); - Contact kabir = new Contact(); - kabir.setCustomer( customer ); - kabir.setName( "Kabir" ); - kabir.setTlf( "1111" ); - contacts.add( kabir ); + Contact bill = new Contact(); + bill.setCustomer(customer); + bill.setName("Bill"); + bill.setTlf("2222"); + contacts.add(bill); - Contact bill = new Contact(); - bill.setCustomer( customer ); - bill.setName( "Bill" ); - bill.setTlf( "2222" ); - contacts.add( bill ); + customer.setContacts(contacts); - customer.setContacts( contacts ); + withTxSession(sessionFactory, session -> session.save(customer)); - session.save( customer ); - tm.commit(); + IdContainer ids = new IdContainer(); + ids.customerId = customer.getId(); + Set contactIds = new HashSet(); + contactIds.add( kabir.getId() ); + contactIds.add( bill.getId() ); + ids.contactIds = contactIds; - IdContainer ids = new IdContainer(); - ids.customerId = customer.getId(); - Set contactIds = new HashSet(); - contactIds.add( kabir.getId() ); - contactIds.add( bill.getId() ); - ids.contactIds = contactIds; - - return ids; - } - catch (Exception e) { - log.error( "Caught exception creating customer", e ); - try { - tm.rollback(); - } - catch (Exception e1) { - log.error( "Exception rolling back txn", e1 ); - } - throw e; - } - finally { - log.debug( "CREATE CUSTOMER - END" ); - } + log.debug( "CREATE CUSTOMER - END" ); + return ids; } - private Customer getCustomer(Integer id, SessionFactory sessionFactory, TransactionManager tm) throws Exception { + private Customer getCustomer(Integer id, SessionFactory sessionFactory) throws Exception { log.debug( "Find customer with id=" + id ); - tm.begin(); - try { - Session session = sessionFactory.getCurrentSession(); - Customer customer = doGetCustomer( id, session, tm ); - tm.commit(); - return customer; - } - catch (Exception e) { - try { - tm.rollback(); - } - catch (Exception e1) { - log.error( "Exception rolling back txn", e1 ); - } - throw e; - } - finally { - log.debug( "Find customer ended." ); - } + return withTxSessionApply(sessionFactory, session -> doGetCustomer(id, session)); } - private Customer doGetCustomer(Integer id, Session session, TransactionManager tm) throws Exception { + private Customer doGetCustomer(Integer id, Session session) throws Exception { Customer customer = session.get( Customer.class, id ); if (customer == null) { return null; @@ -346,15 +295,13 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { return customer; } - private IdContainer modifyCustomer(Integer id, SessionFactory sessionFactory, TransactionManager tm) + private IdContainer modifyCustomer(Integer id, SessionFactory sessionFactory) throws Exception { log.debug( "Modify customer with id=" + id ); - tm.begin(); - try { - Session session = sessionFactory.getCurrentSession(); + return withTxSessionApply(sessionFactory, session -> { IdContainer ids = new IdContainer(); Set contactIds = new HashSet(); - Customer customer = doGetCustomer( id, session, tm ); + Customer customer = doGetCustomer( id, session ); customer.setName( "NewJBoss" ); ids.customerId = customer.getId(); Set contacts = customer.getContacts(); @@ -368,51 +315,26 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { contact.setCustomer( null ); session.save( customer ); - tm.commit(); return ids; - } - catch (Exception e) { - try { - tm.rollback(); - } - catch (Exception e1) { - log.error( "Exception rolling back txn", e1 ); - } - throw e; - } - finally { - log.debug( "Find customer ended." ); - } + }); } - private void cleanup(SessionFactory sessionFactory, TransactionManager tm) throws Exception { - tm.begin(); - try { - Session session = sessionFactory.getCurrentSession(); - Customer c = (Customer) session.get( Customer.class, CUSTOMER_ID ); - if ( c != null ) { + private void cleanup(SessionFactory sessionFactory) throws Exception { + withTxSession(sessionFactory, session -> { + Customer c = (Customer) session.get(Customer.class, CUSTOMER_ID); + if (c != null) { Set contacts = c.getContacts(); - for ( Iterator it = contacts.iterator(); it.hasNext(); ) { - session.delete( it.next() ); + for (Iterator it = contacts.iterator(); it.hasNext(); ) { + session.delete(it.next()); } - c.setContacts( null ); - session.delete( c ); + c.setContacts(null); + session.delete(c); } // since we don't use orphan removal, some contacts may persist for (Object contact : session.createCriteria(Contact.class).list()) { session.delete(contact); } - tm.commit(); - } - catch (Exception e) { - try { - tm.rollback(); - } - catch (Exception e1) { - log.error( "Exception rolling back txn", e1 ); - } - log.error( "Caught exception in cleanup", e ); - } + }); } private void assertLoadedFromCache(MyListener listener, Integer custId, Set contactIds) { @@ -477,7 +399,7 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase { String key = event.getCache().getName() + "#" + event.getKey(); log.debug( "MyListener[" + name + "] - Visiting key " + key ); // String name = fqn.toString(); - String token = ".functional."; + String token = ".entities."; int index = key.indexOf( token ); if ( index > -1 ) { index += token.length(); diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/NaturalIdInvalidationTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/NaturalIdInvalidationTest.java new file mode 100644 index 0000000000..a2e52df3aa --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/NaturalIdInvalidationTest.java @@ -0,0 +1,244 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional.cluster; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import org.hibernate.Criteria; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cache.infinispan.util.Caches; +import org.hibernate.criterion.Restrictions; +import org.hibernate.test.cache.infinispan.functional.entities.Citizen; +import org.hibernate.test.cache.infinispan.functional.entities.NaturalIdOnManyToOne; +import org.hibernate.test.cache.infinispan.functional.entities.State; +import org.infinispan.Cache; +import org.infinispan.manager.CacheContainer; +import org.infinispan.notifications.Listener; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited; +import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent; +import org.infinispan.util.logging.Log; +import org.infinispan.util.logging.LogFactory; +import org.jboss.util.collection.ConcurrentSet; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * // TODO: Document this + * + * @author Galder Zamarreño + */ +public class NaturalIdInvalidationTest extends DualNodeTest { + + private static final Log log = LogFactory.getLog(NaturalIdInvalidationTest.class); + + private static final long SLEEP_TIME = 50l; + + @Override + public List getParameters() { + return Arrays.asList(TRANSACTIONAL, READ_WRITE, READ_ONLY); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Citizen.class, State.class, + NaturalIdOnManyToOne.class + }; + } + + @Test + public void testAll() throws Exception { + log.info( "*** testAll()" ); + + // Bind a listener to the "local" cache + // Our region factory makes its CacheManager available to us + CacheContainer localManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTest.LOCAL); + Cache localNaturalIdCache = localManager.getCache(Citizen.class.getName() + "##NaturalId"); + MyListener localListener = new MyListener( "local" ); + localNaturalIdCache.addListener(localListener); + + // Bind a listener to the "remote" cache + CacheContainer remoteManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTest.REMOTE); + Cache remoteNaturalIdCache = remoteManager.getCache(Citizen.class.getName() + "##NaturalId"); + MyListener remoteListener = new MyListener( "remote" ); + remoteNaturalIdCache.addListener(remoteListener); + + SessionFactory localFactory = sessionFactory(); + SessionFactory remoteFactory = secondNodeEnvironment().getSessionFactory(); + + try { + assertTrue(remoteListener.isEmpty()); + assertTrue(localListener.isEmpty()); + + saveSomeCitizens(localFactory); + + assertTrue(remoteListener.isEmpty()); + assertTrue(localListener.isEmpty()); + + // Sleep a bit to let async commit propagate. Really just to + // help keep the logs organized for debugging any issues + sleep( SLEEP_TIME ); + + log.debug("Find node 0"); + // This actually brings the collection into the cache + getCitizenWithCriteria(localFactory); + + sleep( SLEEP_TIME ); + // Now the collection is in the cache so, the 2nd "get" + // should read everything from the cache + log.debug( "Find(2) node 0" ); + localListener.clear(); + getCitizenWithCriteria(localFactory); + + // Check the read came from the cache + log.debug( "Check cache 0" ); + assertLoadedFromCache(localListener, "1234"); + + log.debug( "Find node 1" ); + // This actually brings the collection into the cache since invalidation is in use + getCitizenWithCriteria(remoteFactory); + + // Now the collection is in the cache so, the 2nd "get" + // should read everything from the cache + log.debug( "Find(2) node 1" ); + remoteListener.clear(); + getCitizenWithCriteria(remoteFactory); + + // Check the read came from the cache + log.debug( "Check cache 1" ); + assertLoadedFromCache(remoteListener, "1234"); + + // Modify customer in remote + remoteListener.clear(); + deleteCitizenWithCriteria(remoteFactory); + sleep(250); + + Set localKeys = Caches.keys(localNaturalIdCache.getAdvancedCache()).toSet(); + assertEquals(1, localKeys.size()); + // Only key left is the one for the citizen *not* in France + localKeys.toString().contains("000"); + } + catch (Exception e) { + log.error("Error", e); + throw e; + } finally { + withTxSession(localFactory, s -> { + s.createQuery( "delete NaturalIdOnManyToOne" ).executeUpdate(); + s.createQuery( "delete Citizen" ).executeUpdate(); + s.createQuery( "delete State" ).executeUpdate(); + }); + } + } + + private void assertLoadedFromCache(MyListener localListener, String id) { + for (String visited : localListener.visited){ + if (visited.contains(id)) + return; + } + fail("Citizen (" + id + ") should have present in the cache"); + } + + private void saveSomeCitizens(SessionFactory sf) throws Exception { + final Citizen c1 = new Citizen(); + c1.setFirstname( "Emmanuel" ); + c1.setLastname( "Bernard" ); + c1.setSsn( "1234" ); + + final State france = new State(); + france.setName( "Ile de France" ); + c1.setState( france ); + + final Citizen c2 = new Citizen(); + c2.setFirstname( "Gavin" ); + c2.setLastname( "King" ); + c2.setSsn( "000" ); + final State australia = new State(); + australia.setName( "Australia" ); + c2.setState( australia ); + + withTxSession(sf, s -> { + s.persist( australia ); + s.persist( france ); + s.persist( c1 ); + s.persist( c2 ); + }); + } + + private void getCitizenWithCriteria(SessionFactory sf) throws Exception { + withTxSession(sf, s -> { + State france = getState(s, "Ile de France"); + Criteria criteria = s.createCriteria( Citizen.class ); + criteria.add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", france ) ); + criteria.setCacheable( true ); + criteria.list(); + }); + } + + private void deleteCitizenWithCriteria(SessionFactory sf) throws Exception { + withTxSession(sf, s -> { + State france = getState(s, "Ile de France"); + Criteria criteria = s.createCriteria( Citizen.class ); + criteria.add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", france ) ); + criteria.setCacheable( true ); + Citizen c = (Citizen) criteria.uniqueResult(); + s.delete(c); + }); + } + + private State getState(Session s, String name) { + Criteria criteria = s.createCriteria( State.class ); + criteria.add( Restrictions.eq("name", name) ); + criteria.setCacheable(true); + return (State) criteria.list().get( 0 ); + } + + @Listener + public static class MyListener { + private static final Log log = LogFactory.getLog( MyListener.class ); + private Set visited = new ConcurrentSet(); + private final String name; + + public MyListener(String name) { + this.name = name; + } + + public void clear() { + visited.clear(); + } + + public boolean isEmpty() { + return visited.isEmpty(); + } + + @CacheEntryVisited + public void nodeVisited(CacheEntryVisitedEvent event) { + log.debug( event.toString() ); + if ( !event.isPre() ) { + visited.add(event.getKey().toString()); +// Integer primKey = (Integer) cacheKey.getKey(); +// String key = (String) cacheKey.getEntityOrRoleName() + '#' + primKey; +// log.debug( "MyListener[" + name + "] - Visiting key " + key ); +// // String name = fqn.toString(); +// String token = ".functional."; +// int index = key.indexOf( token ); +// if ( index > -1 ) { +// index += token.length(); +// key = key.substring( index ); +// log.debug( "MyListener[" + name + "] - recording visit to " + key ); +// visited.add( key ); +// } + } + } + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/NaturalIdInvalidationTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/NaturalIdInvalidationTestCase.java deleted file mode 100644 index 87f154a9b2..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/NaturalIdInvalidationTestCase.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.functional.cluster; - -import javax.transaction.TransactionManager; -import java.util.Set; -import java.util.concurrent.Callable; - -import org.hibernate.Criteria; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.hibernate.cache.infinispan.util.Caches; -import org.hibernate.criterion.Restrictions; -import org.hibernate.test.cache.infinispan.functional.Citizen; -import org.hibernate.test.cache.infinispan.functional.NaturalIdOnManyToOne; -import org.hibernate.test.cache.infinispan.functional.State; -import org.infinispan.Cache; -import org.infinispan.manager.CacheContainer; -import org.infinispan.notifications.Listener; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited; -import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent; -import org.infinispan.util.logging.Log; -import org.infinispan.util.logging.LogFactory; -import org.jboss.util.collection.ConcurrentSet; -import org.junit.Test; - -import static org.infinispan.test.TestingUtil.withTx; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * // TODO: Document this - * - * @author Galder Zamarreño - * @since // TODO - */ -public class NaturalIdInvalidationTestCase extends DualNodeTestCase { - - private static final Log log = LogFactory.getLog(NaturalIdInvalidationTestCase.class); - - private static final long SLEEP_TIME = 50l; - private static final Integer CUSTOMER_ID = new Integer( 1 ); - private static int test = 0; - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Citizen.class, State.class, - NaturalIdOnManyToOne.class - }; - } - - @Test - public void testAll() throws Exception { - log.info( "*** testAll()" ); - - // Bind a listener to the "local" cache - // Our region factory makes its CacheManager available to us - CacheContainer localManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.LOCAL); - Cache localNaturalIdCache = localManager.getCache(Citizen.class.getName() + "##NaturalId"); - MyListener localListener = new MyListener( "local" ); - localNaturalIdCache.addListener(localListener); - TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.LOCAL); - - // Bind a listener to the "remote" cache - CacheContainer remoteManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.REMOTE); - Cache remoteNaturalIdCache = remoteManager.getCache(Citizen.class.getName() + "##NaturalId"); - MyListener remoteListener = new MyListener( "remote" ); - remoteNaturalIdCache.addListener(remoteListener); - TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.REMOTE); - - SessionFactory localFactory = sessionFactory(); - SessionFactory remoteFactory = secondNodeEnvironment().getSessionFactory(); - - try { - assertTrue(remoteListener.isEmpty()); - assertTrue(localListener.isEmpty()); - - saveSomeCitizens(localTM, localFactory); - - assertTrue(remoteListener.isEmpty()); - assertTrue(localListener.isEmpty()); - - // Sleep a bit to let async commit propagate. Really just to - // help keep the logs organized for debugging any issues - sleep( SLEEP_TIME ); - - log.debug("Find node 0"); - // This actually brings the collection into the cache - getCitizenWithCriteria(localTM, localFactory); - - sleep( SLEEP_TIME ); - // Now the collection is in the cache so, the 2nd "get" - // should read everything from the cache - log.debug( "Find(2) node 0" ); - localListener.clear(); - getCitizenWithCriteria(localTM, localFactory); - - // Check the read came from the cache - log.debug( "Check cache 0" ); - assertLoadedFromCache(localListener, "1234"); - - log.debug( "Find node 1" ); - // This actually brings the collection into the cache since invalidation is in use - getCitizenWithCriteria(remoteTM, remoteFactory); - - // Now the collection is in the cache so, the 2nd "get" - // should read everything from the cache - log.debug( "Find(2) node 1" ); - remoteListener.clear(); - getCitizenWithCriteria(remoteTM, remoteFactory); - - // Check the read came from the cache - log.debug( "Check cache 1" ); - assertLoadedFromCache(remoteListener, "1234"); - - // Modify customer in remote - remoteListener.clear(); - deleteCitizenWithCriteria(remoteTM, remoteFactory); - sleep(250); - - Set localKeys = Caches.keys(localNaturalIdCache.getAdvancedCache()).toSet(); - assertEquals(1, localKeys.size()); - // Only key left is the one for the citizen *not* in France - localKeys.toString().contains("000"); - } - catch (Exception e) { - log.error("Error", e); - throw e; - } finally { - withTx(localTM, new Callable() { - @Override - public Void call() throws Exception { - Session s = sessionFactory().openSession(); - s.beginTransaction(); - s.createQuery( "delete NaturalIdOnManyToOne" ).executeUpdate(); - s.createQuery( "delete Citizen" ).executeUpdate(); - s.createQuery( "delete State" ).executeUpdate(); - s.getTransaction().commit(); - s.close(); - return null; - } - }); - } - } - - private void assertLoadedFromCache(MyListener localListener, String id) { - for (String visited : localListener.visited){ - if (visited.contains(id)) - return; - } - fail("Citizen (" + id + ") should have present in the cache"); - } - - private void saveSomeCitizens(TransactionManager tm, final SessionFactory sf) throws Exception { - final Citizen c1 = new Citizen(); - c1.setFirstname( "Emmanuel" ); - c1.setLastname( "Bernard" ); - c1.setSsn( "1234" ); - - final State france = new State(); - france.setName( "Ile de France" ); - c1.setState( france ); - - final Citizen c2 = new Citizen(); - c2.setFirstname( "Gavin" ); - c2.setLastname( "King" ); - c2.setSsn( "000" ); - final State australia = new State(); - australia.setName( "Australia" ); - c2.setState( australia ); - - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = sf.openSession(); - Transaction tx = s.beginTransaction(); - s.persist( australia ); - s.persist( france ); - s.persist( c1 ); - s.persist( c2 ); - tx.commit(); - s.close(); - return null; - } - }); - } - - private void getCitizenWithCriteria(TransactionManager tm, final SessionFactory sf) throws Exception { - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = sf.openSession(); - Transaction tx = s.beginTransaction(); - State france = getState(s, "Ile de France"); - Criteria criteria = s.createCriteria( Citizen.class ); - criteria.add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", france ) ); - criteria.setCacheable( true ); - criteria.list(); - // cleanup - tx.commit(); - s.close(); - return null; - } - }); - } - - private void deleteCitizenWithCriteria(TransactionManager tm, final SessionFactory sf) throws Exception { - withTx(tm, new Callable() { - @Override - public Void call() throws Exception { - Session s = sf.openSession(); - Transaction tx = s.beginTransaction(); - State france = getState(s, "Ile de France"); - Criteria criteria = s.createCriteria( Citizen.class ); - criteria.add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", france ) ); - criteria.setCacheable( true ); - Citizen c = (Citizen) criteria.uniqueResult(); - s.delete(c); - // cleanup - tx.commit(); - s.close(); - return null; - } - }); - } - - private State getState(Session s, String name) { - Criteria criteria = s.createCriteria( State.class ); - criteria.add( Restrictions.eq("name", name) ); - criteria.setCacheable(true); - return (State) criteria.list().get( 0 ); - } - - @Listener - public static class MyListener { - private static final Log log = LogFactory.getLog( MyListener.class ); - private Set visited = new ConcurrentSet(); - private final String name; - - public MyListener(String name) { - this.name = name; - } - - public void clear() { - visited.clear(); - } - - public boolean isEmpty() { - return visited.isEmpty(); - } - - @CacheEntryVisited - public void nodeVisited(CacheEntryVisitedEvent event) { - log.debug( event.toString() ); - if ( !event.isPre() ) { - visited.add(event.getKey().toString()); -// Integer primKey = (Integer) cacheKey.getKey(); -// String key = (String) cacheKey.getEntityOrRoleName() + '#' + primKey; -// log.debug( "MyListener[" + name + "] - Visiting key " + key ); -// // String name = fqn.toString(); -// String token = ".functional."; -// int index = key.indexOf( token ); -// if ( index > -1 ) { -// index += token.length(); -// key = key.substring( index ); -// log.debug( "MyListener[" + name + "] - recording visit to " + key ); -// visited.add( key ); -// } - } - } - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/RepeatableSessionRefreshTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/RepeatableSessionRefreshTest.java index 56c966909e..f9fed3c8cd 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/RepeatableSessionRefreshTest.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/RepeatableSessionRefreshTest.java @@ -13,12 +13,12 @@ package org.hibernate.test.cache.infinispan.functional.cluster; * @author Galder Zamarreño * @since 3.5 */ -public class RepeatableSessionRefreshTest extends SessionRefreshTestCase { - private static final String CACHE_CONFIG = "entity-repeatable"; +public class RepeatableSessionRefreshTest extends SessionRefreshTest { + private static final String CACHE_CONFIG = "entity-repeatable"; - @Override - protected String getEntityCacheConfigName() { - return CACHE_CONFIG; - } + @Override + protected String getEntityCacheConfigName() { + return CACHE_CONFIG; + } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTest.java similarity index 73% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTestCase.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTest.java index e50e2c3b6d..561d9f1d0c 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTest.java @@ -6,16 +6,16 @@ */ package org.hibernate.test.cache.infinispan.functional.cluster; +import java.util.Arrays; +import java.util.List; import java.util.Map; -import javax.transaction.TransactionManager; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cache.infinispan.InfinispanRegionFactory; import org.hibernate.cfg.Environment; -import org.hibernate.test.cache.infinispan.functional.classloader.Account; -import org.hibernate.test.cache.infinispan.functional.classloader.ClassLoaderTestDAO; +import org.hibernate.test.cache.infinispan.functional.entities.Account; import org.junit.Test; import org.infinispan.Cache; @@ -33,12 +33,16 @@ import static org.junit.Assert.assertNotNull; * @author Galder Zamarreño * @since 3.5 */ -public class SessionRefreshTestCase extends DualNodeTestCase { - private static final Logger log = Logger.getLogger( SessionRefreshTestCase.class ); +public class SessionRefreshTest extends DualNodeTest { + private static final Logger log = Logger.getLogger( SessionRefreshTest.class ); - static int test = 0; private Cache localCache; + @Override + public List getParameters() { + return Arrays.asList(TRANSACTIONAL, READ_WRITE); + } + @Override protected void configureSecondNode(StandardServiceRegistryBuilder ssrb) { super.configureSecondNode( ssrb ); @@ -57,7 +61,7 @@ public class SessionRefreshTestCase extends DualNodeTestCase { @Override public String[] getMappings() { - return new String[] {"cache/infinispan/functional/classloader/Account.hbm.xml"}; + return new String[] {"cache/infinispan/functional/entities/Account.hbm.xml"}; } @Override @@ -70,49 +74,47 @@ public class SessionRefreshTestCase extends DualNodeTestCase { @Test public void testRefreshAfterExternalChange() throws Exception { // First session factory uses a cache - CacheContainer localManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTestCase.LOCAL ); + CacheContainer localManager = ClusterAwareRegionFactory.getCacheManager( DualNodeTest.LOCAL ); localCache = localManager.getCache( Account.class.getName() ); - TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance( DualNodeTestCase.LOCAL ); SessionFactory localFactory = sessionFactory(); // Second session factory doesn't; just needs a transaction manager - TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance( DualNodeTestCase.REMOTE ); SessionFactory remoteFactory = secondNodeEnvironment().getSessionFactory(); - ClassLoaderTestDAO dao0 = new ClassLoaderTestDAO( localFactory, localTM ); - ClassLoaderTestDAO dao1 = new ClassLoaderTestDAO( remoteFactory, remoteTM ); + AccountDAO dao0 = new AccountDAO(useJta, localFactory ); + AccountDAO dao1 = new AccountDAO(useJta, remoteFactory ); Integer id = new Integer( 1 ); - dao0.createAccount( dao0.getSmith(), id, new Integer( 5 ), DualNodeTestCase.LOCAL ); + dao0.createAccount( dao0.getSmith(), id, new Integer( 5 ), DualNodeTest.LOCAL ); // Basic sanity check Account acct1 = dao1.getAccount( id ); assertNotNull( acct1 ); - assertEquals( DualNodeTestCase.LOCAL, acct1.getBranch() ); + assertEquals( DualNodeTest.LOCAL, acct1.getBranch() ); // This dao's session factory isn't caching, so cache won't see this change - dao1.updateAccountBranch( id, DualNodeTestCase.REMOTE ); + dao1.updateAccountBranch( id, DualNodeTest.REMOTE ); // dao1's session doesn't touch the cache, // so reading from dao0 should show a stale value from the cache // (we check to confirm the cache is used) Account acct0 = dao0.getAccount( id ); assertNotNull( acct0 ); - assertEquals( DualNodeTestCase.LOCAL, acct0.getBranch() ); + assertEquals( DualNodeTest.LOCAL, acct0.getBranch() ); log.debug( "Contents when re-reading from local: " + TestingUtil.printCache( localCache ) ); // Now call session.refresh and confirm we get the correct value acct0 = dao0.getAccountWithRefresh( id ); assertNotNull( acct0 ); - assertEquals( DualNodeTestCase.REMOTE, acct0.getBranch() ); + assertEquals( DualNodeTest.REMOTE, acct0.getBranch() ); log.debug( "Contents after refreshing in remote: " + TestingUtil.printCache( localCache ) ); // Double check with a brand new session, in case the other session // for some reason bypassed the 2nd level cache - ClassLoaderTestDAO dao0A = new ClassLoaderTestDAO( localFactory, localTM ); + AccountDAO dao0A = new AccountDAO(useJta, localFactory ); Account acct0A = dao0A.getAccount( id ); assertNotNull( acct0A ); - assertEquals( DualNodeTestCase.REMOTE, acct0A.getBranch() ); + assertEquals( DualNodeTest.REMOTE, acct0A.getBranch() ); log.debug( "Contents after creating a new session: " + TestingUtil.printCache( localCache ) ); } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Account.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Account.java new file mode 100644 index 0000000000..3e43cee0bb --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Account.java @@ -0,0 +1,107 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional.entities; + +import java.io.Serializable; + +/** + * Comment + * + * @author Brian Stansberry + */ +public class Account implements Serializable { + + private static final long serialVersionUID = 1L; + + private Integer id; + private AccountHolder accountHolder; + private Integer balance; + private String branch; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public AccountHolder getAccountHolder() { + return accountHolder; + } + + public void setAccountHolder(AccountHolder accountHolder) { + this.accountHolder = accountHolder; + } + + public Integer getBalance() { + return balance; + } + + public void setBalance(Integer balance) { + this.balance = balance; + } + + public String getBranch() { + return branch; + } + + public void setBranch(String branch) { + this.branch = branch; + } + + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!(obj instanceof Account)) + return false; + Account acct = (Account) obj; + if (!safeEquals(id, acct.id)) + return false; + if (!safeEquals(branch, acct.branch)) + return false; + if (!safeEquals(balance, acct.balance)) + return false; + if (!safeEquals(accountHolder, acct.accountHolder)) + return false; + return true; + } + + @Override + public int hashCode() { + int result = 17; + result = result * 31 + safeHashCode(id); + result = result * 31 + safeHashCode(branch); + result = result * 31 + safeHashCode(balance); + result = result * 31 + safeHashCode(accountHolder); + return result; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(getClass().getName()); + sb.append("[id="); + sb.append(id); + sb.append(",branch="); + sb.append(branch); + sb.append(",balance="); + sb.append(balance); + sb.append(",accountHolder="); + sb.append(accountHolder); + sb.append("]"); + return sb.toString(); + } + + private static int safeHashCode(Object obj) { + return obj == null ? 0 : obj.hashCode(); + } + + private static boolean safeEquals(Object a, Object b) { + return (a == b || (a != null && a.equals(b))); + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/AccountHolder.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/AccountHolder.java new file mode 100644 index 0000000000..547454ddc2 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/AccountHolder.java @@ -0,0 +1,89 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional.entities; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + +/** + * Comment + * + * @author Brian Stansberry + */ +public class AccountHolder implements Serializable { + private static final long serialVersionUID = 1L; + + private String lastName; + private String ssn; + private transient boolean deserialized; + + public AccountHolder() { + this("Stansberry", "123-456-7890"); + } + + public AccountHolder(String lastName, String ssn) { + this.lastName = lastName; + this.ssn = ssn; + } + + public String getLastName() { + return this.lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getSsn() { + return ssn; + } + + public void setSsn(String ssn) { + this.ssn = ssn; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!(obj instanceof AccountHolder)) + return false; + AccountHolder pk = (AccountHolder) obj; + if (!lastName.equals(pk.lastName)) + return false; + if (!ssn.equals(pk.ssn)) + return false; + return true; + } + + @Override + public int hashCode() { + int result = 17; + result = result * 31 + lastName.hashCode(); + result = result * 31 + ssn.hashCode(); + return result; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(getClass().getName()); + sb.append("[lastName="); + sb.append(lastName); + sb.append(",ssn="); + sb.append(ssn); + sb.append(",deserialized="); + sb.append(deserialized); + sb.append("]"); + return sb.toString(); + } + + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + deserialized = true; + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Age.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Age.java similarity index 93% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Age.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Age.java index 16ca827fea..2e6ac1bec3 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Age.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Age.java @@ -5,7 +5,7 @@ * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Citizen.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Citizen.java similarity index 95% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Citizen.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Citizen.java index 5ecb52809e..af1b7b2355 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Citizen.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Citizen.java @@ -6,7 +6,7 @@ */ //$Id$ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Contact.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Contact.java new file mode 100755 index 0000000000..5696ecef7d --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Contact.java @@ -0,0 +1,73 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional.entities; +import java.io.Serializable; + +/** + * Entity that has a many-to-one relationship to a Customer + * + * @author Galder Zamarreño + * @since 3.5 + */ +public class Contact implements Serializable { + Integer id; + String name; + String tlf; + Customer customer; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getTlf() { + return tlf; + } + + public void setTlf(String tlf) { + this.tlf = tlf; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Contact)) + return false; + Contact c = (Contact) o; + return c.id.equals(id) && c.name.equals(name) && c.tlf.equals(tlf); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + (id == null ? 0 : id.hashCode()); + result = 31 * result + name.hashCode(); + result = 31 * result + tlf.hashCode(); + return result; + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Customer.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Customer.java new file mode 100755 index 0000000000..fe08e79ef0 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Customer.java @@ -0,0 +1,49 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.functional.entities; +import java.io.Serializable; +import java.util.Set; + +/** + * Company customer + * + * @author Emmanuel Bernard + * @author Kabir Khan + */ +public class Customer implements Serializable { + Integer id; + String name; + + private transient Set contacts; + + public Customer() { + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String string) { + name = string; + } + + public Set getContacts() { + return contacts; + } + + public void setContacts(Set contacts) { + this.contacts = contacts; + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Item.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Item.java similarity index 97% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Item.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Item.java index 7ca99c51ee..7cb0ea3574 100755 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Item.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Item.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; import java.util.ArrayList; import java.util.HashSet; import java.util.List; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Name.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Name.java similarity index 93% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Name.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Name.java index efc9996aca..fcd809a2b4 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Name.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Name.java @@ -1,4 +1,4 @@ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; import javax.persistence.Embeddable; import java.io.Serializable; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NaturalIdOnManyToOne.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/NaturalIdOnManyToOne.java similarity index 93% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NaturalIdOnManyToOne.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/NaturalIdOnManyToOne.java index c97dc3c719..102fa566a5 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/NaturalIdOnManyToOne.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/NaturalIdOnManyToOne.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; import org.hibernate.annotations.NaturalId; import org.hibernate.annotations.NaturalIdCache; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/OtherItem.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/OtherItem.java similarity index 94% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/OtherItem.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/OtherItem.java index 6b81dabe65..518ecb7100 100755 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/OtherItem.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/OtherItem.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; import java.util.ArrayList; import java.util.List; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Person.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Person.java similarity index 91% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Person.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Person.java index 222525c4ff..a815399168 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Person.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/Person.java @@ -1,4 +1,4 @@ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; import javax.persistence.EmbeddedId; import javax.persistence.Entity; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/State.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/State.java similarity index 91% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/State.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/State.java index 70e8b3b487..5cf3cde9ad 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/State.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/State.java @@ -6,7 +6,7 @@ */ //$Id$ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/VersionedItem.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/VersionedItem.java similarity index 93% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/VersionedItem.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/VersionedItem.java index 34d40b3375..14f10e765f 100755 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/VersionedItem.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/entities/VersionedItem.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.cache.infinispan.functional; +package org.hibernate.test.cache.infinispan.functional.entities; /** diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTest.java similarity index 98% rename from hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTestCase.java rename to hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTest.java index 9101437f34..04535dd09e 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTest.java @@ -26,7 +26,7 @@ import org.hibernate.cache.spi.QueryResultsRegion; import org.hibernate.cache.spi.Region; import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.test.cache.infinispan.AbstractGeneralDataRegionTestCase; +import org.hibernate.test.cache.infinispan.AbstractGeneralDataRegionTest; import org.hibernate.test.cache.infinispan.util.CacheTestUtil; import junit.framework.AssertionFailedError; @@ -53,8 +53,8 @@ import static org.junit.Assert.assertTrue; * @author Galder Zamarreño * @since 3.5 */ -public class QueryRegionImplTestCase extends AbstractGeneralDataRegionTestCase { - private static final Logger log = Logger.getLogger( QueryRegionImplTestCase.class ); +public class QueryRegionImplTest extends AbstractGeneralDataRegionTest { + private static final Logger log = Logger.getLogger( QueryRegionImplTest.class ); @Override protected Region createRegion( @@ -77,7 +77,7 @@ public class QueryRegionImplTestCase extends AbstractGeneralDataRegionTestCase { @Override protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() { - return CacheTestUtil.buildCustomQueryCacheStandardServiceRegistryBuilder( REGION_PREFIX, "replicated-query" ); + return CacheTestUtil.buildCustomQueryCacheStandardServiceRegistryBuilder( REGION_PREFIX, "replicated-query", jtaPlatform ); } private interface RegionConsumer { diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/stress/CorrectnessTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/stress/CorrectnessTestCase.java index 06ba623a3f..74200a73d4 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/stress/CorrectnessTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/stress/CorrectnessTestCase.java @@ -22,7 +22,7 @@ import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cache.infinispan.InfinispanRegionFactory; import org.hibernate.cache.infinispan.access.PutFromLoadValidator; -import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate; +import org.hibernate.cache.infinispan.access.InvalidationCacheAccessDelegate; import org.hibernate.cache.spi.access.RegionAccessStrategy; import org.hibernate.cfg.Environment; import org.hibernate.criterion.Restrictions; @@ -40,6 +40,7 @@ import org.hibernate.resource.transaction.spi.TransactionStatus; import org.hibernate.test.cache.infinispan.stress.entities.Address; import org.hibernate.test.cache.infinispan.stress.entities.Family; import org.hibernate.test.cache.infinispan.stress.entities.Person; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; import org.hibernate.testing.jta.JtaAwareConnectionProviderImpl; import org.hibernate.testing.jta.TestingJtaPlatformImpl; import org.infinispan.commands.VisitableCommand; @@ -51,8 +52,6 @@ import org.infinispan.configuration.cache.InterceptorConfiguration; import org.infinispan.configuration.parsing.ConfigurationBuilderHolder; import org.infinispan.context.InvocationContext; import org.infinispan.interceptors.base.BaseCustomInterceptor; -import org.infinispan.manager.DefaultCacheManager; -import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.remoting.RemoteException; import org.infinispan.transaction.TransactionMode; import org.infinispan.util.logging.LogFactory; @@ -222,7 +221,7 @@ public abstract class CorrectnessTestCase { .applySetting( Environment.URL, "jdbc:h2:mem:" + getDbName() + ";TRACE_LEVEL_FILE=4") .applySetting( Environment.DIALECT, H2Dialect.class.getName() ) .applySetting( Environment.HBM2DDL_AUTO, "create-drop" ) - .applySetting( Environment.CACHE_REGION_FACTORY, TestInfinispanRegionFactory.class.getName()) + .applySetting( Environment.CACHE_REGION_FACTORY, FailingInfinispanRegionFactory.class.getName()) .applySetting( Environment.GENERATE_STATISTICS, "false" ); applySettings(ssrb); @@ -291,23 +290,9 @@ public abstract class CorrectnessTestCase { } } - public static class TestInfinispanRegionFactory extends InfinispanRegionFactory { - private static AtomicInteger counter = new AtomicInteger(); - - public TestInfinispanRegionFactory() { - super(); // For reflection-based instantiation - } - + public static class FailingInfinispanRegionFactory extends TestInfinispanRegionFactory { @Override - protected EmbeddedCacheManager createCacheManager(ConfigurationBuilderHolder holder) { - amendConfiguration(holder); - return new DefaultCacheManager(holder, true); - } - protected void amendConfiguration(ConfigurationBuilderHolder holder) { - holder.getGlobalConfigurationBuilder().globalJmxStatistics().allowDuplicateDomains(true); - holder.getGlobalConfigurationBuilder().transport().nodeName("Node" + (char)('A' + counter.getAndIncrement())); - for (Map.Entry entry : holder.getNamedConfigurationBuilders().entrySet()) { // failure to write into timestamps would cause failure even though both DB and cache has been updated if (!entry.getKey().equals("timestamps") && !entry.getKey().endsWith(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME)) { @@ -323,11 +308,7 @@ public abstract class CorrectnessTestCase { } } - public static class ForceNonTxInfinispanRegionFactory extends TestInfinispanRegionFactory { - public ForceNonTxInfinispanRegionFactory() { - super(); // For reflection-based instantiation - } - + public static class ForceNonTxInfinispanRegionFactory extends FailingInfinispanRegionFactory { @Override protected void amendConfiguration(ConfigurationBuilderHolder holder) { super.amendConfiguration(holder); @@ -996,7 +977,7 @@ public abstract class CorrectnessTestCase { Field delegateField = strategy.getClass().getDeclaredField("delegate"); delegateField.setAccessible(true); Object delegate = delegateField.get(strategy); - Field validatorField = TransactionalAccessDelegate.class.getDeclaredField("putValidator"); + Field validatorField = InvalidationCacheAccessDelegate.class.getDeclaredField("putValidator"); validatorField.setAccessible(true); return (PutFromLoadValidator) validatorField.get(delegate); } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/stress/PutFromLoadStressTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/stress/PutFromLoadStressTestCase.java index 48d2e6ba78..5d144045b5 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/stress/PutFromLoadStressTestCase.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/stress/PutFromLoadStressTestCase.java @@ -29,7 +29,7 @@ import org.hibernate.mapping.Collection; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.RootClass; -import org.hibernate.test.cache.infinispan.functional.Age; +import org.hibernate.test.cache.infinispan.functional.entities.Age; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Ignore; diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/timestamp/TimestampsRegionImplTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/timestamp/TimestampsRegionImplTest.java new file mode 100644 index 0000000000..b6381b163c --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/timestamp/TimestampsRegionImplTest.java @@ -0,0 +1,153 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cache.infinispan.timestamp; + +import java.util.Properties; + +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cache.infinispan.InfinispanRegionFactory; +import org.hibernate.cache.infinispan.timestamp.TimestampsRegionImpl; +import org.hibernate.cache.spi.CacheDataDescription; +import org.hibernate.cache.spi.Region; +import org.hibernate.cache.spi.RegionFactory; +import org.hibernate.cache.spi.UpdateTimestampsCache; + +import org.hibernate.test.cache.infinispan.AbstractGeneralDataRegionTest; +import org.hibernate.test.cache.infinispan.functional.entities.Account; +import org.hibernate.test.cache.infinispan.functional.entities.AccountHolder; +import org.hibernate.test.cache.infinispan.functional.classloader.SelectedClassnameClassLoader; +import org.hibernate.test.cache.infinispan.util.CacheTestUtil; +import org.hibernate.test.cache.infinispan.util.ClassLoaderAwareCache; + +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; +import org.infinispan.AdvancedCache; +import org.infinispan.context.Flag; +import org.infinispan.notifications.Listener; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryActivated; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryEvicted; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryLoaded; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryPassivated; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved; +import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited; +import org.infinispan.notifications.cachelistener.event.Event; + +/** + * Tests of TimestampsRegionImpl. + * + * @author Galder Zamarreño + * @since 3.5 + */ +public class TimestampsRegionImplTest extends AbstractGeneralDataRegionTest { + + @Override + protected String getStandardRegionName(String regionPrefix) { + return regionPrefix + "/" + UpdateTimestampsCache.class.getName(); + } + + @Override + protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) { + return regionFactory.buildTimestampsRegion(regionName, properties); + } + + @Override + protected AdvancedCache getInfinispanCache(InfinispanRegionFactory regionFactory) { + return regionFactory.getCacheManager().getCache("timestamps").getAdvancedCache(); + } + + public void testClearTimestampsRegionInIsolated() throws Exception { + StandardServiceRegistryBuilder ssrb = createStandardServiceRegistryBuilder(); + final StandardServiceRegistry registry = ssrb.build(); + final StandardServiceRegistry registry2 = ssrb.build(); + + try { + final Properties properties = CacheTestUtil.toProperties( ssrb.getSettings() ); + + InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory( + registry, + getCacheTestSupport() + ); + // Sleep a bit to avoid concurrent FLUSH problem + avoidConcurrentFlush(); + + InfinispanRegionFactory regionFactory2 = CacheTestUtil.startRegionFactory( + registry2, + getCacheTestSupport() + ); + // Sleep a bit to avoid concurrent FLUSH problem + avoidConcurrentFlush(); + + TimestampsRegionImpl region = (TimestampsRegionImpl) regionFactory.buildTimestampsRegion( + getStandardRegionName(REGION_PREFIX), + properties + ); + TimestampsRegionImpl region2 = (TimestampsRegionImpl) regionFactory2.buildTimestampsRegion( + getStandardRegionName(REGION_PREFIX), + properties + ); + + Account acct = new Account(); + acct.setAccountHolder(new AccountHolder()); + region.getCache().withFlags(Flag.FORCE_SYNCHRONOUS).put(acct, "boo"); + } + finally { + StandardServiceRegistryBuilder.destroy( registry ); + StandardServiceRegistryBuilder.destroy( registry2 ); + } + } + + @Override + protected Class getRegionFactoryClass() { + return MockInfinispanRegionFactory.class; + } + + public static class MockInfinispanRegionFactory extends TestInfinispanRegionFactory { + + public MockInfinispanRegionFactory() { + } + + @Override + protected AdvancedCache createCacheWrapper(AdvancedCache cache) { + return new ClassLoaderAwareCache(cache, Thread.currentThread().getContextClassLoader()) { + @Override + public void addListener(Object listener) { + super.addListener(new MockClassLoaderAwareListener(listener, this)); + } + }; + } + + @Listener + public static class MockClassLoaderAwareListener extends ClassLoaderAwareCache.ClassLoaderAwareListener { + MockClassLoaderAwareListener(Object listener, ClassLoaderAwareCache cache) { + super(listener, cache); + } + + @CacheEntryActivated + @CacheEntryCreated + @CacheEntryEvicted + @CacheEntryInvalidated + @CacheEntryLoaded + @CacheEntryModified + @CacheEntryPassivated + @CacheEntryRemoved + @CacheEntryVisited + public void event(Event event) throws Throwable { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + String notFoundPackage = "org.hibernate.test.cache.infinispan.functional.entities"; + String[] notFoundClasses = { notFoundPackage + ".Account", notFoundPackage + ".AccountHolder" }; + SelectedClassnameClassLoader visible = new SelectedClassnameClassLoader(null, null, notFoundClasses, cl); + Thread.currentThread().setContextClassLoader(visible); + super.event(event); + Thread.currentThread().setContextClassLoader(cl); + } + } + } + +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/timestamp/TimestampsRegionImplTestCase.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/timestamp/TimestampsRegionImplTestCase.java deleted file mode 100644 index 428718883f..0000000000 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/timestamp/TimestampsRegionImplTestCase.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.cache.infinispan.timestamp; - -import java.util.Properties; - -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cache.infinispan.InfinispanRegionFactory; -import org.hibernate.cache.infinispan.timestamp.TimestampsRegionImpl; -import org.hibernate.cache.spi.CacheDataDescription; -import org.hibernate.cache.spi.Region; -import org.hibernate.cache.spi.UpdateTimestampsCache; - -import org.hibernate.test.cache.infinispan.AbstractGeneralDataRegionTestCase; -import org.hibernate.test.cache.infinispan.functional.SingleNodeTestCase; -import org.hibernate.test.cache.infinispan.functional.classloader.Account; -import org.hibernate.test.cache.infinispan.functional.classloader.AccountHolder; -import org.hibernate.test.cache.infinispan.functional.classloader.SelectedClassnameClassLoader; -import org.hibernate.test.cache.infinispan.util.CacheTestUtil; -import org.hibernate.test.cache.infinispan.util.ClassLoaderAwareCache; - -import org.infinispan.AdvancedCache; -import org.infinispan.context.Flag; -import org.infinispan.notifications.Listener; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryActivated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryEvicted; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryLoaded; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryPassivated; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved; -import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited; -import org.infinispan.notifications.cachelistener.event.Event; - -/** - * Tests of TimestampsRegionImpl. - * - * @author Galder Zamarreño - * @since 3.5 - */ -public class TimestampsRegionImplTestCase extends AbstractGeneralDataRegionTestCase { - - @Override - protected String getStandardRegionName(String regionPrefix) { - return regionPrefix + "/" + UpdateTimestampsCache.class.getName(); - } - - @Override - protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) { - return regionFactory.buildTimestampsRegion(regionName, properties); - } - - @Override - protected AdvancedCache getInfinispanCache(InfinispanRegionFactory regionFactory) { - return regionFactory.getCacheManager().getCache("timestamps").getAdvancedCache(); - } - - public void testClearTimestampsRegionInIsolated() throws Exception { - StandardServiceRegistryBuilder ssrb = createStandardServiceRegistryBuilder(); - final StandardServiceRegistry registry = ssrb.build(); - final StandardServiceRegistry registry2 = ssrb.build(); - - try { - final Properties properties = CacheTestUtil.toProperties( ssrb.getSettings() ); - - InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory( - registry, - getCacheTestSupport() - ); - // Sleep a bit to avoid concurrent FLUSH problem - avoidConcurrentFlush(); - - InfinispanRegionFactory regionFactory2 = CacheTestUtil.startRegionFactory( - registry2, - getCacheTestSupport() - ); - // Sleep a bit to avoid concurrent FLUSH problem - avoidConcurrentFlush(); - - TimestampsRegionImpl region = (TimestampsRegionImpl) regionFactory.buildTimestampsRegion( - getStandardRegionName(REGION_PREFIX), - properties - ); - TimestampsRegionImpl region2 = (TimestampsRegionImpl) regionFactory2.buildTimestampsRegion( - getStandardRegionName(REGION_PREFIX), - properties - ); - - Account acct = new Account(); - acct.setAccountHolder(new AccountHolder()); - region.getCache().withFlags(Flag.FORCE_SYNCHRONOUS).put(acct, "boo"); - } - finally { - StandardServiceRegistryBuilder.destroy( registry ); - StandardServiceRegistryBuilder.destroy( registry2 ); - } - } - - @Override - protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() { - return CacheTestUtil.buildBaselineStandardServiceRegistryBuilder( - "test", - MockInfinispanRegionFactory.class, - false, - true - ); - } - - public static class MockInfinispanRegionFactory extends SingleNodeTestCase.TestInfinispanRegionFactory { - - public MockInfinispanRegionFactory() { - } - - @Override - protected AdvancedCache createCacheWrapper(AdvancedCache cache) { - return new ClassLoaderAwareCache(cache, Thread.currentThread().getContextClassLoader()) { - @Override - public void addListener(Object listener) { - super.addListener(new MockClassLoaderAwareListener(listener, this)); - } - }; - } - - @Listener - public static class MockClassLoaderAwareListener extends ClassLoaderAwareCache.ClassLoaderAwareListener { - MockClassLoaderAwareListener(Object listener, ClassLoaderAwareCache cache) { - super(listener, cache); - } - - @CacheEntryActivated - @CacheEntryCreated - @CacheEntryEvicted - @CacheEntryInvalidated - @CacheEntryLoaded - @CacheEntryModified - @CacheEntryPassivated - @CacheEntryRemoved - @CacheEntryVisited - public void event(Event event) throws Throwable { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - String notFoundPackage = "org.hibernate.test.cache.infinispan.functional.classloader"; - String[] notFoundClasses = { notFoundPackage + ".Account", notFoundPackage + ".AccountHolder" }; - SelectedClassnameClassLoader visible = new SelectedClassnameClassLoader(null, null, notFoundClasses, cl); - Thread.currentThread().setContextClassLoader(visible); - super.event(event); - Thread.currentThread().setContextClassLoader(cl); - } - } - } - -} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java index 6fbb49e189..e2d10b36bd 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/JBossStandaloneJtaExampleTest.java @@ -22,7 +22,6 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.engine.transaction.jta.platform.internal.JBossStandAloneJtaPlatform; import org.hibernate.mapping.Collection; @@ -33,12 +32,13 @@ import org.hibernate.service.ServiceRegistry; import org.hibernate.stat.Statistics; import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup; +import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory; import org.hibernate.testing.ServiceRegistryBuilder; import org.hibernate.testing.jta.JtaAwareConnectionProviderImpl; -import org.hibernate.test.cache.infinispan.functional.Item; +import org.hibernate.test.cache.infinispan.functional.entities.Item; import org.junit.After; import org.junit.Before; -import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.infinispan.configuration.cache.ConfigurationBuilder; @@ -66,208 +66,205 @@ import static org.junit.Assert.assertNull; * @since 3.5 */ public class JBossStandaloneJtaExampleTest { - private static final Log log = LogFactory.getLog(JBossStandaloneJtaExampleTest.class); - private static final JBossStandaloneJTAManagerLookup lookup = new JBossStandaloneJTAManagerLookup(); - Context ctx; - Main jndiServer; - private ServiceRegistry serviceRegistry; + private static final Log log = LogFactory.getLog(JBossStandaloneJtaExampleTest.class); + private static final JBossStandaloneJTAManagerLookup lookup = new JBossStandaloneJTAManagerLookup(); + Context ctx; + Main jndiServer; + private ServiceRegistry serviceRegistry; - @ClassRule - public static final InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); + @Rule + public final InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup(); - @Before - public void setUp() throws Exception { - jndiServer = startJndiServer(); - ctx = createJndiContext(); - // Inject configuration to initialise transaction manager from config classloader - lookup.init(new ConfigurationBuilder().build()); - bindTransactionManager(); - bindUserTransaction(); - } + @Before + public void setUp() throws Exception { + jndiServer = startJndiServer(); + ctx = createJndiContext(); + // Inject configuration to initialise transaction manager from config classloader + lookup.init(new ConfigurationBuilder().build()); + bindTransactionManager(); + bindUserTransaction(); + } - @After - public void tearDown() throws Exception { - try { - unbind("UserTransaction", ctx); - unbind("java:/TransactionManager", ctx); - ctx.close(); - jndiServer.stop(); + @After + public void tearDown() throws Exception { + try { + unbind("UserTransaction", ctx); + unbind("java:/TransactionManager", ctx); + ctx.close(); + jndiServer.stop(); } finally { if ( serviceRegistry != null ) { ServiceRegistryBuilder.destroy( serviceRegistry ); } } - } - @Test - public void testPersistAndLoadUnderJta() throws Exception { - Item item; - SessionFactory sessionFactory = buildSessionFactory(); - try { - UserTransaction ut = (UserTransaction) ctx.lookup("UserTransaction"); - ut.begin(); - try { - Session session = sessionFactory.openSession(); - session.getTransaction().begin(); - item = new Item("anItem", "An item owned by someone"); - session.persist(item); - session.getTransaction().commit(); - session.close(); - } catch(Exception e) { - ut.setRollbackOnly(); - throw e; - } finally { - if (ut.getStatus() == Status.STATUS_ACTIVE) - ut.commit(); - else - ut.rollback(); - } + } + @Test + public void testPersistAndLoadUnderJta() throws Exception { + Item item; + SessionFactory sessionFactory = buildSessionFactory(); + try { + UserTransaction ut = (UserTransaction) ctx.lookup("UserTransaction"); + ut.begin(); + try { + Session session = sessionFactory.openSession(); + session.getTransaction().begin(); + item = new Item("anItem", "An item owned by someone"); + session.persist(item); + session.getTransaction().commit(); + session.close(); + } catch(Exception e) { + ut.setRollbackOnly(); + throw e; + } finally { + if (ut.getStatus() == Status.STATUS_ACTIVE) + ut.commit(); + else + ut.rollback(); + } - ut = (UserTransaction) ctx.lookup("UserTransaction"); - ut.begin(); - try { - Session session = sessionFactory.openSession(); - session.getTransaction().begin(); - Item found = (Item) session.load(Item.class, item.getId()); - Statistics stats = session.getSessionFactory().getStatistics(); - log.info(stats.toString()); - assertEquals(item.getDescription(), found.getDescription()); - assertEquals(0, stats.getSecondLevelCacheMissCount()); - assertEquals(1, stats.getSecondLevelCacheHitCount()); - session.delete(found); - session.getTransaction().commit(); - session.close(); - } catch(Exception e) { - ut.setRollbackOnly(); - throw e; - } finally { - if (ut.getStatus() == Status.STATUS_ACTIVE) - ut.commit(); - else - ut.rollback(); - } + ut = (UserTransaction) ctx.lookup("UserTransaction"); + ut.begin(); + try { + Session session = sessionFactory.openSession(); + session.getTransaction().begin(); + Item found = (Item) session.load(Item.class, item.getId()); + Statistics stats = session.getSessionFactory().getStatistics(); + log.info(stats.toString()); + assertEquals(item.getDescription(), found.getDescription()); + assertEquals(0, stats.getSecondLevelCacheMissCount()); + assertEquals(1, stats.getSecondLevelCacheHitCount()); + session.delete(found); + session.getTransaction().commit(); + session.close(); + } catch(Exception e) { + ut.setRollbackOnly(); + throw e; + } finally { + if (ut.getStatus() == Status.STATUS_ACTIVE) + ut.commit(); + else + ut.rollback(); + } - ut = (UserTransaction) ctx.lookup("UserTransaction"); - ut.begin(); - try { - Session session = sessionFactory.openSession(); - session.getTransaction().begin(); - assertNull(session.get(Item.class, item.getId())); - session.getTransaction().commit(); - session.close(); - } catch(Exception e) { - ut.setRollbackOnly(); - throw e; - } finally { - if (ut.getStatus() == Status.STATUS_ACTIVE) - ut.commit(); - else - ut.rollback(); - } - } finally { - if (sessionFactory != null) - sessionFactory.close(); - } + ut = (UserTransaction) ctx.lookup("UserTransaction"); + ut.begin(); + try { + Session session = sessionFactory.openSession(); + session.getTransaction().begin(); + assertNull(session.get(Item.class, item.getId())); + session.getTransaction().commit(); + session.close(); + } catch(Exception e) { + ut.setRollbackOnly(); + throw e; + } finally { + if (ut.getStatus() == Status.STATUS_ACTIVE) + ut.commit(); + else + ut.rollback(); + } + } finally { + if (sessionFactory != null) + sessionFactory.close(); + } - } + } - private Main startJndiServer() throws Exception { - // Create an in-memory jndi - NamingServer namingServer = new NamingServer(); - NamingContext.setLocal(namingServer); - Main namingMain = new Main(); - namingMain.setInstallGlobalService(true); - namingMain.setPort( -1 ); - namingMain.start(); - return namingMain; - } + private Main startJndiServer() throws Exception { + // Create an in-memory jndi + NamingServer namingServer = new NamingServer(); + NamingContext.setLocal(namingServer); + Main namingMain = new Main(); + namingMain.setInstallGlobalService(true); + namingMain.setPort( -1 ); + namingMain.start(); + return namingMain; + } - private Context createJndiContext() throws Exception { - Properties props = new Properties(); - props.put( Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory" ); - props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); - return new InitialContext(props); - } + private Context createJndiContext() throws Exception { + Properties props = new Properties(); + props.put( Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory" ); + props.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces"); + return new InitialContext(props); + } - private void bindTransactionManager() throws Exception { - // as JBossTransactionManagerLookup extends JNDITransactionManagerLookup we must also register the TransactionManager - bind("java:/TransactionManager", lookup.getTransactionManager(), lookup.getTransactionManager().getClass(), ctx); - } + private void bindTransactionManager() throws Exception { + // as JBossTransactionManagerLookup extends JNDITransactionManagerLookup we must also register the TransactionManager + bind("java:/TransactionManager", lookup.getTransactionManager(), lookup.getTransactionManager().getClass(), ctx); + } - private void bindUserTransaction() throws Exception { - // also the UserTransaction must be registered on jndi: org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory#getUserTransaction() requires this - bind( "UserTransaction", lookup.getUserTransaction(), lookup.getUserTransaction().getClass(), ctx ); - } + private void bindUserTransaction() throws Exception { + // also the UserTransaction must be registered on jndi: org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory#getUserTransaction() requires this + bind( "UserTransaction", lookup.getUserTransaction(), lookup.getUserTransaction().getClass(), ctx ); + } - /** - * Helper method that binds the a non serializable object to the JNDI tree. - * - * @param jndiName Name under which the object must be bound - * @param who Object to bind in JNDI - * @param classType Class type under which should appear the bound object - * @param ctx Naming context under which we bind the object - * @throws Exception Thrown if a naming exception occurs during binding - */ - private void bind(String jndiName, Object who, Class classType, Context ctx) throws Exception { - // Ah ! This service isn't serializable, so we use a helper class - NonSerializableFactory.bind(jndiName, who); - Name n = ctx.getNameParser("").parse(jndiName); - while (n.size() > 1) { - String ctxName = n.get(0); - try { - ctx = (Context) ctx.lookup(ctxName); - } catch (NameNotFoundException e) { - System.out.println("Creating subcontext:" + ctxName); - ctx = ctx.createSubcontext(ctxName); - } - n = n.getSuffix(1); - } + /** + * Helper method that binds the a non serializable object to the JNDI tree. + * + * @param jndiName Name under which the object must be bound + * @param who Object to bind in JNDI + * @param classType Class type under which should appear the bound object + * @param ctx Naming context under which we bind the object + * @throws Exception Thrown if a naming exception occurs during binding + */ + private void bind(String jndiName, Object who, Class classType, Context ctx) throws Exception { + // Ah ! This service isn't serializable, so we use a helper class + NonSerializableFactory.bind(jndiName, who); + Name n = ctx.getNameParser("").parse(jndiName); + while (n.size() > 1) { + String ctxName = n.get(0); + try { + ctx = (Context) ctx.lookup(ctxName); + } catch (NameNotFoundException e) { + System.out.println("Creating subcontext:" + ctxName); + ctx = ctx.createSubcontext(ctxName); + } + n = n.getSuffix(1); + } - // The helper class NonSerializableFactory uses address type nns, we go on to - // use the helper class to bind the service object in JNDI - StringRefAddr addr = new StringRefAddr("nns", jndiName); - Reference ref = new Reference(classType.getName(), addr, NonSerializableFactory.class.getName(), null); - ctx.rebind(n.get(0), ref); - } + // The helper class NonSerializableFactory uses address type nns, we go on to + // use the helper class to bind the service object in JNDI + StringRefAddr addr = new StringRefAddr("nns", jndiName); + Reference ref = new Reference(classType.getName(), addr, NonSerializableFactory.class.getName(), null); + ctx.rebind(n.get(0), ref); + } - private void unbind(String jndiName, Context ctx) throws Exception { - NonSerializableFactory.unbind(jndiName); - ctx.unbind(jndiName); - } + private void unbind(String jndiName, Context ctx) throws Exception { + NonSerializableFactory.unbind(jndiName); + ctx.unbind(jndiName); + } - private SessionFactory buildSessionFactory() { - // Extra options located in src/test/resources/hibernate.properties - StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder() - .applySetting( Environment.DIALECT, "HSQL" ) - .applySetting( Environment.HBM2DDL_AUTO, "create-drop" ) - .applySetting( Environment.CONNECTION_PROVIDER, JtaAwareConnectionProviderImpl.class.getName() ) - .applySetting( Environment.JNDI_CLASS, "org.jnp.interfaces.NamingContextFactory" ) - .applySetting( Environment.TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class.getName() ) - .applySetting( Environment.CURRENT_SESSION_CONTEXT_CLASS, "jta" ) - .applySetting( Environment.RELEASE_CONNECTIONS, "auto" ) - .applySetting( Environment.USE_SECOND_LEVEL_CACHE, "true" ) - .applySetting( Environment.USE_QUERY_CACHE, "true" ) - .applySetting( AvailableSettings.JTA_PLATFORM, new JBossStandAloneJtaPlatform() ) - .applySetting( - Environment.CACHE_REGION_FACTORY, - "org.hibernate.test.cache.infinispan.functional.SingleNodeTestCase$TestInfinispanRegionFactory" - ); + private SessionFactory buildSessionFactory() { + // Extra options located in src/test/resources/hibernate.properties + StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder() + .applySetting( Environment.DIALECT, "HSQL" ) + .applySetting( Environment.HBM2DDL_AUTO, "create-drop" ) + .applySetting( Environment.CONNECTION_PROVIDER, JtaAwareConnectionProviderImpl.class.getName() ) + .applySetting( Environment.JNDI_CLASS, "org.jnp.interfaces.NamingContextFactory" ) + .applySetting( Environment.TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class.getName() ) + .applySetting( Environment.CURRENT_SESSION_CONTEXT_CLASS, "jta" ) + .applySetting( Environment.RELEASE_CONNECTIONS, "auto" ) + .applySetting( Environment.USE_SECOND_LEVEL_CACHE, "true" ) + .applySetting( Environment.USE_QUERY_CACHE, "true" ) + .applySetting( Environment.JTA_PLATFORM, new JBossStandAloneJtaPlatform() ) + .applySetting( Environment.CACHE_REGION_FACTORY, TestInfinispanRegionFactory.class.getName() ); - StandardServiceRegistry serviceRegistry = ssrb.build(); + StandardServiceRegistry serviceRegistry = ssrb.build(); - MetadataSources metadataSources = new MetadataSources( serviceRegistry ); - metadataSources.addResource( "org/hibernate/test/cache/infinispan/functional/Item.hbm.xml" ); + MetadataSources metadataSources = new MetadataSources( serviceRegistry ); + metadataSources.addResource("org/hibernate/test/cache/infinispan/functional/entities/Item.hbm.xml"); - Metadata metadata = metadataSources.buildMetadata(); - for ( PersistentClass entityBinding : metadata.getEntityBindings() ) { - if ( entityBinding instanceof RootClass ) { - ( (RootClass) entityBinding ).setCacheConcurrencyStrategy( "transactional" ); - } - } - for ( Collection collectionBinding : metadata.getCollectionBindings() ) { - collectionBinding.setCacheConcurrencyStrategy( "transactional" ); - } + Metadata metadata = metadataSources.buildMetadata(); + for ( PersistentClass entityBinding : metadata.getEntityBindings() ) { + if ( entityBinding instanceof RootClass ) { + ( (RootClass) entityBinding ).setCacheConcurrencyStrategy( "transactional" ); + } + } + for ( Collection collectionBinding : metadata.getCollectionBindings() ) { + collectionBinding.setCacheConcurrencyStrategy( "transactional" ); + } - return metadata.buildSessionFactory(); - } + return metadata.buildSessionFactory(); + } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionCoordinator.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionCoordinator.java index 162ab44404..629eeb2e2e 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionCoordinator.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionCoordinator.java @@ -1,12 +1,20 @@ package org.hibernate.test.cache.infinispan.util; +import org.hibernate.HibernateException; +import org.hibernate.Transaction; import org.hibernate.engine.transaction.spi.IsolationDelegate; import org.hibernate.engine.transaction.spi.TransactionObserver; import org.hibernate.resource.transaction.SynchronizationRegistry; import org.hibernate.resource.transaction.TransactionCoordinator; import org.hibernate.resource.transaction.TransactionCoordinatorBuilder; +import org.hibernate.resource.transaction.backend.jta.internal.StatusTranslator; +import org.hibernate.resource.transaction.spi.TransactionStatus; import org.infinispan.transaction.tm.BatchModeTransactionManager; +import org.infinispan.transaction.tm.DummyTransaction; +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.Synchronization; @@ -19,76 +27,165 @@ import javax.transaction.SystemException; * @author Radim Vansa <rvansa@redhat.com> */ public class BatchModeTransactionCoordinator implements TransactionCoordinator { - @Override - public void explicitJoin() { - } + private BatchModeTransactionManager tm = BatchModeTransactionManager.getInstance();; + private TransactionDriver transactionDriver = new TransactionDriver() { + @Override + public void begin() { + try { + tm.begin(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } - @Override - public boolean isJoined() { - return true; - } + @Override + public void commit() { + try { + tm.commit(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } - @Override - public void pulse() { - } + @Override + public void rollback() { + try { + tm.rollback(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } - @Override - public TransactionDriver getTransactionDriverControl() { - throw new UnsupportedOperationException(); - } + @Override + public TransactionStatus getStatus() { + try { + DummyTransaction transaction = tm.getTransaction(); + return transaction == null ? TransactionStatus.NOT_ACTIVE : StatusTranslator.translate(transaction.getStatus()); + } catch (SystemException e) { + throw new RuntimeException(e); + } + } - @Override - public SynchronizationRegistry getLocalSynchronizations() { - return new SynchronizationRegistry() { - @Override - public void registerSynchronization(Synchronization synchronization) { - try { - BatchModeTransactionManager.getInstance().getTransaction().registerSynchronization(synchronization); - } catch (RollbackException e) { - throw new RuntimeException(e); - } catch (SystemException e) { - throw new RuntimeException(e); - } - } - }; - } + @Override + public void markRollbackOnly() { + throw new UnsupportedOperationException(); + } + };; - @Override - public boolean isActive() { - try { - return BatchModeTransactionManager.getInstance().getStatus() == Status.STATUS_ACTIVE; - } catch (SystemException e) { - return false; - } - } + @Override + public void explicitJoin() { + } - @Override - public IsolationDelegate createIsolationDelegate() { - throw new UnsupportedOperationException(); - } + @Override + public boolean isJoined() { + return true; + } - @Override - public void addObserver(TransactionObserver observer) { - throw new UnsupportedOperationException(); - } + @Override + public void pulse() { + } - @Override - public void removeObserver(TransactionObserver observer) { - throw new UnsupportedOperationException(); - } + @Override + public TransactionDriver getTransactionDriverControl() { + return transactionDriver; + } - @Override - public TransactionCoordinatorBuilder getTransactionCoordinatorBuilder() { - throw new UnsupportedOperationException(); - } + @Override + public SynchronizationRegistry getLocalSynchronizations() { + return new SynchronizationRegistry() { + @Override + public void registerSynchronization(Synchronization synchronization) { + try { + BatchModeTransactionManager.getInstance().getTransaction().registerSynchronization(synchronization); + } catch (RollbackException e) { + throw new RuntimeException(e); + } catch (SystemException e) { + throw new RuntimeException(e); + } + } + }; + } - @Override - public void setTimeOut(int seconds) { - throw new UnsupportedOperationException(); - } + @Override + public boolean isActive() { + try { + return BatchModeTransactionManager.getInstance().getStatus() == Status.STATUS_ACTIVE; + } catch (SystemException e) { + return false; + } + } - @Override - public int getTimeOut() { - throw new UnsupportedOperationException(); - } + @Override + public IsolationDelegate createIsolationDelegate() { + throw new UnsupportedOperationException(); + } + + @Override + public void addObserver(TransactionObserver observer) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeObserver(TransactionObserver observer) { + throw new UnsupportedOperationException(); + } + + @Override + public TransactionCoordinatorBuilder getTransactionCoordinatorBuilder() { + throw new UnsupportedOperationException(); + } + + @Override + public void setTimeOut(int seconds) { + throw new UnsupportedOperationException(); + } + + @Override + public int getTimeOut() { + throw new UnsupportedOperationException(); + } + + public Transaction newTransaction() { + return new BatchModeTransaction(); + } + + public class BatchModeTransaction implements Transaction { + @Override + public void begin() { + } + + @Override + public void commit() { + transactionDriver.commit(); + } + + @Override + public void rollback() { + transactionDriver.rollback(); + } + + @Override + public TransactionStatus getStatus() { + return transactionDriver.getStatus(); + } + + @Override + public void registerSynchronization(Synchronization synchronization) throws HibernateException { + getLocalSynchronizations().registerSynchronization(synchronization); + } + + @Override + public void setTimeout(int seconds) { + } + + @Override + public int getTimeout() { + return 0; + } + + @Override + public void markRollbackOnly() { + transactionDriver.markRollbackOnly(); + } + } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java index de495142f3..1baad09699 100644 --- a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java @@ -19,11 +19,14 @@ import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cache.infinispan.InfinispanRegionFactory; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.internal.util.compare.EqualsHelper; +import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl; +import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl; import org.hibernate.service.ServiceRegistry; -import org.hibernate.test.cache.infinispan.functional.SingleNodeTestCase; /** * Utilities for cache testing. @@ -31,148 +34,155 @@ import org.hibernate.test.cache.infinispan.functional.SingleNodeTestCase; * @author Brian Stansberry */ public class CacheTestUtil { - @SuppressWarnings("unchecked") - public static Map buildBaselineSettings( - String regionPrefix, - Class regionFactory, - boolean use2ndLevel, - boolean useQueries) { - Map settings = new HashMap(); + @SuppressWarnings("unchecked") + public static Map buildBaselineSettings( + String regionPrefix, + Class regionFactory, + boolean use2ndLevel, + boolean useQueries, + Class jtaPlatform) { + Map settings = new HashMap(); - settings.put( AvailableSettings.GENERATE_STATISTICS, "true" ); - settings.put( AvailableSettings.USE_STRUCTURED_CACHE, "true" ); - settings.put( AvailableSettings.JTA_PLATFORM, BatchModeJtaPlatform.class.getName() ); + settings.put( AvailableSettings.GENERATE_STATISTICS, "true" ); + settings.put( AvailableSettings.USE_STRUCTURED_CACHE, "true" ); + if (jtaPlatform == null) { + settings.put(Environment.TRANSACTION_COORDINATOR_STRATEGY, JdbcResourceLocalTransactionCoordinatorBuilderImpl.class.getName()); + } else { + settings.put(Environment.TRANSACTION_COORDINATOR_STRATEGY, JtaTransactionCoordinatorBuilderImpl.class.getName()); + settings.put(AvailableSettings.JTA_PLATFORM, jtaPlatform); + } + settings.put( AvailableSettings.CACHE_REGION_FACTORY, regionFactory.getName() ); + settings.put( AvailableSettings.CACHE_REGION_PREFIX, regionPrefix ); + settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, String.valueOf( use2ndLevel ) ); + settings.put( AvailableSettings.USE_QUERY_CACHE, String.valueOf( useQueries ) ); - settings.put( AvailableSettings.CACHE_REGION_FACTORY, regionFactory.getName() ); - settings.put( AvailableSettings.CACHE_REGION_PREFIX, regionPrefix ); - settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, String.valueOf( use2ndLevel ) ); - settings.put( AvailableSettings.USE_QUERY_CACHE, String.valueOf( useQueries ) ); + return settings; + } - return settings; - } + public static StandardServiceRegistryBuilder buildBaselineStandardServiceRegistryBuilder( + String regionPrefix, + Class regionFactory, + boolean use2ndLevel, + boolean useQueries, + Class jtaPlatform) { + StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(); - public static StandardServiceRegistryBuilder buildBaselineStandardServiceRegistryBuilder( - String regionPrefix, - Class regionFactory, - boolean use2ndLevel, - boolean useQueries) { - StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(); + ssrb.applySettings( + buildBaselineSettings( regionPrefix, regionFactory, use2ndLevel, useQueries, jtaPlatform ) + ); - ssrb.applySettings( - buildBaselineSettings( regionPrefix, regionFactory, use2ndLevel, useQueries ) - ); + return ssrb; + } - return ssrb; - } + public static StandardServiceRegistryBuilder buildCustomQueryCacheStandardServiceRegistryBuilder( + String regionPrefix, + String queryCacheName, + Class jtaPlatform) { + final StandardServiceRegistryBuilder ssrb = buildBaselineStandardServiceRegistryBuilder( + regionPrefix, InfinispanRegionFactory.class, true, true, jtaPlatform + ); + ssrb.applySetting( InfinispanRegionFactory.QUERY_CACHE_RESOURCE_PROP, queryCacheName ); + return ssrb; + } - public static StandardServiceRegistryBuilder buildCustomQueryCacheStandardServiceRegistryBuilder( - String regionPrefix, - String queryCacheName) { - final StandardServiceRegistryBuilder ssrb = buildBaselineStandardServiceRegistryBuilder( - regionPrefix, InfinispanRegionFactory.class, true, true - ); - ssrb.applySetting( InfinispanRegionFactory.QUERY_CACHE_RESOURCE_PROP, queryCacheName ); - return ssrb; - } + public static InfinispanRegionFactory startRegionFactory(ServiceRegistry serviceRegistry) { + try { + final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); - public static InfinispanRegionFactory startRegionFactory(ServiceRegistry serviceRegistry) { - try { - final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); + String factoryType = cfgService.getSetting( AvailableSettings.CACHE_REGION_FACTORY, StandardConverters.STRING ); + Class clazz = Thread.currentThread().getContextClassLoader().loadClass( factoryType ); + InfinispanRegionFactory regionFactory; + if (clazz == InfinispanRegionFactory.class) { + regionFactory = new TestInfinispanRegionFactory(); + } + else { + regionFactory = (InfinispanRegionFactory) clazz.newInstance(); + } - String factoryType = cfgService.getSetting( AvailableSettings.CACHE_REGION_FACTORY, StandardConverters.STRING ); - Class clazz = Thread.currentThread().getContextClassLoader().loadClass( factoryType ); - InfinispanRegionFactory regionFactory; - if (clazz == InfinispanRegionFactory.class) { - regionFactory = new SingleNodeTestCase.TestInfinispanRegionFactory(); - } - else { - regionFactory = (InfinispanRegionFactory) clazz.newInstance(); - } + final SessionFactoryOptionsImpl sessionFactoryOptions = new SessionFactoryOptionsImpl( + new SessionFactoryBuilderImpl.SessionFactoryOptionsStateStandardImpl( + (StandardServiceRegistry) serviceRegistry + ) + ); + final Properties properties = toProperties( cfgService.getSettings() ); - final SessionFactoryOptionsImpl sessionFactoryOptions = new SessionFactoryOptionsImpl( - new SessionFactoryBuilderImpl.SessionFactoryOptionsStateStandardImpl( - (StandardServiceRegistry) serviceRegistry - ) - ); - final Properties properties = toProperties( cfgService.getSettings() ); + regionFactory.start( sessionFactoryOptions, properties ); - regionFactory.start( sessionFactoryOptions, properties ); + return regionFactory; + } + catch (RuntimeException e) { + throw e; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } - return regionFactory; - } - catch (RuntimeException e) { - throw e; - } - catch (Exception e) { - throw new RuntimeException(e); - } - } + public static InfinispanRegionFactory startRegionFactory( + ServiceRegistry serviceRegistry, + CacheTestSupport testSupport) { + InfinispanRegionFactory factory = startRegionFactory( serviceRegistry ); + testSupport.registerFactory( factory ); + return factory; + } - public static InfinispanRegionFactory startRegionFactory( - ServiceRegistry serviceRegistry, - CacheTestSupport testSupport) { - InfinispanRegionFactory factory = startRegionFactory( serviceRegistry ); - testSupport.registerFactory( factory ); - return factory; - } + public static void stopRegionFactory( + InfinispanRegionFactory factory, + CacheTestSupport testSupport) { + testSupport.unregisterFactory( factory ); + factory.stop(); + } - public static void stopRegionFactory( - InfinispanRegionFactory factory, - CacheTestSupport testSupport) { - testSupport.unregisterFactory( factory ); - factory.stop(); - } + public static Properties toProperties(Map map) { + if ( map == null ) { + return null; + } - public static Properties toProperties(Map map) { - if ( map == null ) { - return null; - } + if ( map instanceof Properties ) { + return (Properties) map; + } - if ( map instanceof Properties ) { - return (Properties) map; - } + Properties properties = new Properties(); + properties.putAll( map ); + return properties; + } - Properties properties = new Properties(); - properties.putAll( map ); - return properties; - } + /** + * Executes {@link #assertEqualsEventually(Object, Callable, long, TimeUnit)} without time limit. + * @param expected + * @param callable + * @param + */ + public static void assertEqualsEventually(T expected, Callable callable) throws Exception { + assertEqualsEventually(expected, callable, -1, TimeUnit.SECONDS); + } - /** - * Executes {@link #assertEqualsEventually(Object, Callable, long, TimeUnit)} without time limit. - * @param expected - * @param callable - * @param - */ - public static void assertEqualsEventually(T expected, Callable callable) throws Exception { - assertEqualsEventually(expected, callable, -1, TimeUnit.SECONDS); - } + /** + * Periodically calls callable and compares returned value with expected value. If the value matches to expected, + * the method returns. If callable throws an exception, this is propagated. If the returned value does not match to + * expected before timeout, {@link TimeoutException} is thrown. + * @param expected + * @param callable + * @param timeout If non-positive, there is no limit. + * @param timeUnit + * @param + */ + public static void assertEqualsEventually(T expected, Callable callable, long timeout, TimeUnit timeUnit) throws Exception { + long now, deadline = timeout <= 0 ? Long.MAX_VALUE : System.currentTimeMillis() + timeUnit.toMillis(timeout); + for (;;) { + T value = callable.call(); + if (EqualsHelper.equals(value, expected)) return; + now = System.currentTimeMillis(); + if (now < deadline) { + Thread.sleep(Math.min(100, deadline - now)); + } else break; + } + throw new TimeoutException(); + } - /** - * Periodically calls callable and compares returned value with expected value. If the value matches to expected, - * the method returns. If callable throws an exception, this is propagated. If the returned value does not match to - * expected before timeout, {@link TimeoutException} is thrown. - * @param expected - * @param callable - * @param timeout If non-positive, there is no limit. - * @param timeUnit - * @param - */ - public static void assertEqualsEventually(T expected, Callable callable, long timeout, TimeUnit timeUnit) throws Exception { - long now, deadline = timeout <= 0 ? Long.MAX_VALUE : System.currentTimeMillis() + timeUnit.toMillis(timeout); - for (;;) { - T value = callable.call(); - if (EqualsHelper.equals(value, expected)) return; - now = System.currentTimeMillis(); - if (now < deadline) { - Thread.sleep(Math.min(100, deadline - now)); - } else break; - } - throw new TimeoutException(); - } - - /** - * Prevent instantiation. - */ - private CacheTestUtil() { - } + /** + * Prevent instantiation. + */ + private CacheTestUtil() { + } } diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/JdbcResourceTransactionMock.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/JdbcResourceTransactionMock.java new file mode 100644 index 0000000000..7dd1b4d247 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/JdbcResourceTransactionMock.java @@ -0,0 +1,35 @@ +package org.hibernate.test.cache.infinispan.util; + +import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransaction; +import org.hibernate.resource.transaction.spi.TransactionStatus; + +import static org.junit.Assert.assertEquals; + +/** + * @author Radim Vansa <rvansa@redhat.com> + */ +public class JdbcResourceTransactionMock implements JdbcResourceTransaction { + private TransactionStatus status = TransactionStatus.NOT_ACTIVE; + + @Override + public void begin() { + assertEquals(TransactionStatus.NOT_ACTIVE, status); + status = TransactionStatus.ACTIVE; + } + + @Override + public void commit() { + assertEquals(TransactionStatus.ACTIVE, status); + status = TransactionStatus.COMMITTED; + } + + @Override + public void rollback() { + status = TransactionStatus.ROLLED_BACK; + } + + @Override + public TransactionStatus getStatus() { + return status; + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestDisconnectHandler.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestDisconnectHandler.java new file mode 100644 index 0000000000..6704a5f6fa --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestDisconnectHandler.java @@ -0,0 +1,77 @@ +package org.hibernate.test.cache.infinispan.util; + +import org.infinispan.util.concurrent.ConcurrentHashSet; +import org.jgroups.Address; +import org.jgroups.Event; +import org.jgroups.protocols.FD_ALL; +import org.jgroups.protocols.FD_ALL2; +import org.jgroups.protocols.FD_HOST; +import org.jgroups.protocols.FD_SOCK; +import org.jgroups.protocols.pbcast.GMS; +import org.jgroups.stack.Protocol; + +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Works around some issues slowing down cluster shutdown in testsuite. + * + * @author Radim Vansa <rvansa@redhat.com> + */ +public class TestDisconnectHandler extends Protocol { + private static Set connected = new ConcurrentHashSet<>(); + private static Executor executor = Executors.newCachedThreadPool(new ThreadFactory() { + AtomicInteger counter = new AtomicInteger(); + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setName(TestDisconnectHandler.class.getSimpleName() + "-" + counter.incrementAndGet()); + return t; + } + }); + + private Address localAddress; + + @Override + public Object down(Event evt) { + switch (evt.getType()) { + case Event.SET_LOCAL_ADDRESS: + localAddress = (Address) evt.getArg(); + log.trace("Set address " + localAddress); + break; + case Event.CONNECT: + case Event.CONNECT_WITH_STATE_TRANSFER: + case Event.CONNECT_USE_FLUSH: + case Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH: + log.trace("Connecting on " + localAddress); + // we need to pass the message from below GMS (let's say regular FD* protocols + connected.add(getFD()); + break; + case Event.DISCONNECT: + log.trace("Disconnecting on " + localAddress); + connected.remove(getFD()); + // reduce view ack collection timeout to minimum, since we don't want to wait anymore + GMS gms = (GMS) getProtocolStack().findProtocol(GMS.class); + gms.setViewAckCollectionTimeout(1); + for (Protocol other : connected) { + executor.execute(() -> { + log.trace("Suspecting " + localAddress + " on " + other); + Event suspectEvent = new Event(Event.SUSPECT, localAddress); + other.up(suspectEvent); + other.down(suspectEvent); + }); + } + break; + } + return super.down(evt); + } + + private Protocol getFD() { + Protocol protocol = getProtocolStack().findProtocol(FD_ALL.class, FD_ALL2.class, FD_SOCK.class, FD_HOST.class); + log.trace("Found protocol " + protocol); + return protocol; + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestInfinispanRegionFactory.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestInfinispanRegionFactory.java new file mode 100644 index 0000000000..1084227f67 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestInfinispanRegionFactory.java @@ -0,0 +1,66 @@ +package org.hibernate.test.cache.infinispan.util; + +import org.hibernate.cache.infinispan.InfinispanRegionFactory; +import org.infinispan.commons.executors.CachedThreadPoolExecutorFactory; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.configuration.global.TransportConfigurationBuilder; +import org.infinispan.configuration.parsing.ConfigurationBuilderHolder; +import org.infinispan.manager.DefaultCacheManager; +import org.infinispan.manager.EmbeddedCacheManager; +import org.infinispan.remoting.transport.jgroups.JGroupsTransport; +import org.infinispan.test.fwk.TestResourceTracker; +import org.infinispan.transaction.TransactionMode; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Factory that should be overridden in tests. + * + * @author Radim Vansa <rvansa@redhat.com> + */ +public class TestInfinispanRegionFactory extends InfinispanRegionFactory { + private static AtomicInteger counter = new AtomicInteger(); + + @Override + protected EmbeddedCacheManager createCacheManager(ConfigurationBuilderHolder holder) { + amendConfiguration(holder); + return new DefaultCacheManager(holder, true); + } + + protected void amendConfiguration(ConfigurationBuilderHolder holder) { + holder.getGlobalConfigurationBuilder().globalJmxStatistics().allowDuplicateDomains(true); + TransportConfigurationBuilder transport = holder.getGlobalConfigurationBuilder().transport(); + transport.nodeName(TestResourceTracker.getNextNodeName()); + transport.clusterName(TestResourceTracker.getCurrentTestName()); + // minimize number of threads using unlimited cached thread pool + transport.remoteCommandThreadPool().threadPoolFactory(CachedThreadPoolExecutorFactory.create()); + transport.transportThreadPool().threadPoolFactory(CachedThreadPoolExecutorFactory.create()); + for (Map.Entry cfg : holder.getNamedConfigurationBuilders().entrySet()) { + amendCacheConfiguration(cfg.getKey(), cfg.getValue()); + } + } + + private String buildNodeName() { + StringBuilder sb = new StringBuilder("Node"); + int id = counter.getAndIncrement(); + int alphabet = 'Z' - 'A'; + do { + sb.append((char) (id % alphabet + 'A')); + id /= alphabet; + } while (id > alphabet); + return sb.toString(); + } + + protected void amendCacheConfiguration(String cacheName, ConfigurationBuilder configurationBuilder) { + } + + public static class Transactional extends TestInfinispanRegionFactory { + @Override + protected void amendCacheConfiguration(String cacheName, ConfigurationBuilder configurationBuilder) { + if (!cacheName.endsWith("query") && !cacheName.equals(DEF_TIMESTAMPS_RESOURCE)) { + configurationBuilder.transaction().transactionMode(TransactionMode.TRANSACTIONAL).useSynchronization(true); + } + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestSynchronization.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestSynchronization.java new file mode 100644 index 0000000000..e93c887730 --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TestSynchronization.java @@ -0,0 +1,74 @@ +package org.hibernate.test.cache.infinispan.util; + +import org.hibernate.cache.spi.access.EntityRegionAccessStrategy; +import org.hibernate.cache.spi.access.RegionAccessStrategy; +import org.hibernate.cache.spi.access.SoftLock; +import org.hibernate.engine.spi.SessionImplementor; + +import javax.transaction.Synchronization; + +/** + * @author Radim Vansa <rvansa@redhat.com> + */ +public abstract class TestSynchronization implements javax.transaction.Synchronization { + protected final SessionImplementor session; + protected final Object key; + protected final Object value; + + public TestSynchronization(SessionImplementor session, Object key, Object value) { + this.session = session; + this.key = key; + this.value = value; + } + + @Override + public void beforeCompletion() { + } + + + public static class AfterInsert extends TestSynchronization { + private final EntityRegionAccessStrategy strategy; + + public AfterInsert(EntityRegionAccessStrategy strategy, SessionImplementor session, Object key, Object value) { + super(session, key, value); + this.strategy = strategy; + } + + @Override + public void afterCompletion(int status) { + strategy.afterInsert(session, key, value, null); + } + } + + public static class AfterUpdate extends TestSynchronization { + private final EntityRegionAccessStrategy strategy; + private final SoftLock lock; + + public AfterUpdate(EntityRegionAccessStrategy strategy, SessionImplementor session, Object key, Object value, SoftLock lock) { + super(session, key, value); + this.strategy = strategy; + this.lock = lock; + } + + @Override + public void afterCompletion(int status) { + strategy.afterUpdate(session, key, value, null, null, lock); + } + } + + public static class UnlockItem extends TestSynchronization { + private final RegionAccessStrategy strategy; + private final SoftLock lock; + + public UnlockItem(RegionAccessStrategy strategy, SessionImplementor session, Object key, SoftLock lock) { + super(session, key, null); + this.strategy = strategy; + this.lock = lock; + } + + @Override + public void afterCompletion(int status) { + strategy.unlockItem(session, key, lock); + } + } +} diff --git a/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TxUtil.java b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TxUtil.java new file mode 100644 index 0000000000..f070e84cda --- /dev/null +++ b/hibernate-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/TxUtil.java @@ -0,0 +1,149 @@ +package org.hibernate.test.cache.infinispan.util; + +import org.hibernate.Session; +import org.hibernate.SessionBuilder; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.cache.infinispan.util.Caches; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; +import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl; +import org.hibernate.resource.transaction.spi.TransactionStatus; + +import javax.transaction.SystemException; +import javax.transaction.TransactionManager; + +import java.util.concurrent.Callable; + +/** + * @author Radim Vansa <rvansa@redhat.com> + */ +public final class TxUtil { + public static void withTxSession(boolean useJta, SessionFactory sessionFactory, ThrowingConsumer consumer) throws Exception { + JtaPlatform jtaPlatform = useJta ? sessionFactory.getSessionFactoryOptions().getServiceRegistry().getService(JtaPlatform.class) : null; + withTxSession(jtaPlatform, sessionFactory.withOptions(), consumer); + } + + public static void withTxSession(JtaPlatform jtaPlatform, SessionBuilder sessionBuilder, ThrowingConsumer consumer) throws Exception { + if (jtaPlatform != null) { + TransactionManager tm = jtaPlatform.retrieveTransactionManager(); + final SessionBuilder sb = sessionBuilder; + Caches.withinTx(tm, () -> { + withSession(sb, s -> { + consumer.accept(s); + // we need to flush the session before close when running with JTA transactions + s.flush(); + }); + return null; + }); + } else { + withSession(sessionBuilder, s -> withResourceLocalTx(s, consumer)); + } + } + + public static T withTxSessionApply(boolean useJta, SessionFactory sessionFactory, ThrowingFunction function) throws Exception { + JtaPlatform jtaPlatform = useJta ? sessionFactory.getSessionFactoryOptions().getServiceRegistry().getService(JtaPlatform.class) : null; + return withTxSessionApply(jtaPlatform, sessionFactory.withOptions(), function); + } + + public static T withTxSessionApply(JtaPlatform jtaPlatform, SessionBuilder sessionBuilder, ThrowingFunction function) throws Exception { + if (jtaPlatform != null) { + TransactionManager tm = jtaPlatform.retrieveTransactionManager(); + Callable callable = () -> withSessionApply(sessionBuilder, s -> { + T t = function.apply(s); + s.flush(); + return t; + }); + return Caches.withinTx(tm, callable); + } else { + return withSessionApply(sessionBuilder, s -> withResourceLocalTx(s, function)); + } + } + + public static void withSession(SessionBuilder sessionBuilder, ThrowingConsumer consumer) throws E { + Session s = sessionBuilder.openSession(); + try { + consumer.accept(s); + } finally { + s.close(); + } + } + + public static R withSessionApply(SessionBuilder sessionBuilder, ThrowingFunction function) throws E { + Session s = sessionBuilder.openSession(); + try { + return function.apply(s); + } finally { + s.close(); + } + } + + public static void withResourceLocalTx(Session session, ThrowingConsumer consumer) throws Exception { + Transaction transaction = session.beginTransaction(); + boolean rollingBack = false; + try { + consumer.accept(session); + if (transaction.getStatus() == TransactionStatus.ACTIVE) { + transaction.commit(); + } else { + rollingBack = true; + transaction.rollback(); + } + } catch (Exception e) { + if (!rollingBack) { + try { + transaction.rollback(); + } catch (Exception suppressed) { + e.addSuppressed(suppressed); + } + } + throw e; + } + } + + public static T withResourceLocalTx(Session session, ThrowingFunction consumer) throws Exception { + Transaction transaction = session.beginTransaction(); + boolean rollingBack = false; + try { + T t = consumer.apply(session); + if (transaction.getStatus() == TransactionStatus.ACTIVE) { + transaction.commit(); + } else { + rollingBack = true; + transaction.rollback(); + } + return t; + } catch (Exception e) { + if (!rollingBack) { + try { + transaction.rollback(); + } catch (Exception suppressed) { + e.addSuppressed(suppressed); + } + } + throw e; + } + } + + public static void markRollbackOnly(boolean useJta, Session s) { + if (useJta) { + JtaPlatform jtaPlatform = s.getSessionFactory().getSessionFactoryOptions().getServiceRegistry().getService(JtaPlatform.class); + TransactionManager tm = jtaPlatform.retrieveTransactionManager(); + try { + tm.setRollbackOnly(); + } catch (SystemException e) { + throw new RuntimeException(e); + } + } else { + s.getTransaction().markRollbackOnly(); + } + } + + public interface ThrowingConsumer { + void accept(T t) throws E; + } + + public interface ThrowingFunction { + R apply(T t) throws E; + } +} diff --git a/hibernate-infinispan/src/test/resources/2lc-test-tcp.xml b/hibernate-infinispan/src/test/resources/2lc-test-tcp.xml index 6065c9ea3d..a6e0055bfb 100644 --- a/hibernate-infinispan/src/test/resources/2lc-test-tcp.xml +++ b/hibernate-infinispan/src/test/resources/2lc-test-tcp.xml @@ -6,38 +6,29 @@ --> + xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/JGroups-3.6.xsd"> + oob_thread_pool.rejection_policy="Discard" + /> - - - + + + + - - - - - + + + + diff --git a/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/classloader/Account.hbm.xml b/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Account.hbm.xml similarity index 84% rename from hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/classloader/Account.hbm.xml rename to hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Account.hbm.xml index 17f649db84..0d8eb4d5a0 100755 --- a/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/classloader/Account.hbm.xml +++ b/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Account.hbm.xml @@ -9,13 +9,9 @@ "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - + - - - diff --git a/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Contact.hbm.xml b/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Contact.hbm.xml similarity index 91% rename from hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Contact.hbm.xml rename to hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Contact.hbm.xml index 24c911dc32..94e3259da5 100755 --- a/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Contact.hbm.xml +++ b/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Contact.hbm.xml @@ -10,7 +10,7 @@ "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> + package="org.hibernate.test.cache.infinispan.functional.entities"> diff --git a/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Customer.hbm.xml b/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Customer.hbm.xml similarity index 91% rename from hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Customer.hbm.xml rename to hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Customer.hbm.xml index ef43acffd8..a40231de22 100644 --- a/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Customer.hbm.xml +++ b/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Customer.hbm.xml @@ -10,7 +10,7 @@ "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> + package="org.hibernate.test.cache.infinispan.functional.entities"> diff --git a/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Item.hbm.xml b/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Item.hbm.xml similarity index 98% rename from hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Item.hbm.xml rename to hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Item.hbm.xml index a2d6cd2619..401dc3460e 100755 --- a/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Item.hbm.xml +++ b/hibernate-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/entities/Item.hbm.xml @@ -9,7 +9,7 @@ "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - +