HHH-9843 Use optimized cache key implementation in Infinispan 2LC

* When multi-tenancy is not used, entity's @Id can be used as key to the cache
* Added Type to CacheDataDescription (in SPI), later used for container key equivalence
* Introduced CacheKeysFactory to SPI
* Pending puts cache is now per region - this is necessary as we need to use custom key equivalence
This commit is contained in:
Radim Vansa 2015-07-02 09:40:41 +02:00 committed by Steve Ebersole
parent bcf38a02b5
commit 2f1b67b03f
36 changed files with 671 additions and 106 deletions

View File

@ -11,6 +11,7 @@ import java.util.Comparator;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.type.Type;
import org.hibernate.type.VersionType;
/**
@ -22,19 +23,21 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
private final boolean mutable;
private final boolean versioned;
private final Comparator versionComparator;
private final Type keyType;
/**
* Constructs a CacheDataDescriptionImpl instance. Generally speaking, code should use one of the
* overloaded {@link #decode} methods rather than direct instantiation.
*
* @param mutable Is the described data mutable?
* @param versioned Is the described data versioned?
* @param versionComparator The described data's version value comparator (if versioned).
* @param keyType
*/
public CacheDataDescriptionImpl(boolean mutable, boolean versioned, Comparator versionComparator) {
public CacheDataDescriptionImpl(boolean mutable, boolean versioned, Comparator versionComparator, Type keyType) {
this.mutable = mutable;
this.versioned = versioned;
this.versionComparator = versionComparator;
this.keyType = keyType;
}
@Override
@ -52,6 +55,11 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
return versionComparator;
}
@Override
public Type getKeyType() {
return keyType;
}
/**
* Builds a CacheDataDescriptionImpl from the mapping model of an entity class.
*
@ -65,8 +73,8 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
model.isVersioned(),
model.isVersioned()
? ( (VersionType) model.getVersion().getType() ).getComparator()
: null
);
: null,
model.getIdentifierProperty().getType());
}
/**
@ -82,8 +90,8 @@ public class CacheDataDescriptionImpl implements CacheDataDescription {
model.getOwner().isVersioned(),
model.getOwner().isVersioned()
? ( (VersionType) model.getOwner().getVersion().getType() ).getComparator()
: null
);
: null,
model.getKey().getType());
}
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.cache.internal;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.collection.CollectionPersister;
@ -48,7 +49,7 @@ public class DefaultCacheKeysFactory {
}
public static Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return new OldNaturalIdCacheKey( naturalIdValues, persister, session );
return new OldNaturalIdCacheKey( naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), persister.getRootEntityName(), session );
}
public static Object getEntityId(Object cacheKey) {
@ -62,4 +63,36 @@ public class DefaultCacheKeysFactory {
public static Object[] getNaturalIdValues(Object cacheKey) {
return ((OldNaturalIdCacheKey) cacheKey).getNaturalIdValues();
}
public static CacheKeysFactory INSTANCE = new CacheKeysFactory() {
@Override
public Object createCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createCollectionKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object createEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createEntityKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return DefaultCacheKeysFactory.createNaturalIdKey(naturalIdValues, persister, session);
}
@Override
public Object getEntityId(Object cacheKey) {
return DefaultCacheKeysFactory.getEntityId(cacheKey);
}
@Override
public Object getCollectionId(Object cacheKey) {
return DefaultCacheKeysFactory.getCollectionId(cacheKey);
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return DefaultCacheKeysFactory.getNaturalIdValues(cacheKey);
}
};
}

View File

@ -15,7 +15,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.ValueHolder;
import org.hibernate.internal.util.compare.EqualsHelper;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
@ -41,24 +40,22 @@ public class OldNaturalIdCacheKey implements Serializable {
/**
* Construct a new key for a caching natural identifier resolutions into the second level cache.
*
* @param naturalIdValues The naturalIdValues associated with the cached data
* @param persister The persister for the entity
* @param propertyTypes
* @param naturalIdPropertyIndexes
* @param session The originating session
*/
public OldNaturalIdCacheKey(
final Object[] naturalIdValues,
final EntityPersister persister,
Type[] propertyTypes, int[] naturalIdPropertyIndexes, final String entityName,
final SessionImplementor session) {
this.entityName = persister.getRootEntityName();
this.entityName = entityName;
this.tenantId = session.getTenantIdentifier();
this.naturalIdValues = new Serializable[naturalIdValues.length];
final SessionFactoryImplementor factory = session.getFactory();
final int[] naturalIdPropertyIndexes = persister.getNaturalIdentifierProperties();
final Type[] propertyTypes = persister.getPropertyTypes();
final int prime = 31;
int result = 1;
@ -93,7 +90,7 @@ public class OldNaturalIdCacheKey implements Serializable {
public String initialize() {
//Complex toString is needed as naturalIds for entities are not simply based on a single value like primary keys
//the only same way to differentiate the keys is to included the disassembled values in the string.
final StringBuilder toStringBuilder = new StringBuilder( entityName ).append( "##NaturalId[" );
final StringBuilder toStringBuilder = new StringBuilder().append( entityName ).append( "##NaturalId[" );
for ( int i = 0; i < naturalIdValues.length; i++ ) {
toStringBuilder.append( naturalIdValues[i] );
if ( i + 1 < naturalIdValues.length ) {

View File

@ -0,0 +1,54 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.internal;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
/**
* Factory that does not fill in the entityName or role
*
* @author Radim Vansa &lt;rvansa@redhat.com&gt;
*/
public class SimpleCacheKeysFactory implements CacheKeysFactory {
public static CacheKeysFactory INSTANCE = new SimpleCacheKeysFactory();
@Override
public Object createCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return id;
}
@Override
public Object createEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return id;
}
@Override
public Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
// natural ids always need to be wrapped
return new OldNaturalIdCacheKey(naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), null, session);
}
@Override
public Object getEntityId(Object cacheKey) {
return cacheKey;
}
@Override
public Object getCollectionId(Object cacheKey) {
return cacheKey;
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return ((OldNaturalIdCacheKey) cacheKey).getNaturalIdValues();
}
}

View File

@ -8,6 +8,8 @@ package org.hibernate.cache.spi;
import java.util.Comparator;
import org.hibernate.type.Type;
/**
* Describes attributes regarding the type of data to be cached.
*
@ -37,4 +39,10 @@ public interface CacheDataDescription {
* @return The comparator for versions, or {@code null}
*/
public Comparator getVersionComparator();
/**
* @return Type of the key that will be used as the key in the cache, or {@code null} if the natural comparison
* ({@link Object#hashCode()} and {@link Object#equals(Object)} methods should be used.
*/
Type getKeyType();
}

