HHH-6974 Class level naturalId cache and stats

Add class level @NaturalIdCache annotation to denote if second level natualId caching should be done
Flush out stats model for naturalId cache related stats
Add ehcache support classes for naturalId region
This commit is contained in:
Eric Dalquist 2012-01-27 16:46:25 -06:00 committed by Steve Ebersole
parent 72fe79a3f2
commit c473520585
36 changed files with 1539 additions and 67 deletions

View File

@ -23,17 +23,18 @@
*/
package org.hibernate.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* This specifies that a property is part of the natural id of the entity.
*
* @author Nicol<EFBFBD>s Lichtmaier
* @see NaturalIdCache
*/
@Target( { METHOD, FIELD } )
@Retention( RUNTIME )
@ -44,11 +45,4 @@ public @interface NaturalId {
* @return {@code true} indicates the natural id is mutable; {@code false} (the default) that it is immutable.
*/
boolean mutable() default false;
/**
* Should the mapping of this natural id to the primary id be cached
*
* @return {@code true} (the default) indicates the natural id mapping should be cached; {@code false} that the mapping should not be cached.
*/
boolean cache() default true;
}

View File

@ -0,0 +1,44 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Add caching strategy for the NaturalId to Id of a root entity that has a natural id
*
* @author Eric Dalquist
* @see NaturalId
*/
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface NaturalIdCache {
/** cache region name, defaults to full.entity.Name##NaturalId */
String region() default "";
}

View File

@ -0,0 +1,47 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.spi;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
/**
* Defines the contract for a cache region which will specifically be used to
* store naturalId data.
*
* @author Eric Dalquist
*/
public interface NaturalIdRegion extends TransactionalDataRegion {
/**
* Build an access strategy for the requested access type.
*
* @param accessType The type of access strategy to build; never null.
* @return The appropriate strategy contract for accessing this region
* for the requested type of access.
* @throws org.hibernate.cache.CacheException Usually indicates mis-configuration.
*/
public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException;
}

View File

@ -0,0 +1,50 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.spi.access;
import org.hibernate.cache.spi.NaturalIdRegion;
/**
* Contract for managing transactional and concurrent access to cached naturalId
* data. For cached naturalId data, all modification actions actually just
* invalidate the entry(s). The call sequence here is:
* {@link #lockItem} -> {@link #remove} -> {@link #unlockItem}
* <p/>
* There is another usage pattern that is used to invalidate entries
* after performing "bulk" HQL/SQL operations:
* {@link #lockRegion} -> {@link #removeAll} -> {@link #unlockRegion}
*
* @author Gavin King
* @author Steve Ebersole
* @author Eric Dalquist
*/
public interface NaturalIdRegionAccessStrategy extends RegionAccessStrategy{
/**
* Get the wrapped naturalId cache region
*
* @return The underlying region
*/
public NaturalIdRegion getRegion();
}

View File

