Skip to content

Commit

Permalink
HHH-6974 Class level naturalId cache and stats
Browse files Browse the repository at this point in the history
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
  • Loading branch information
edalquist authored and sebersole committed Feb 7, 2012
1 parent 72fe79a commit c473520
Show file tree
Hide file tree
Showing 36 changed files with 1,539 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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�s Lichtmaier
* @see NaturalIdCache
*/
@Target( { METHOD, FIELD } )
@Retention( RUNTIME )
Expand All @@ -44,11 +45,4 @@
* @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;
}
Original file line number Diff line number Diff line change
@@ -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 "";
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.CollectionTable;
Expand Down Expand Up @@ -79,8 +80,6 @@
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;
Expand Down Expand Up @@ -112,6 +111,7 @@
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;
Expand Down Expand Up @@ -167,6 +167,7 @@
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
Expand Down Expand Up @@ -574,6 +575,7 @@ public static void bindClass(
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() ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.Access;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
Expand All @@ -35,8 +36,6 @@
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;
Expand All @@ -47,6 +46,7 @@
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;
Expand Down Expand Up @@ -89,6 +89,7 @@
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
Expand All @@ -97,7 +98,8 @@
*/
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;
Expand All @@ -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;
Expand Down Expand Up @@ -230,6 +233,7 @@ public void bindEntity() {
rootClass.setCacheRegionName( cacheRegion );
rootClass.setLazyPropertiesCacheable( cacheLazyProperty );
}
rootClass.setNaturalIdCacheRegionName( naturalIdCacheRegion );
boolean forceDiscriminatorInSelects = forceDiscriminator == null
? mappings.forceDiscriminatorInSelectsByDefault()
: forceDiscriminator;
Expand Down Expand Up @@ -826,6 +830,25 @@ else if ( "non-lazy".equalsIgnoreCase( cacheAnn.include() ) ) {
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@
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;
Expand Down Expand Up @@ -145,6 +144,7 @@
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver;
import org.jboss.logging.Logger;


/**
Expand Down Expand Up @@ -173,7 +173,6 @@
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();

Expand Down Expand Up @@ -360,8 +359,8 @@ public void sessionFactoryClosed(SessionFactory factory) {
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() ) {
Expand Down Expand Up @@ -805,14 +804,6 @@ public void sessionFactoryClosed(SessionFactory factory) {
);
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);

Expand Down Expand Up @@ -1643,6 +1634,10 @@ public Region getSecondLevelCacheRegion(String regionName) {
return allCacheRegions.get( regionName );
}

public Region getNaturalIdCacheRegion(String regionName) {
return allCacheRegions.get( regionName );
}

@SuppressWarnings( {"unchecked"})
public Map getAllSecondLevelCacheRegions() {
return new HashMap( allCacheRegions );
Expand Down
Loading

0 comments on commit c473520

Please sign in to comment.