View File

@ -0,0 +1,29 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
/**
* @author Radim Vansa &lt;rvansa@redhat.com&gt;
*/
public interface CacheKeysFactory {
Object createCollectionKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier);
Object createEntityKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier);
Object createNaturalIdKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session);
Object getEntityId(Object cacheKey);
Object getCollectionId(Object cacheKey);
Object[] getNaturalIdValues(Object cacheKey);
}

View File

@ -62,7 +62,7 @@ public class NaturalIdCacheKeyTest {
});
final OldNaturalIdCacheKey key = (OldNaturalIdCacheKey) DefaultCacheKeysFactory.createNaturalIdKey( new Object[] {"a", "b", "c"}, entityPersister, sessionImplementor );
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(key);

View File

@ -20,6 +20,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.collection.CollectionRegionImpl;
@ -33,7 +34,10 @@ import org.hibernate.cache.infinispan.timestamp.TimestampsRegionImpl;
import org.hibernate.cache.infinispan.tm.HibernateTransactionManagerLookup;
import org.hibernate.cache.infinispan.util.CacheCommandFactory;
import org.hibernate.cache.infinispan.util.Caches;
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
import org.hibernate.cache.internal.SimpleCacheKeysFactory;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
@ -217,6 +221,7 @@ public class InfinispanRegionFactory implements RegionFactory {
private org.infinispan.transaction.lookup.TransactionManagerLookup transactionManagerlookup;
private List<String> regionNames = new ArrayList<String>();
private SessionFactoryOptions settings;
/**
* Create a new instance using the default configuration.
@ -241,8 +246,8 @@ public class InfinispanRegionFactory implements RegionFactory {
if ( log.isDebugEnabled() ) {
log.debug( "Building collection cache region [" + regionName + "]" );
}
final AdvancedCache cache = getCache( regionName, COLLECTION_KEY, properties );
final CollectionRegionImpl region = new CollectionRegionImpl( cache, regionName, metadata, this );
final AdvancedCache cache = getCache( regionName, COLLECTION_KEY, properties, metadata);
final CollectionRegionImpl region = new CollectionRegionImpl( cache, regionName, metadata, this, buildCacheKeysFactory() );
startRegion( region, regionName );
return region;
}
@ -258,8 +263,8 @@ public class InfinispanRegionFactory implements RegionFactory {
metadata.isVersioned()
);
}
final AdvancedCache cache = getCache( regionName, metadata.isMutable() ? ENTITY_KEY : IMMUTABLE_ENTITY_KEY, properties );
final EntityRegionImpl region = new EntityRegionImpl( cache, regionName, metadata, this );
final AdvancedCache cache = getCache( regionName, metadata.isMutable() ? ENTITY_KEY : IMMUTABLE_ENTITY_KEY, properties, metadata );
final EntityRegionImpl region = new EntityRegionImpl( cache, regionName, metadata, this, buildCacheKeysFactory() );
startRegion( region, regionName );
return region;
}
@ -268,10 +273,10 @@ public class InfinispanRegionFactory implements RegionFactory {
public NaturalIdRegion buildNaturalIdRegion(String regionName, Properties properties, CacheDataDescription metadata)
throws CacheException {
if ( log.isDebugEnabled() ) {
log.debug( "Building natural id cache region [" + regionName + "]" );
log.debug("Building natural id cache region [" + regionName + "]");
}
final AdvancedCache cache = getCache( regionName, NATURAL_ID_KEY, properties );
final NaturalIdRegionImpl region = new NaturalIdRegionImpl( cache, regionName, metadata, this );
final AdvancedCache cache = getCache( regionName, NATURAL_ID_KEY, properties, metadata);
final NaturalIdRegionImpl region = new NaturalIdRegionImpl( cache, regionName, metadata, this, buildCacheKeysFactory());
startRegion( region, regionName );
return region;
}
@ -288,7 +293,7 @@ public class InfinispanRegionFactory implements RegionFactory {
cacheName = regionName;
}
final AdvancedCache cache = getCache( cacheName, QUERY_KEY, properties );
final AdvancedCache cache = getCache( cacheName, QUERY_KEY, properties, null);
final QueryResultsRegionImpl region = new QueryResultsRegionImpl( cache, regionName, this );
startRegion( region, regionName );
return region;
@ -300,7 +305,7 @@ public class InfinispanRegionFactory implements RegionFactory {
if ( log.isDebugEnabled() ) {
log.debug( "Building timestamps cache region [" + regionName + "]" );
}
final AdvancedCache cache = getCache( regionName, TIMESTAMPS_KEY, properties );
final AdvancedCache cache = getCache( regionName, TIMESTAMPS_KEY, properties, null);
final TimestampsRegionImpl region = createTimestampsRegion( cache, regionName );
startRegion( region, regionName );
return region;
@ -308,7 +313,7 @@ public class InfinispanRegionFactory implements RegionFactory {
protected TimestampsRegionImpl createTimestampsRegion(
AdvancedCache cache, String regionName) {
if ( Caches.isClustered( cache ) ) {
if ( Caches.isClustered(cache) ) {
return new ClusteredTimestampsRegionImpl( cache, regionName, this );
}
else {
@ -316,6 +321,15 @@ public class InfinispanRegionFactory implements RegionFactory {
}
}
private CacheKeysFactory buildCacheKeysFactory() {
if (settings.getMultiTenancyStrategy() != MultiTenancyStrategy.NONE) {
return DefaultCacheKeysFactory.INSTANCE;
}
else {
return SimpleCacheKeysFactory.INSTANCE;
}
}
@Override
public boolean isMinimalPutsEnabledByDefault() {
return true;
@ -345,6 +359,7 @@ public class InfinispanRegionFactory implements RegionFactory {
try {
transactionManagerlookup = createTransactionManagerLookup( settings, properties );
manager = createCacheManager( properties, settings.getServiceRegistry() );
this.settings = settings;
initGenericDataTypeOverrides();
final Enumeration keys = properties.propertyNames();
while ( keys.hasMoreElements() ) {
@ -587,7 +602,7 @@ public class InfinispanRegionFactory implements RegionFactory {
}
}
private AdvancedCache getCache(String regionName, String typeKey, Properties properties) {
private AdvancedCache getCache(String regionName, String typeKey, Properties properties, CacheDataDescription metadata) {
TypeOverrides regionOverride = typeOverrides.get( regionName );
if ( !definedConfigurations.contains( regionName ) ) {
final String templateCacheName;
@ -621,6 +636,13 @@ public class InfinispanRegionFactory implements RegionFactory {
// Apply overrides
typeOverrides.get( typeKey ).applyTo( builder );
}
// with multi-tenancy the keys will be wrapped
if (settings.getMultiTenancyStrategy() == MultiTenancyStrategy.NONE) {
// the keys may not define hashCode/equals correctly (e.g. arrays)
if (metadata != null && metadata.getKeyType() != null) {
builder.dataContainer().keyEquivalence(new TypeEquivalance(metadata.getKeyType()));
}
}
// Configure transaction manager
configureTransactionManager( builder, templateCacheName, properties );
// Define configuration

View File

@ -0,0 +1,46 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.infinispan;
import org.hibernate.type.Type;
import org.infinispan.commons.equivalence.Equivalence;
/**
* @author Radim Vansa &lt;rvansa@redhat.com&gt;
*/
public class TypeEquivalance implements Equivalence<Object> {
private final Type type;
public TypeEquivalance(Type type) {
this.type = type;
}
@Override
public int hashCode(Object o) {
return type.getHashCode(o);
}
@Override
public boolean equals(Object x, Object y) {
return type.isEqual(x, y);
}
@Override
public String toString(Object o) {
return String.valueOf(o);
}
@Override
public boolean isComparable(Object o) {
return true; // cannot guess from the type
}
@Override
public int compare(Object x, Object y) {
return type.compare(x, y);
}
}

View File

@ -6,6 +6,9 @@
*/
package org.hibernate.cache.infinispan.access;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@ -15,14 +18,12 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
import org.infinispan.AdvancedCache;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.EmbeddedCacheManager;
/**
@ -130,27 +131,37 @@ public class PutFromLoadValidator {
public PutFromLoadValidator(
AdvancedCache cache,
long nakedPutInvalidationPeriod) {
this(
cache.getCacheManager(), cache.getTransactionManager(),
this(cache, cache.getCacheManager(), cache.getTransactionManager(),
nakedPutInvalidationPeriod
);
}
/**
* Creates a new put from load validator instance.
*
* @param cacheManager where to find a cache to store pending put information
* @param tm transaction manager
* @param nakedPutInvalidationPeriod Period (in ms) after a removal during which a call to
* {@link #acquirePutFromLoadLock(Object)} that hasn't been
* {@link #registerPendingPut(Object) pre-registered} (aka a "naked put")
* will return false.
*/
public PutFromLoadValidator(
*
* @param cache Cache instance on which to store pending put information.
* @param cacheManager where to find a cache to store pending put information
* @param tm transaction manager
* @param nakedPutInvalidationPeriod Period (in ms) after a removal during which a call to
* {@link #acquirePutFromLoadLock(Object)} that hasn't been
* {@link #registerPendingPut(Object) pre-registered} (aka a "naked put")
* will return false.
*/
public PutFromLoadValidator(AdvancedCache cache,
EmbeddedCacheManager cacheManager,
TransactionManager tm, long nakedPutInvalidationPeriod) {
this.pendingPuts = cacheManager
.getCache( InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME );
Configuration cacheConfiguration = cache.getCacheConfiguration();
Configuration pendingPutsConfiguration = cacheManager.getCacheConfiguration(InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME);
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
if (pendingPutsConfiguration != null) {
configurationBuilder.read(pendingPutsConfiguration);
}
configurationBuilder.dataContainer().keyEquivalence(cacheConfiguration.dataContainer().keyEquivalence());
String pendingPutsName = cache.getName() + "-" + InfinispanRegionFactory.PENDING_PUTS_CACHE_NAME;
cacheManager.defineConfiguration(pendingPutsName, configurationBuilder.build());
this.pendingPuts = cacheManager.getCache(pendingPutsName);
this.transactionManager = tm;
this.nakedPutInvalidationPeriod = nakedPutInvalidationPeriod;
}

View File

@ -10,11 +10,11 @@ import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.infinispan.AdvancedCache;
/**
@ -33,11 +33,12 @@ public class CollectionRegionImpl extends BaseTransactionalDataRegion implements
* @param name of collection type
* @param metadata for the collection type
* @param factory for the region
* @param cacheKeysFactory factory for cache keys
*/
public CollectionRegionImpl(
AdvancedCache cache, String name,
CacheDataDescription metadata, RegionFactory factory) {
super( cache, name, metadata, factory );
CacheDataDescription metadata, RegionFactory factory, CacheKeysFactory cacheKeysFactory) {
super( cache, name, metadata, factory, cacheKeysFactory );
}
@Override

View File

@ -8,7 +8,6 @@ package org.hibernate.cache.infinispan.collection;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate;
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;
@ -82,12 +81,12 @@ class TransactionalAccess implements CollectionRegionAccessStrategy {
@Override
public Object generateCacheKey(Object id, CollectionPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createCollectionKey(id, persister, factory, tenantIdentifier);
return region.getCacheKeysFactory().createCollectionKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getCollectionId(cacheKey);
return region.getCacheKeysFactory().getCollectionId(cacheKey);
}
}

View File

@ -10,6 +10,7 @@ import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
@ -33,11 +34,12 @@ public class EntityRegionImpl extends BaseTransactionalDataRegion implements Ent
* @param name of entity type
* @param metadata for the entity type
* @param factory for the region
* @param cacheKeysFactory factory for cache keys
*/
public EntityRegionImpl(
AdvancedCache cache, String name,
CacheDataDescription metadata, RegionFactory factory) {
super( cache, name, metadata, factory );
CacheDataDescription metadata, RegionFactory factory, CacheKeysFactory cacheKeysFactory) {
super( cache, name, metadata, factory, cacheKeysFactory);
}
@Override
@ -60,5 +62,4 @@ public class EntityRegionImpl extends BaseTransactionalDataRegion implements Ent
public PutFromLoadValidator getPutFromLoadValidator() {
return new PutFromLoadValidator( cache );
}
}

View File

@ -8,7 +8,6 @@ package org.hibernate.cache.infinispan.entity;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate;
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;
@ -100,11 +99,11 @@ class TransactionalAccess implements EntityRegionAccessStrategy {
@Override
public Object generateCacheKey(Object id, EntityPersister persister, SessionFactoryImplementor factory, String tenantIdentifier) {
return DefaultCacheKeysFactory.createEntityKey(id, persister, factory, tenantIdentifier);
return region.getCacheKeysFactory().createEntityKey(id, persister, factory, tenantIdentifier);
}
@Override
public Object getCacheKeyId(Object cacheKey) {
return DefaultCacheKeysFactory.getEntityId(cacheKey);
return region.getCacheKeysFactory().getEntityId(cacheKey);
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.cache.infinispan.impl;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TransactionalDataRegion;
@ -23,6 +24,7 @@ public abstract class BaseTransactionalDataRegion
extends BaseRegion implements TransactionalDataRegion {
private final CacheDataDescription metadata;
private final CacheKeysFactory cacheKeysFactory;
/**
* Base transactional region constructor
@ -31,12 +33,14 @@ public abstract class BaseTransactionalDataRegion
* @param name of the transactional region
* @param metadata for the transactional region
* @param factory for the transactional region
* @param cacheKeysFactory factory for cache keys
*/
public BaseTransactionalDataRegion(
AdvancedCache cache, String name,
CacheDataDescription metadata, RegionFactory factory) {
super( cache, name, factory );
CacheDataDescription metadata, RegionFactory factory, CacheKeysFactory cacheKeysFactory) {
super( cache, name, factory);
this.metadata = metadata;
this.cacheKeysFactory = cacheKeysFactory;
}
@Override
@ -44,4 +48,7 @@ public abstract class BaseTransactionalDataRegion
return metadata;
}
public CacheKeysFactory getCacheKeysFactory() {
return cacheKeysFactory;
}
}

View File

@ -10,11 +10,11 @@ import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.infinispan.AdvancedCache;
/**
@ -33,11 +33,12 @@ public class NaturalIdRegionImpl extends BaseTransactionalDataRegion
* @param name of natural id region
* @param metadata for the natural id region
* @param factory for the natural id region
* @param cacheKeysFactory factory for cache keys
*/
public NaturalIdRegionImpl(
AdvancedCache cache, String name,
CacheDataDescription metadata, RegionFactory factory) {
super( cache, name, metadata, factory );
CacheDataDescription metadata, RegionFactory factory, CacheKeysFactory cacheKeysFactory) {
super( cache, name, metadata, factory, cacheKeysFactory );
}
@Override

View File

@ -8,7 +8,6 @@ package org.hibernate.cache.infinispan.naturalid;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate;
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;
@ -108,11 +107,11 @@ class TransactionalAccess implements NaturalIdRegionAccessStrategy {
@Override
public Object generateCacheKey(Object[] naturalIdValues, EntityPersister persister, SessionImplementor session) {
return DefaultCacheKeysFactory.createNaturalIdKey( naturalIdValues, persister, session );
return region.getCacheKeysFactory().createNaturalIdKey(naturalIdValues, persister, session);
}
@Override
public Object[] getNaturalIdValues(Object cacheKey) {
return DefaultCacheKeysFactory.getNaturalIdValues(cacheKey);
return region.getCacheKeysFactory().getNaturalIdValues(cacheKey);
}
}

View File

@ -13,7 +13,6 @@ import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
import org.hibernate.cache.infinispan.util.Caches;
import org.hibernate.cache.spi.QueryResultsRegion;
import org.hibernate.cache.spi.RegionFactory;
import org.infinispan.AdvancedCache;
import org.infinispan.context.Flag;
@ -38,7 +37,7 @@ public class QueryResultsRegionImpl extends BaseTransactionalDataRegion implemen
* @param factory for the query region
*/
public QueryResultsRegionImpl(AdvancedCache cache, String name, RegionFactory factory) {
super( cache, name, null, factory );
super( cache, name, null, factory, null );
// If Infinispan is using INVALIDATION for query cache, we don't want to propagate changes.
// We use the Timestamps cache to manage invalidation
final boolean localOnly = Caches.isInvalidationCache( cache );

View File

@ -11,10 +11,12 @@ 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.internal.CacheDataDescriptionImpl;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TransactionalDataRegion;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.internal.util.compare.ComparableComparator;
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
import org.junit.Test;
@ -29,6 +31,8 @@ import static org.junit.Assert.assertTrue;
* @since 3.5
*/
public abstract class AbstractEntityCollectionRegionTestCase extends AbstractRegionImplTestCase {
protected static CacheDataDescription MUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(true, false, ComparableComparator.INSTANCE, null);
@Test
public void testSupportedAccessTypes() throws Exception {
supportedAccessTypeTest();

View File

@ -133,11 +133,11 @@ public abstract class AbstractGeneralDataRegionTestCase extends AbstractRegionIm
}
protected void regionEvict(GeneralDataRegion region) throws Exception {
region.evict(KEY);
region.evict(KEY);
}
protected void regionPut(GeneralDataRegion region) throws Exception {
region.put(KEY, VALUE1);
region.put(KEY, VALUE1);
}
protected abstract String getStandardRegionName(String regionPrefix);

View File

@ -32,7 +32,7 @@ public abstract class AbstractRegionImplTestCase extends AbstractNonFunctionalTe
protected abstract void removeFromRegion(Region region, Object key);
protected CacheDataDescription getCacheDataDescription() {
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE, null);
}
}

View File

@ -56,8 +56,8 @@ import static org.junit.Assert.fail;
* @since 3.5
*/
public class InfinispanRegionFactoryTestCase {
private static CacheDataDescription MUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(true, false, null);
private static CacheDataDescription IMMUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(false, false, 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);
@Test
public void testConfigurationProcessing() {

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.test.cache.infinispan.access;
import javax.transaction.TransactionManager;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
@ -15,20 +16,18 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import javax.transaction.TransactionManager;
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.infinispan.AdvancedCache;
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.Test;
import static org.infinispan.test.TestingUtil.withCacheManager;
import static org.junit.Assert.assertEquals;
@ -84,7 +83,7 @@ public class PutFromLoadValidatorUnitTestCase {
@Override
public void call() {
try {
PutFromLoadValidator testee = new PutFromLoadValidator(cm,
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm,
transactional ? tm : null,
PutFromLoadValidator.NAKED_PUT_INVALIDATION_PERIOD);
if (transactional) {
@ -119,7 +118,7 @@ public class PutFromLoadValidatorUnitTestCase {
TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
PutFromLoadValidator testee = new PutFromLoadValidator(cm,
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm,
transactional ? tm : null,
PutFromLoadValidator.NAKED_PUT_INVALIDATION_PERIOD);
try {
@ -166,7 +165,7 @@ public class PutFromLoadValidatorUnitTestCase {
TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
PutFromLoadValidator testee = new PutFromLoadValidator(cm,
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm,
transactional ? tm : null,
PutFromLoadValidator.NAKED_PUT_INVALIDATION_PERIOD);
if (removeRegion) {
@ -218,7 +217,7 @@ public class PutFromLoadValidatorUnitTestCase {
TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
PutFromLoadValidator testee = new PutFromLoadValidator(cm,
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm,
transactional ? tm : null,
PutFromLoadValidator.NAKED_PUT_INVALIDATION_PERIOD);
if (removeRegion) {
@ -272,7 +271,7 @@ public class PutFromLoadValidatorUnitTestCase {
TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
PutFromLoadValidator testee = new PutFromLoadValidator(cm,
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm,
transactional ? tm : null,
PutFromLoadValidator.NAKED_PUT_INVALIDATION_PERIOD);
try {
@ -325,7 +324,7 @@ public class PutFromLoadValidatorUnitTestCase {
TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
PutFromLoadValidator testee = new TestValidator(cm,
PutFromLoadValidator testee = new TestValidator(cm.getCache().getAdvancedCache(), cm,
transactional ? tm : null, 100);
if (removeRegion) {
testee.invalidateRegion();
@ -368,7 +367,7 @@ public class PutFromLoadValidatorUnitTestCase {
TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
final PutFromLoadValidator testee = new PutFromLoadValidator(cm,
final PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), cm,
transactional ? tm : null,
PutFromLoadValidator.NAKED_PUT_INVALIDATION_PERIOD);
@ -440,8 +439,8 @@ public class PutFromLoadValidatorUnitTestCase {
TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
final PutFromLoadValidator testee = new PutFromLoadValidator(
cm, null, PutFromLoadValidator.NAKED_PUT_INVALIDATION_PERIOD);
final PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(),
cm, null, PutFromLoadValidator.NAKED_PUT_INVALIDATION_PERIOD);
final CountDownLatch removeLatch = new CountDownLatch(1);
final CountDownLatch pferLatch = new CountDownLatch(1);
final AtomicReference<Object> cache = new AtomicReference<Object>("INITIAL");
@ -503,10 +502,10 @@ public class PutFromLoadValidatorUnitTestCase {
private static class TestValidator extends PutFromLoadValidator {
protected TestValidator(EmbeddedCacheManager cm,
protected TestValidator(AdvancedCache cache, EmbeddedCacheManager cm,
TransactionManager transactionManager,
long nakedPutInvalidationPeriod) {
super(cm, transactionManager, nakedPutInvalidationPeriod);
super(cache, cm, transactionManager, nakedPutInvalidationPeriod);
}
@Override

View File

@ -115,7 +115,7 @@ public abstract class AbstractCollectionRegionAccessStrategyTestCase extends Abs
}
protected CacheDataDescription getCacheDataDescription() {
return new CacheDataDescriptionImpl( true, true, ComparableComparator.INSTANCE );
return new CacheDataDescriptionImpl( true, true, ComparableComparator.INSTANCE, null);
}
@After
@ -152,7 +152,7 @@ public abstract class AbstractCollectionRegionAccessStrategyTestCase extends Abs
withCacheManager(new CacheManagerCallable(TestCacheManagerFactory.createCacheManager(false)) {
@Override
public void call() {
PutFromLoadValidator validator = new PutFromLoadValidator(cm,
PutFromLoadValidator validator = new PutFromLoadValidator(remoteCollectionRegion.getCache(), cm,
remoteTm, 20000) {
@Override
public boolean acquirePutFromLoadLock(Object key) {

View File

@ -10,7 +10,6 @@ import java.util.Properties;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
import org.hibernate.cache.internal.CacheDataDescriptionImpl;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.Region;
@ -29,9 +28,6 @@ import static org.junit.Assert.fail;
* @author Galder Zamarreño
*/
public class CollectionRegionImplTestCase extends AbstractEntityCollectionRegionTestCase {
private static CacheDataDescription MUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(true, false, null);
@Override
protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) {
CollectionRegion region = regionFactory.buildCollectionRegion("test", properties, MUTABLE_NON_VERSIONED);

View File

@ -8,9 +8,12 @@ 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.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;
@ -31,8 +34,8 @@ public class TransactionalExtraAPITestCase extends AbstractNonFunctionalTestCase
public static final String REGION_NAME = "test/com.foo.test";
public static final Object KEY = TestingKeyFactory.generateCollectionCacheKey( "KEY" );
public static final String VALUE1 = "VALUE1";
public static final String VALUE2 = "VALUE2";
public static final CacheDataDescription CACHE_DATA_DESCRIPTION
= new CacheDataDescriptionImpl(false, false, ComparableComparator.INSTANCE, null);
private NodeEnvironment environment;
private static CollectionRegionAccessStrategy accessStrategy;
@ -45,7 +48,7 @@ public class TransactionalExtraAPITestCase extends AbstractNonFunctionalTestCase
// Sleep a bit to avoid concurrent FLUSH problem
avoidConcurrentFlush();
accessStrategy = environment.getCollectionRegion( REGION_NAME, null ).buildAccessStrategy( getAccessType() );
accessStrategy = environment.getCollectionRegion( REGION_NAME, CACHE_DATA_DESCRIPTION).buildAccessStrategy( getAccessType() );
}
protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() {

View File

@ -115,7 +115,7 @@ public abstract class AbstractEntityRegionAccessStrategyTestCase extends Abstrac
}
protected CacheDataDescription getCacheDataDescription() {
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE, null);
}
@After

View File

@ -10,7 +10,6 @@ import java.util.Properties;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
import org.hibernate.cache.internal.CacheDataDescriptionImpl;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.Region;
@ -30,8 +29,6 @@ import static org.junit.Assert.fail;
*/
public class EntityRegionImplTestCase extends AbstractEntityCollectionRegionTestCase {
private static CacheDataDescription MUTABLE_NON_VERSIONED = new CacheDataDescriptionImpl(true, false, null);
@Override
protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) {
EntityRegion region = regionFactory.buildEntityRegion("test", properties, MUTABLE_NON_VERSIONED);

View File

@ -12,6 +12,7 @@ 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.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;
@ -38,6 +39,8 @@ public class TransactionalExtraAPITestCase extends AbstractNonFunctionalTestCase
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 NodeEnvironment environment;
private EntityRegionAccessStrategy accessStrategy;
@ -50,7 +53,7 @@ public class TransactionalExtraAPITestCase extends AbstractNonFunctionalTestCase
// Sleep a bit to avoid concurrent FLUSH problem
avoidConcurrentFlush();
accessStrategy = environment.getEntityRegion( REGION_NAME, new CacheDataDescriptionImpl(true, false, null)).buildAccessStrategy( getAccessType() );
accessStrategy = environment.getEntityRegion( REGION_NAME, CACHE_DATA_DESCRIPTION).buildAccessStrategy( getAccessType() );
}
protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() {

View File

@ -0,0 +1,77 @@
package org.hibernate.test.cache.infinispan.functional;
import java.util.concurrent.Callable;
import org.hibernate.Session;
import org.hibernate.stat.Statistics;
import org.junit.Test;
import static org.infinispan.test.TestingUtil.withTx;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Persons should be correctly indexed since we can use Type for comparison
*
* @author Radim Vansa &lt;rvansa@redhat.com&gt;
*/
public class EqualityTest extends SingleNodeTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { Person.class };
}
@Test
public void testEqualityFromType() throws Exception {
Person john = new Person("John", "Black", 26);
Person peter = new Person("Peter", "White", 32);
withTx(tm, new Callable<Void>() {
@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;
}
});
Statistics statistics = sessionFactory().getStatistics();
statistics.clear();
for (int i = 0; i < 5; ++i) {
withTx(tm, new Callable<Void>() {
@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;
}
});
}
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());
}
}

View File

@ -0,0 +1,118 @@
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.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.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 &lt;rvansa@redhat.com&gt;
*/
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<Long>() {
@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<Void>() {
@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<Void>() {
// @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());
CloseableIteratorSet keySet = region.getCache().withFlags(Flag.CACHE_MODE_LOCAL).keySet();
assertEquals(1, keySet.size());
assertEquals("OldCacheKeyImplementation", keySet.iterator().next().getClass().getSimpleName());
}
}

View File

@ -0,0 +1,48 @@
package org.hibernate.test.cache.infinispan.functional;
import javax.persistence.Embeddable;
import java.io.Serializable;
/**
* Test class with incorrectly defined equals and hashCode.
*
* @author Radim Vansa &lt;rvansa@redhat.com&gt;
*/
@Embeddable
public class Name implements Serializable {
String firstName;
String lastName;
public Name() {}
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object obj) {
return false;
}
}

View File

@ -0,0 +1,56 @@
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.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 &lt;rvansa@redhat.com&gt;
*/
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<Long>() {
@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<Void>() {
@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());
CloseableIteratorSet keySet = region.getCache().withFlags(Flag.CACHE_MODE_LOCAL).keySet();
assertEquals(1, keySet.size());
assertEquals(sessionFactory().getClassMetadata(Item.class).getIdentifierType().getReturnedClass(), keySet.iterator().next().getClass());
}
}

View File

@ -0,0 +1,41 @@
package org.hibernate.test.cache.infinispan.functional;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import java.io.Serializable;
/**
* Test class using EmbeddedId
*
* @author Radim Vansa &lt;rvansa@redhat.com&gt;
*/
@Entity
public class Person implements Serializable {
@EmbeddedId
Name name;
int age;
public Person() {}
public Person(String firstName, String lastName, int age) {
name = new Name(firstName, lastName);
this.age = age;
}
public Name getName() {
return name;
}
public void setName(Name name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

View File

@ -343,7 +343,7 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase {
public void nodeVisited(CacheEntryVisitedEvent event) {
log.debug( event.toString() );
if ( !event.isPre() ) {
String key = String.valueOf(event.getKey());
String key = event.getCache().getName() + "#" + event.getKey();
log.debug( "MyListener[" + name + "] - Visiting key " + key );
// String name = fqn.toString();
String token = ".functional.";
@ -351,7 +351,7 @@ public class EntityCollectionInvalidationTestCase extends DualNodeTestCase {
if ( index > -1 ) {
index += token.length();
key = key.substring( index );
log.debug( "MyListener[" + name + "] - recording visit to " + key );
log.debug( "MyListener[" + this.name + "] - recording visit to " + key );
visited.add( key );
}
}

View File

@ -23,10 +23,19 @@ import org.hibernate.testing.env.ConnectionProviderBuilder;
* @since 3.5
*/
public class XaConnectionProvider implements ConnectionProvider {
private static ConnectionProvider actualConnectionProvider = ConnectionProviderBuilder.buildConnectionProvider();
private final static ConnectionProvider DEFAULT_CONNECTION_PROVIDER = ConnectionProviderBuilder.buildConnectionProvider();
private final ConnectionProvider actualConnectionProvider;
private boolean isTransactional;
public static ConnectionProvider getActualConnectionProvider() {
public XaConnectionProvider() {
this(DEFAULT_CONNECTION_PROVIDER);
}
public XaConnectionProvider(ConnectionProvider connectionProvider) {
this.actualConnectionProvider = connectionProvider;
}
public ConnectionProvider getActualConnectionProvider() {
return actualConnectionProvider;
}