@ -34,6 +34,7 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.CollectionTable;
@ -79,8 +80,6 @@ import javax.persistence.TableGenerator;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
@ -112,6 +111,7 @@ import org.hibernate.annotations.LazyToOneOption;
import org.hibernate.annotations.ManyToAny;
import org.hibernate.annotations.MapKeyType;
import org.hibernate.annotations.NaturalId;
import org.hibernate.annotations.NaturalIdCache;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.OnDelete;
@ -167,6 +167,7 @@ import org.hibernate.mapping.SingleTableSubclass;
import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.UnionSubclass;
import org.jboss.logging.Logger;
/**
* JSR 175 annotation binder which reads the annotations from classes, applies the
@ -574,6 +575,7 @@ public final class AnnotationBinder {
entityBinder.setBatchSize( clazzToProcess.getAnnotation( BatchSize.class ) );
entityBinder.setWhere( clazzToProcess.getAnnotation( Where.class ) );
entityBinder.setCache( determineCacheSettings( clazzToProcess, mappings ) );
entityBinder.setNaturalIdCache( clazzToProcess.getAnnotation( NaturalIdCache.class ) );
//Filters are not allowed on subclasses
if ( !inheritanceState.hasParents() ) {

View File

@ -27,6 +27,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.persistence.Access;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
@ -35,8 +36,6 @@ import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
@ -47,6 +46,7 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Loader;
import org.hibernate.annotations.NaturalIdCache;
import org.hibernate.annotations.OptimisticLockType;
import org.hibernate.annotations.Persister;
import org.hibernate.annotations.PolymorphismType;
@ -89,6 +89,7 @@ import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.TableOwner;
import org.hibernate.mapping.Value;
import org.jboss.logging.Logger;
/**
* Stateful holder and processor for binding Entity information
@ -97,7 +98,8 @@ import org.hibernate.mapping.Value;
*/
public class EntityBinder {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, EntityBinder.class.getName());
private static final String NATURAL_ID_CACHE_SUFFIX = "##NaturalId";
private String name;
private XClass annotatedClass;
private PersistentClass persistentClass;
@ -119,6 +121,7 @@ public class EntityBinder {
private java.util.Map<String, Object> secondaryTableJoins = new HashMap<String, Object>();
private String cacheConcurrentStrategy;
private String cacheRegion;
private String naturalIdCacheRegion;
private java.util.Map<String, String> filters = new HashMap<String, String>();
private InheritanceState inheritanceState;
private boolean ignoreIdAnnotations;
@ -230,6 +233,7 @@ public class EntityBinder {
rootClass.setCacheRegionName( cacheRegion );
rootClass.setLazyPropertiesCacheable( cacheLazyProperty );
}
rootClass.setNaturalIdCacheRegionName( naturalIdCacheRegion );
boolean forceDiscriminatorInSelects = forceDiscriminator == null
? mappings.forceDiscriminatorInSelectsByDefault()
: forceDiscriminator;
@ -826,6 +830,25 @@ public class EntityBinder {
cacheLazyProperty = true;
}
}
public void setNaturalIdCache(NaturalIdCache naturalIdCacheAnn) {
if ( naturalIdCacheAnn != null ) {
if ( BinderHelper.isEmptyAnnotationValue( naturalIdCacheAnn.region() ) ) {
if (cacheRegion != null) {
naturalIdCacheRegion = cacheRegion + NATURAL_ID_CACHE_SUFFIX;
}
else {
naturalIdCacheRegion = persistentClass.getEntityName() + NATURAL_ID_CACHE_SUFFIX;
}
}
else {
naturalIdCacheRegion = naturalIdCacheAnn.region();
}
}
else {
naturalIdCacheRegion = null;
}
}
public static String getCacheConcurrencyStrategy(CacheConcurrencyStrategy strategy) {
org.hibernate.cache.spi.access.AccessType accessType = strategy.toAccessType();

View File

@ -182,6 +182,14 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
* @return The region
*/
public Region getSecondLevelCacheRegion(String regionName);
/**
* Get a named naturalId cache region
*
* @param regionName The name of the region to retrieve.
* @return The region
*/
public Region getNaturalIdCacheRegion(String regionName);
/**
* Get a map of all the second level cache regions currently maintained in

View File

@ -39,11 +39,10 @@ import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import org.jboss.logging.Logger;
import org.hibernate.AssertionFailure;
import org.hibernate.Cache;
import org.hibernate.ConnectionReleaseMode;
@ -145,6 +144,7 @@ import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver;
import org.jboss.logging.Logger;
/**
@ -173,7 +173,6 @@ import org.hibernate.type.TypeResolver;
public final class SessionFactoryImpl
implements SessionFactoryImplementor {
private static final String NATURAL_ID_CACHE_SUFFIX = "##NaturalId";
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, SessionFactoryImpl.class.getName());
private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator();
@ -360,8 +359,8 @@ public final class SessionFactoryImpl
entityPersisters.put( model.getEntityName(), cp );
classMeta.put( model.getEntityName(), cp.getClassMetadata() );
if ( cp.hasNaturalIdentifier() && cp.isNatrualIdentifierCached() ) {
final String naturalIdCacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName() + NATURAL_ID_CACHE_SUFFIX;
if ( cp.hasNaturalIdentifier() && model.getNaturalIdCacheRegionName() != null ) {
final String naturalIdCacheRegionName = cacheRegionPrefix + model.getNaturalIdCacheRegionName();
NaturalIdRegionAccessStrategy naturalIdAccessStrategy = ( NaturalIdRegionAccessStrategy ) entityAccessStrategies.get( naturalIdCacheRegionName );
if ( naturalIdAccessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
@ -805,14 +804,6 @@ public final class SessionFactoryImpl
);
entityPersisters.put( model.getEntity().getName(), cp );
classMeta.put( model.getEntity().getName(), cp.getClassMetadata() );
if ( settings.isSecondLevelCacheEnabled() && cp.hasNaturalIdentifier() && cp.isNatrualIdentifierCached() ) {
final String naturalIdCacheRegionName = cacheRegionPrefix + rootEntityBinding.getHierarchyDetails().getCaching().getRegion() + NATURAL_ID_CACHE_SUFFIX;
final NaturalIdRegion naturalIdRegion = settings.getRegionFactory().buildNaturalIdRegion( naturalIdCacheRegionName, properties, CacheDataDescriptionImpl.decode( cp ) );
final NaturalIdRegionAccessStrategy naturalIdAccessStrategy = naturalIdRegion.buildAccessStrategy( settings.getRegionFactory().getDefaultAccessType() );
entityAccessStrategies.put( naturalIdCacheRegionName, naturalIdAccessStrategy );
allCacheRegions.put( naturalIdCacheRegionName, naturalIdRegion );
}
}
this.classMetadata = Collections.unmodifiableMap(classMeta);
@ -1643,6 +1634,10 @@ public final class SessionFactoryImpl
return allCacheRegions.get( regionName );
}
public Region getNaturalIdCacheRegion(String regionName) {
return allCacheRegions.get( regionName );
}
@SuppressWarnings( {"unchecked"})
public Map getAllSecondLevelCacheRegions() {
return new HashMap( allCacheRegions );

View File

@ -12,6 +12,7 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.SessionFactoryRegistry;
import org.hibernate.stat.CollectionStatistics;
import org.hibernate.stat.EntityStatistics;
import org.hibernate.stat.NaturalIdCacheStatistics;
import org.hibernate.stat.QueryStatistics;
import org.hibernate.stat.SecondLevelCacheStatistics;
import org.hibernate.stat.Statistics;
@ -227,6 +228,23 @@ public class StatisticsService implements StatisticsServiceMBean {
public long getSecondLevelCachePutCount() {
return stats.getSecondLevelCachePutCount();
}
public NaturalIdCacheStatistics getNaturalIdCacheStatistics(String regionName) {
return stats.getNaturalIdCacheStatistics( regionName );
}
public long getNaturalIdCacheHitCount() {
return stats.getNaturalIdCacheHitCount();
}
public long getNaturalIdCacheMissCount() {
return stats.getNaturalIdCacheMissCount();
}
public long getNaturalIdCachePutCount() {
return stats.getNaturalIdCachePutCount();
}
/**
* @see StatisticsServiceMBean#getSessionCloseCount()
*/

View File

@ -248,6 +248,7 @@ public abstract class PersistentClass implements Serializable, Filterable, MetaA
public abstract boolean isInherited();
public abstract boolean isPolymorphic();
public abstract boolean isVersioned();
public abstract String getNaturalIdCacheRegionName();
public abstract String getCacheConcurrencyStrategy();
public abstract PersistentClass getSuperclass();
public abstract boolean isExplicitPolymorphism();

View File

@ -32,6 +32,7 @@ import org.jboss.logging.Logger;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.SingletonIterator;
@ -52,6 +53,7 @@ public class RootClass extends PersistentClass implements TableOwner {
private boolean polymorphic;
private String cacheConcurrencyStrategy;
private String cacheRegionName;
private String naturalIdCacheRegionName;
private boolean lazyPropertiesCacheable = true;
private Value discriminator; //may be final
private boolean mutable = true;
@ -307,7 +309,15 @@ public class RootClass extends PersistentClass implements TableOwner {
public void setCacheRegionName(String cacheRegionName) {
this.cacheRegionName = cacheRegionName;
}
@Override
public String getNaturalIdCacheRegionName() {
return naturalIdCacheRegionName;
}
public void setNaturalIdCacheRegionName(String naturalIdCacheRegionName) {
this.naturalIdCacheRegionName = naturalIdCacheRegionName;
}
@Override
public boolean isLazyPropertiesCacheable() {
return lazyPropertiesCacheable;

View File

@ -55,6 +55,11 @@ public class Subclass extends PersistentClass {
return subclassId;
}
@Override
public String getNaturalIdCacheRegionName() {
return getSuperclass().getNaturalIdCacheRegionName();
}
public String getCacheConcurrencyStrategy() {
return getSuperclass().getCacheConcurrencyStrategy();
}

View File

@ -37,8 +37,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
@ -122,6 +120,7 @@ import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeHelper;
import org.hibernate.type.VersionType;
import org.jboss.logging.Logger;
/**
* Basic functionality for persisting an entity via JDBC
@ -4601,11 +4600,6 @@ public abstract class AbstractEntityPersister
public boolean hasNaturalIdentifier() {
return entityMetamodel.hasNaturalIdentifier();
}
@Override
public boolean isNatrualIdentifierCached() {
return entityMetamodel.isNatrualIdentifierCached();
}
public void setPropertyValue(Object object, String propertyName, Object value) {
getEntityTuplizer().setPropertyValue( object, propertyName, value );

View File

@ -289,13 +289,6 @@ public interface EntityPersister extends OptimisticCacheSource {
* @return True if the entity defines a natural id; false otherwise.
*/
public boolean hasNaturalIdentifier();
/**
* Determine whether this entity's natural identifier is cacheable. {@link NaturalId#cache()}
*
* @return True if the natural id is cacheable, false if it is not cacheable or no natural id is defined
*/
public boolean isNatrualIdentifierCached();
/**
* If the entity defines a natural id ({@link #hasNaturalIdentifier()}), which

View File

@ -0,0 +1,50 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.stat;
import java.io.Serializable;
import java.util.Map;
/**
* NaturalId query statistics
* <p/>
* Note that for a cached natural id, the cache miss is equals to the db count
*
* @author Eric Dalquist
*/
public interface NaturalIdCacheStatistics extends Serializable {
long getHitCount();
long getMissCount();
long getPutCount();
long getElementCountInMemory();
long getElementCountOnDisk();
long getSizeInMemory();
Map getEntries();
}

View File

@ -59,6 +59,14 @@ public interface Statistics {
*/
public SecondLevelCacheStatistics getSecondLevelCacheStatistics(String regionName);
/**
* Natural id cache statistics per region
*
* @param regionName region name
* @return NaturalIdCacheStatistics
*/
public NaturalIdCacheStatistics getNaturalIdCacheStatistics(String regionName);
/**
* Query statistics from query string (HQL or SQL)
*
@ -123,6 +131,18 @@ public interface Statistics {
* Get the global number of cacheable queries put in cache
*/
public long getQueryCachePutCount();
/**
* Get the global number of cached naturalId lookups successfully retrieved from cache
*/
public long getNaturalIdCacheHitCount();
/**
* Get the global number of cached naturalId lookups *not* found in cache
*/
public long getNaturalIdCacheMissCount();
/**
* Get the global number of cacheable naturalId lookups put in cache
*/
public long getNaturalIdCachePutCount();
/**
* Get the global number of timestamps successfully retrieved from cache
*/

View File

@ -0,0 +1,112 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.stat.internal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.hibernate.cache.spi.CacheKey;
import org.hibernate.cache.spi.Region;
import org.hibernate.stat.NaturalIdCacheStatistics;
/**
* Second level cache statistics of a specific region
*
* @author Alex Snaps
*/
public class ConcurrentNaturalIdCacheStatisticsImpl extends CategorizedStatistics implements NaturalIdCacheStatistics {
private final transient Region region;
private AtomicLong hitCount = new AtomicLong();
private AtomicLong missCount = new AtomicLong();
private AtomicLong putCount = new AtomicLong();
ConcurrentNaturalIdCacheStatisticsImpl(Region region) {
super( region.getName() );
this.region = region;
}
public long getHitCount() {
return hitCount.get();
}
public long getMissCount() {
return missCount.get();
}
public long getPutCount() {
return putCount.get();
}
public long getElementCountInMemory() {
return region.getElementCountInMemory();
}
public long getElementCountOnDisk() {
return region.getElementCountOnDisk();
}
public long getSizeInMemory() {
return region.getSizeInMemory();
}
public Map getEntries() {
Map map = new HashMap();
Iterator iter = region.toMap().entrySet().iterator();
while (iter.hasNext()) {
Map.Entry me = (Map.Entry) iter.next();
map.put(((CacheKey) me.getKey()).getKey(), me.getValue());
}
return map;
}
public String toString() {
StringBuilder buf = new StringBuilder()
.append("NaturalIdCacheStatistics")
.append("[hitCount=").append(this.hitCount)
.append(",missCount=").append(this.missCount)
.append(",putCount=").append(this.putCount);
//not sure if this would ever be null but wanted to be careful
if (region != null) {
buf.append(",elementCountInMemory=").append(this.getElementCountInMemory())
.append(",elementCountOnDisk=").append(this.getElementCountOnDisk())
.append(",sizeInMemory=").append(this.getSizeInMemory());
}
buf.append(']');
return buf.toString();
}
void incrementHitCount() {
hitCount.getAndIncrement();
}
void incrementMissCount() {
missCount.getAndIncrement();
}
void incrementPutCount() {
putCount.getAndIncrement();
}
}

View File

@ -27,8 +27,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import org.jboss.logging.Logger;
import org.hibernate.cache.spi.Region;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreMessageLogger;
@ -36,9 +34,11 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.service.Service;
import org.hibernate.stat.CollectionStatistics;
import org.hibernate.stat.EntityStatistics;
import org.hibernate.stat.NaturalIdCacheStatistics;
import org.hibernate.stat.QueryStatistics;
import org.hibernate.stat.SecondLevelCacheStatistics;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.jboss.logging.Logger;
/**
* Implementation of {@link org.hibernate.stat.Statistics} based on the {@link java.util.concurrent} package.
@ -76,6 +76,10 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service
private AtomicLong secondLevelCacheHitCount = new AtomicLong();
private AtomicLong secondLevelCacheMissCount = new AtomicLong();
private AtomicLong secondLevelCachePutCount = new AtomicLong();
private AtomicLong naturalIdCacheHitCount = new AtomicLong();
private AtomicLong naturalIdCacheMissCount = new AtomicLong();
private AtomicLong naturalIdCachePutCount = new AtomicLong();
private AtomicLong queryExecutionCount = new AtomicLong();
private AtomicLong queryExecutionMaxTime = new AtomicLong();
@ -93,6 +97,10 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service
private AtomicLong optimisticFailureCount = new AtomicLong();
/**
* natural id cache statistics per region
*/
private final ConcurrentMap naturalIdCacheStatistics = new ConcurrentHashMap();
/**
* second level cache statistics per region
*/
@ -127,6 +135,10 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service
secondLevelCacheHitCount.set( 0 );
secondLevelCacheMissCount.set( 0 );
secondLevelCachePutCount.set( 0 );
naturalIdCacheHitCount.set( 0 );
naturalIdCacheMissCount.set( 0 );
naturalIdCachePutCount.set( 0 );
sessionCloseCount.set( 0 );
sessionOpenCount.set( 0 );
@ -282,6 +294,31 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service
collectionRemoveCount.getAndIncrement();
( (ConcurrentCollectionStatisticsImpl) getCollectionStatistics( role ) ).incrementRemoveCount();
}
@Override
public NaturalIdCacheStatistics getNaturalIdCacheStatistics(String regionName) {
ConcurrentNaturalIdCacheStatisticsImpl nics =
(ConcurrentNaturalIdCacheStatisticsImpl) naturalIdCacheStatistics.get( regionName );
if ( nics == null ) {
if ( sessionFactory == null ) {
return null;
}
Region region = sessionFactory.getNaturalIdCacheRegion( regionName );
if ( region == null ) {
return null;
}
nics = new ConcurrentNaturalIdCacheStatisticsImpl( region );
ConcurrentNaturalIdCacheStatisticsImpl previous;
if ( ( previous = (ConcurrentNaturalIdCacheStatisticsImpl) naturalIdCacheStatistics.putIfAbsent(
regionName, nics
) ) != null ) {
nics = previous;
}
}
return nics;
}
/**
* Second level cache statistics per region
@ -326,6 +363,24 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service
secondLevelCacheMissCount.getAndIncrement();
( (ConcurrentSecondLevelCacheStatisticsImpl) getSecondLevelCacheStatistics( regionName ) ).incrementMissCount();
}
@Override
public void naturalIdCachePut(String regionName) {
naturalIdCachePutCount.getAndIncrement();
( (ConcurrentNaturalIdCacheStatisticsImpl) getNaturalIdCacheStatistics( regionName ) ).incrementPutCount();
}
@Override
public void naturalIdCacheHit(String regionName) {
naturalIdCacheHitCount.getAndIncrement();
( (ConcurrentNaturalIdCacheStatisticsImpl) getNaturalIdCacheStatistics( regionName ) ).incrementHitCount();
}
@Override
public void naturalIdCacheMiss(String regionName) {
naturalIdCacheMissCount.getAndIncrement();
( (ConcurrentNaturalIdCacheStatisticsImpl) getNaturalIdCacheStatistics( regionName ) ).incrementMissCount();
}
@SuppressWarnings({ "UnnecessaryBoxing" })
public void queryExecuted(String hql, int rows, long time) {
@ -515,6 +570,21 @@ public class ConcurrentStatisticsImpl implements StatisticsImplementor, Service
public long getSecondLevelCachePutCount() {
return secondLevelCachePutCount.get();
}
@Override
public long getNaturalIdCacheHitCount() {
return naturalIdCacheHitCount.get();
}
@Override
public long getNaturalIdCacheMissCount() {
return naturalIdCacheMissCount.get();
}
@Override
public long getNaturalIdCachePutCount() {
return naturalIdCachePutCount.get();
}
/**
* @return session closing

View File

@ -25,6 +25,7 @@ package org.hibernate.stat.spi;
import org.hibernate.service.Service;
import org.hibernate.stat.Statistics;
import org.hibernate.stat.internal.ConcurrentSecondLevelCacheStatisticsImpl;
/**
* Statistics SPI for the Hibernate core. This is essentially the "statistic collector" API, its the contract
@ -171,6 +172,27 @@ public interface StatisticsImplementor extends Statistics, Service {
* @param regionName The name of the cache region
*/
public void secondLevelCacheMiss(String regionName);
/**
* Callback indicating a put into natural id cache.
*
* @param regionName The name of the cache region
*/
public void naturalIdCachePut(String regionName);
/**
* Callback indicating a get from natural id cache resulted in a hit.
*
* @param regionName The name of the cache region
*/
public void naturalIdCacheHit(String regionName);
/**
* Callback indicating a get from natural id cache resulted in a miss.
*
* @param regionName The name of the cache region
*/
public void naturalIdCacheMiss(String regionName);
/**
* Callback indicating a put into the query cache.

View File

@ -263,7 +263,7 @@ public class EntityMetamodel implements Serializable {
else {
naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers);
hasImmutableNaturalId = !foundUpdateableNaturalIdProperty;
hasCacheableNaturalId = true; //TODO how to read the annotation here?
hasCacheableNaturalId = persistentClass.getNaturalIdCacheRegionName() != null;
}
hasInsertGeneratedValues = foundInsertGeneratedValue;
@ -510,7 +510,7 @@ public class EntityMetamodel implements Serializable {
else {
naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers);
hasImmutableNaturalId = !foundUpdateableNaturalIdProperty;
hasCacheableNaturalId = true; //TODO how to read the annotation here?
hasCacheableNaturalId = false; //See previous TODO and HHH-6354
}
hasInsertGeneratedValues = foundInsertGeneratedValue;

View File

@ -23,11 +23,14 @@
*/
package org.hibernate.test.annotations.naturalid;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.junit.Test;
import org.hibernate.Criteria;
import org.hibernate.NaturalIdLoadAccess;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
@ -35,9 +38,7 @@ import org.hibernate.criterion.Restrictions;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.stat.Statistics;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Test case for NaturalId annotation
@ -112,6 +113,53 @@ public class NaturalIdTest extends BaseCoreFunctionalTestCase {
s.close();
}
@Test
public void testNaturalIdLoaderCached() {
saveSomeCitizens();
Session s = openSession();
Transaction tx = s.beginTransaction();
State france = ( State ) s.load( State.class, 2 );
final NaturalIdLoadAccess naturalIdLoader = s.byNaturalId( Citizen.class );
naturalIdLoader.using( "ssn", "1234" ).using( "state", france );
Statistics stats = sessionFactory().getStatistics();
stats.setStatisticsEnabled( true );
stats.clear();
assertEquals(
"Cache hits should be empty", 0, stats
.getQueryCacheHitCount()
);
// first query
Citizen citizen = (Citizen)naturalIdLoader.load();
assertNotNull( citizen );
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);
assertEquals(
"First load should be a miss", 1, stats
.getNaturalIdCacheMissCount()
);
assertEquals(
"Query result should be added to cache", 1, stats
.getNaturalIdCachePutCount()
);
// query a second time - result should be cached
citizen = (Citizen)naturalIdLoader.load();
assertNotNull( citizen );
assertEquals(
"Cache hits should be empty", 1, stats
.getNaturalIdCacheHitCount()
);
// cleanup
tx.rollback();
s.close();
}
@Test
public void testNaturalIdUncached() {
saveSomeCitizens();

View File

@ -235,11 +235,6 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
public boolean hasNaturalIdentifier() {
return false;
}
@Override
public boolean isNatrualIdentifierCached() {
return false;
}
@Override
public int[] getNaturalIdentifierProperties() {

View File

@ -563,11 +563,6 @@ public class CustomPersister implements EntityPersister {
public boolean hasNaturalIdentifier() {
return false;
}
@Override
public boolean isNatrualIdentifierCached() {
return false;
}
@Override
public boolean hasMutableProperties() {

View File

@ -0,0 +1,227 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.ehcache.internal.nonstop;
import net.sf.ehcache.constructs.nonstop.NonStopCacheException;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;
/**
* Implementation of {@link NaturalIdRegionAccessStrategy} that handles {@link NonStopCacheException} using
* {@link HibernateNonstopCacheExceptionHandler}
*
* @author Abhishek Sanoujam
* @author Alex Snaps
*/
public class NonstopAwareNaturalIdRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
private final NaturalIdRegionAccessStrategy actualStrategy;
private final HibernateNonstopCacheExceptionHandler hibernateNonstopExceptionHandler;
/**
* Constructor accepting the actual {@link NaturalIdRegionAccessStrategy} and the {@link HibernateNonstopCacheExceptionHandler}
*
* @param actualStrategy
* @param hibernateNonstopExceptionHandler
*/
public NonstopAwareNaturalIdRegionAccessStrategy(NaturalIdRegionAccessStrategy actualStrategy,
HibernateNonstopCacheExceptionHandler hibernateNonstopExceptionHandler) {
this.actualStrategy = actualStrategy;
this.hibernateNonstopExceptionHandler = hibernateNonstopExceptionHandler;
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#getRegion()
*/
public NaturalIdRegion getRegion() {
return actualStrategy.getRegion();
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#evict(java.lang.Object)
*/
public void evict(Object key) throws CacheException {
try {
actualStrategy.evict( key );
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#evictAll()
*/
public void evictAll() throws CacheException {
try {
actualStrategy.evictAll();
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#get(java.lang.Object, long)
*/
public Object get(Object key, long txTimestamp) throws CacheException {
try {
return actualStrategy.get( key, txTimestamp );
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
return null;
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#lockItem(java.lang.Object, java.lang.Object)
*/
public SoftLock lockItem(Object key, Object version) throws CacheException {
try {
return actualStrategy.lockItem( key, version );
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
return null;
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#lockRegion()
*/
public SoftLock lockRegion() throws CacheException {
try {
return actualStrategy.lockRegion();
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
return null;
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#putFromLoad(java.lang.Object, java.lang.Object, long, java.lang.Object,
* boolean)
*/
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
throws CacheException {
try {
return actualStrategy.putFromLoad( key, value, txTimestamp, version, minimalPutOverride );
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
return false;
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#putFromLoad(java.lang.Object, java.lang.Object, long, java.lang.Object)
*/
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
try {
return actualStrategy.putFromLoad( key, value, txTimestamp, version );
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
return false;
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#remove(java.lang.Object)
*/
public void remove(Object key) throws CacheException {
try {
actualStrategy.remove( key );
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#removeAll()
*/
public void removeAll() throws CacheException {
try {
actualStrategy.removeAll();
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#unlockItem(java.lang.Object, org.hibernate.cache.spi.access.SoftLock)
*/
public void unlockItem(Object key, SoftLock lock) throws CacheException {
try {
actualStrategy.unlockItem( key, lock );
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
}
}
/**
* {@inheritDoc}
*
* @see org.hibernate.cache.spi.access.EntityRegionAccessStrategy#unlockRegion(org.hibernate.cache.spi.access.SoftLock)
*/
public void unlockRegion(SoftLock lock) throws CacheException {
try {
actualStrategy.unlockRegion( lock );
}
catch ( NonStopCacheException nonStopCacheException ) {
hibernateNonstopExceptionHandler.handleNonstopCacheException( nonStopCacheException );
}
}
}

View File

@ -0,0 +1,66 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.ehcache.internal.regions;
import java.util.Properties;
import net.sf.ehcache.Ehcache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactory;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cfg.Settings;
/**
* A collection region specific wrapper around an Ehcache instance.
* <p/>
* This implementation returns Ehcache specific access strategy instances for all the non-transactional access types. Transactional access
* is not supported.
*
* @author Chris Dennis
* @author Abhishek Sanoujam
* @author Alex Snaps
*/
public class EhcacheNaturalIdRegion extends EhcacheTransactionalDataRegion implements NaturalIdRegion {
/**
* Constructs an EhcacheNaturalIdRegion around the given underlying cache.
*
* @param accessStrategyFactory
*/
public EhcacheNaturalIdRegion(EhcacheAccessStrategyFactory accessStrategyFactory, Ehcache underlyingCache, Settings settings,
CacheDataDescription metadata, Properties properties) {
super( accessStrategyFactory, underlyingCache, settings, metadata, properties );
}
@Override
public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
return accessStrategyFactory.createNaturalIdRegionAccessStrategy( this, accessType );
}
}

View File

@ -0,0 +1,99 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.ehcache.internal.strategy;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.cfg.Settings;
/**
* Ehcache specific non-strict read/write NaturalId region access strategy
*
* @author Chris Dennis
* @author Alex Snaps
*/
public class NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy
extends AbstractEhcacheAccessStrategy<EhcacheNaturalIdRegion>
implements NaturalIdRegionAccessStrategy {
/**
* Create a non-strict read/write access strategy accessing the given NaturalId region.
*/
public NonStrictReadWriteEhcacheNaturalIdRegionAccessStrategy(EhcacheNaturalIdRegion region, Settings settings) {
super( region, settings );
}
/**
* {@inheritDoc}
*/
public NaturalIdRegion getRegion() {
return region;
}
/**
* {@inheritDoc}
*/
public Object get(Object key, long txTimestamp) throws CacheException {
return region.get( key );
}
/**
* {@inheritDoc}
*/
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
throws CacheException {
if ( minimalPutOverride && region.contains( key ) ) {
return false;
}
else {
region.put( key, value );
return true;
}
}
/**
* Since this is a non-strict read/write strategy item locking is not used.
*/
public SoftLock lockItem(Object key, Object version) throws CacheException {
return null;
}
/**
* Since this is a non-strict read/write strategy item locking is not used.
*/
public void unlockItem(Object key, SoftLock lock) throws CacheException {
region.remove( key );
}
/**
* {@inheritDoc}
*/
@Override
public void remove(Object key) throws CacheException {
region.remove( key );
}
}

View File

@ -0,0 +1,93 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.ehcache.internal.strategy;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.cfg.Settings;
/**
* Ehcache specific read-only NaturalId region access strategy
*
* @author Chris Dennis
* @author Alex Snaps
*/
public class ReadOnlyEhcacheNaturalIdRegionAccessStrategy
extends AbstractEhcacheAccessStrategy<EhcacheNaturalIdRegion>
implements NaturalIdRegionAccessStrategy {
/**
* Create a read-only access strategy accessing the given NaturalId region.
*/
public ReadOnlyEhcacheNaturalIdRegionAccessStrategy(EhcacheNaturalIdRegion region, Settings settings) {
super( region, settings );
}
/**
* {@inheritDoc}
*/
public NaturalIdRegion getRegion() {
return region;
}
/**
* {@inheritDoc}
*/
public Object get(Object key, long txTimestamp) throws CacheException {
return region.get( key );
}
/**
* {@inheritDoc}
*/
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
throws CacheException {
if ( minimalPutOverride && region.contains( key ) ) {
return false;
}
else {
region.put( key, value );
return true;
}
}
/**
* Throws UnsupportedOperationException since this cache is read-only
*
* @throws UnsupportedOperationException always
*/
public SoftLock lockItem(Object key, Object version) throws UnsupportedOperationException {
throw new UnsupportedOperationException( "Can't write to a readonly object" );
}
/**
* A no-op since this cache is read-only
*/
public void unlockItem(Object key, SoftLock lock) throws CacheException {
//throw new UnsupportedOperationException("Can't write to a readonly object");
}
}

View File

@ -0,0 +1,54 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.ehcache.internal.strategy;
import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cfg.Settings;
/**
* Ehcache specific read/write NaturalId region access strategy
*
* @author Chris Dennis
* @author Alex Snaps
*/
public class ReadWriteEhcacheNaturalIdRegionAccessStrategy
extends AbstractReadWriteEhcacheAccessStrategy<EhcacheNaturalIdRegion>
implements NaturalIdRegionAccessStrategy {
/**
* Create a read/write access strategy accessing the given NaturalId region.
*/
public ReadWriteEhcacheNaturalIdRegionAccessStrategy(EhcacheNaturalIdRegion region, Settings settings) {
super( region, settings );
}
/**
* {@inheritDoc}
*/
public NaturalIdRegion getRegion() {
return region;
}
}

View File

@ -0,0 +1,127 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cache.ehcache.internal.strategy;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.ehcache.internal.regions.EhcacheNaturalIdRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.cfg.Settings;
/**
* JTA NaturalIdRegionAccessStrategy.
*
* @author Chris Dennis
* @author Ludovic Orban
* @author Alex Snaps
*/
public class TransactionalEhcacheNaturalIdRegionAccessStrategy
extends AbstractEhcacheAccessStrategy<EhcacheNaturalIdRegion>
implements NaturalIdRegionAccessStrategy {
private final Ehcache ehcache;
/**
* Construct a new collection region access strategy.
*
* @param region the Hibernate region.
* @param ehcache the cache.
* @param settings the Hibernate settings.
*/
public TransactionalEhcacheNaturalIdRegionAccessStrategy(EhcacheNaturalIdRegion region, Ehcache ehcache, Settings settings) {
super( region, settings );
this.ehcache = ehcache;
}
/**
* {@inheritDoc}
*/
public Object get(Object key, long txTimestamp) throws CacheException {
try {
Element element = ehcache.get( key );
return element == null ? null : element.getObjectValue();
}
catch ( net.sf.ehcache.CacheException e ) {
throw new CacheException( e );
}
}
/**
* {@inheritDoc}
*/
public NaturalIdRegion getRegion() {
return region;
}
/**
* {@inheritDoc}
*/
public SoftLock lockItem(Object key, Object version) throws CacheException {
return null;
}
/**
* {@inheritDoc}
*/
public boolean putFromLoad(Object key, Object value, long txTimestamp,
Object version, boolean minimalPutOverride) throws CacheException {
try {
if ( minimalPutOverride && ehcache.get( key ) != null ) {
return false;
}
//OptimisticCache? versioning?
ehcache.put( new Element( key, value ) );
return true;
}
catch ( net.sf.ehcache.CacheException e ) {
throw new CacheException( e );
}
}
/**
* {@inheritDoc}
*/
@Override
public void remove(Object key) throws CacheException {
try {
ehcache.remove( key );
}
catch ( net.sf.ehcache.CacheException e ) {
throw new CacheException( e );
}
}
/**
* {@inheritDoc}
*/
public void unlockItem(Object key, SoftLock lock) throws CacheException {
// no-op
}
}

View File

@ -258,11 +258,6 @@ public class PersisterClassProviderTest {
return false;
}
@Override
public boolean isNatrualIdentifierCached() {
return false;
}
@Override
public int[] getNaturalIdentifierProperties() {
return new int[0];

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.cache;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
/**
* @author Eric Dalquist
*/
class BaseNaturalIdRegionAccessStrategy extends BaseRegionAccessStrategy implements NaturalIdRegionAccessStrategy {
private final NaturalIdRegionImpl region;
@Override
protected BaseGeneralDataRegion getInternalRegion() {
return region;
}
@Override
protected boolean isDefaultMinimalPutOverride() {
return region.getSettings().isMinimalPutsEnabled();
}
@Override
public NaturalIdRegion getRegion() {
return region;
}
BaseNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) {
this.region = region;
}
}

View File

@ -0,0 +1,73 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.cache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cfg.Settings;
import org.hibernate.internal.CoreMessageLogger;
import org.jboss.logging.Logger;
/**
* @author Eric Dalquist
*/
class NaturalIdRegionImpl extends BaseTransactionalDataRegion implements NaturalIdRegion {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class, NaturalIdRegionImpl.class.getName()
);
private final Settings settings;
NaturalIdRegionImpl(String name, CacheDataDescription metadata, Settings settings) {
super( name, metadata );
this.settings=settings;
}
public Settings getSettings() {
return settings;
}
@Override
public NaturalIdRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
switch ( accessType ) {
case READ_ONLY:
if ( getCacheDataDescription().isMutable() ) {
LOG.warnf( "read-only cache configured for mutable collection [ %s ]", getName() );
}
return new ReadOnlyNaturalIdRegionAccessStrategy( this );
case READ_WRITE:
return new ReadWriteNaturalIdRegionAccessStrategy( this );
case NONSTRICT_READ_WRITE:
return new NonstrictReadWriteNaturalIdRegionAccessStrategy( this );
case TRANSACTIONAL:
return new TransactionalNaturalIdRegionAccessStrategy( this );
// throw new UnsupportedOperationException( "doesn't support this access strategy" );
default:
throw new IllegalArgumentException( "unrecognized access strategy type [" + accessType + "]" );
}
}
}

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.cache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.SoftLock;
/**
* @author Eric Dalquist
*/
class NonstrictReadWriteNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy {
NonstrictReadWriteNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) {
super( region );
}
@Override
public void unlockItem(Object key, SoftLock lock) throws CacheException {
evict( key );
}
@Override
public void remove(Object key) throws CacheException {
evict( key );
}
}

View File

@ -0,0 +1,57 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.cache;
import org.jboss.logging.Logger;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.internal.CoreMessageLogger;
/**
* @author Eric Dalquist
*/
class ReadOnlyNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class, ReadOnlyNaturalIdRegionAccessStrategy.class.getName()
);
ReadOnlyNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) {
super( region );
}
@Override
public void unlockItem(Object key, SoftLock lock) throws CacheException {
LOG.invalidEditOfReadOnlyItem( key );
}
@Override
public SoftLock lockItem(Object key, Object version) throws CacheException {
LOG.invalidEditOfReadOnlyItem( key );
throw new UnsupportedOperationException( "Can't write to a readonly object" );
}
}

View File

@ -0,0 +1,62 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.cache;
import java.util.Comparator;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
/**
* @author Eric Dalquist
*/
class ReadWriteNaturalIdRegionAccessStrategy extends AbstractReadWriteAccessStrategy
implements NaturalIdRegionAccessStrategy {
private final NaturalIdRegionImpl region;
ReadWriteNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) {
this.region = region;
}
@Override
Comparator getVersionComparator() {
return region.getCacheDataDescription().getVersionComparator();
}
@Override
protected BaseGeneralDataRegion getInternalRegion() {
return region;
}
@Override
protected boolean isDefaultMinimalPutOverride() {
return region.getSettings().isMinimalPutsEnabled();
}
@Override
public NaturalIdRegion getRegion() {
return region;
}
}

View File

@ -0,0 +1,25 @@
package org.hibernate.testing.cache;
import org.hibernate.cache.CacheException;
/**
* @author Eric Dalquist
*/
class TransactionalNaturalIdRegionAccessStrategy extends BaseNaturalIdRegionAccessStrategy {
TransactionalNaturalIdRegionAccessStrategy(NaturalIdRegionImpl region) {
super( region );
}
/**
* {@inheritDoc}
*/
@Override
public void remove(Object key) throws CacheException {
evict( key );
}
}