HHH-6974 - Add caching to new "load access" api for natural id loading

This commit is contained in:
Steve Ebersole 2012-02-07 09:25:50 -06:00
parent 1569e6194b
commit ae872ed898
6 changed files with 117 additions and 127 deletions

View File

@ -103,6 +103,7 @@ public interface Cache {
*
* @param naturalIdClass The naturalId class.
*/
@SuppressWarnings( {"UnusedDeclaration"})
public void evictNaturalIdRegion(Class naturalIdClass);
/**
@ -131,6 +132,7 @@ public interface Cache {
*
* @return True if the underlying cache contains corresponding data; false otherwise.
*/
@SuppressWarnings( {"UnusedDeclaration"})
public boolean containsCollection(String role, Serializable ownerIdentifier);
/**
@ -143,7 +145,7 @@ public interface Cache {
/**
* Evicts all entity data from the given region (i.e. evicts cached data
* for all of the specified c9ollection role).
* for all of the specified collection role).
*
* @param role The "collection role" (in form [owner-entity-name].[collection-property-name]).
*/
@ -164,6 +166,7 @@ public interface Cache {
*
* @return True if the underlying cache contains corresponding data; false otherwise.
*/
@SuppressWarnings( {"UnusedDeclaration"})
public boolean containsQuery(String regionName);
/**

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2012, 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.
@ -24,49 +24,46 @@
package org.hibernate.cache.spi;
import java.io.Serializable;
import java.util.Arrays;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.compare.EqualsHelper;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.Type;
/**
* Allows multiple entity classes / collection roles to be
* stored in the same cache region. Also allows for composite
* keys which do not properly implement equals()/hashCode().
* Defines a key for caching natural identifier resolutions into the second level cache.
*
* @author Gavin King
* @author Eric Dalquist
* @author Steve Ebersole
*/
public class NaturalIdCacheKey implements Serializable {
private final Serializable[] naturalId;
private final Type[] naturalIdTypes;
private final Serializable[] naturalIdValues;
private final String entityName;
private final String tenantId;
private final int hashCode;
private final String toString;
/**
* Construct a new key for a collection or entity instance.
* Note that an entity name should always be the root entity
* name, not a subclass entity name.
* Construct a new key for a caching natural identifier resolutions into the second level cache.
* Note that an entity name should always be the root entity name, not a subclass entity name.
*
* @param naturalId The naturalId associated with the cached data
* @param naturalIdValues The naturalIdValues associated with the cached data
* @param persister The persister for the entity
* @param session The session for which we are caching
* @param session The originating session
*/
public NaturalIdCacheKey(
final Object[] naturalId,
final Object[] naturalIdValues,
final EntityPersister persister,
final SessionImplementor session) {
this.entityName = persister.getEntityName();
this.entityName = persister.getRootEntityName();
this.tenantId = session.getTenantIdentifier();
final Serializable[] disassembledNaturalId = new Serializable[naturalId.length];
final Type[] naturalIdTypes = new Type[naturalId.length];
final StringBuilder str = new StringBuilder(entityName).append( "##NaturalId[" );
final Serializable[] disassembledNaturalId = new Serializable[naturalIdValues.length];
final StringBuilder toStringBuilder = new StringBuilder( entityName ).append( "##NaturalId[" );
final SessionFactoryImplementor factory = session.getFactory();
final int[] naturalIdPropertyIndexes = persister.getNaturalIdentifierProperties();
final Type[] propertyTypes = persister.getPropertyTypes();
@ -75,39 +72,39 @@ public class NaturalIdCacheKey implements Serializable {
int result = 1;
result = prime * result + ( ( this.entityName == null ) ? 0 : this.entityName.hashCode() );
result = prime * result + ( ( this.tenantId == null ) ? 0 : this.tenantId.hashCode() );
for ( int i = 0; i < naturalId.length; i++ ) {
for ( int i = 0; i < naturalIdValues.length; i++ ) {
final Type type = propertyTypes[naturalIdPropertyIndexes[i]];
final Object value = naturalId[i];
final Object value = naturalIdValues[i];
result = prime * result + type.getHashCode( value, factory );
disassembledNaturalId[i] = type.disassemble( value, session, null );
naturalIdTypes[i] = type;
str.append( type.toLoggableString( value, factory ) );
if (i + 1 < naturalId.length) {
str.append( ", " );
toStringBuilder.append( type.toLoggableString( value, factory ) );
if (i + 1 < naturalIdValues.length) {
toStringBuilder.append( ", " );
}
}
str.append( "]" );
toStringBuilder.append( "]" );
this.naturalId = disassembledNaturalId;
this.naturalIdTypes = naturalIdTypes;
this.naturalIdValues = disassembledNaturalId;
this.hashCode = result;
this.toString = str.toString();
this.toString = toStringBuilder.toString();
}
@SuppressWarnings( {"UnusedDeclaration"})
public String getEntityName() {
return entityName;
}
@SuppressWarnings( {"UnusedDeclaration"})
public String getTenantId() {
return tenantId;
}
public Serializable[] getNaturalId() {
return naturalId;
@SuppressWarnings( {"UnusedDeclaration"})
public Serializable[] getNaturalIdValues() {
return naturalIdValues;
}
@Override
@ -121,38 +118,18 @@ public class NaturalIdCacheKey implements Serializable {
}
@Override
public boolean equals(Object obj) {
if ( this == obj )
public boolean equals(Object o) {
if ( this == o ) {
return true;
if ( obj == null )
return false;
if ( getClass() != obj.getClass() )
return false;
NaturalIdCacheKey other = (NaturalIdCacheKey) obj;
if ( entityName == null ) {
if ( other.entityName != null )
return false;
}
else if ( !entityName.equals( other.entityName ) )
if ( o == null || getClass() != o.getClass() ) {
return false;
if ( tenantId == null ) {
if ( other.tenantId != null )
return false;
}
else if ( !tenantId.equals( other.tenantId ) )
return false;
if ( naturalId == other.naturalId )
return true;
if ( naturalId == null || other.naturalId == null )
return false;
int length = naturalId.length;
if ( other.naturalId.length != length )
return false;
for ( int i = 0; i < length; i++ ) {
if ( !this.naturalIdTypes[i].isEqual( naturalId[i], other.naturalId[i] ) ) {
return false;
}
}
return true;
final NaturalIdCacheKey other = (NaturalIdCacheKey) o;
return entityName.equals( other.entityName )
&& EqualsHelper.equals( tenantId, other.tenantId )
&& Arrays.equals( naturalIdValues, other.naturalIdValues );
}
}

View File

@ -1,7 +1,7 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* Copyright (c) 2012, 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.
@ -32,6 +32,7 @@ import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
* store naturalId data.
*
* @author Eric Dalquist
* @author Steve Ebersole
*/
public interface NaturalIdRegion extends TransactionalDataRegion {

View File

@ -30,13 +30,12 @@ import org.hibernate.engine.spi.TypedValue;
/**
* @author Gavin King
* @deprecated Use {@link Session#byNaturalId(Class)}
*
* @see Session#byNaturalId(Class)
* @see Session#byNaturalId(String)
* @see Session#bySimpleNaturalId(Class)
* @see Session#bySimpleNaturalId(String)
*/
@Deprecated
public class NaturalIdentifier implements Criterion {
private Junction conjunction = new Conjunction();

View File

@ -385,13 +385,14 @@ public class Restrictions {
}
/**
* @deprecated Use {@link Session#byNaturalId(Class)}
* Consider using any of the natural id based loading stuff from session instead, especially in cases
* where the restriction is the full set of natural id values.
*
* @see Session#byNaturalId(Class)
* @see Session#byNaturalId(String)
* @see Session#bySimpleNaturalId(Class)
* @see Session#bySimpleNaturalId(String)
*/
@Deprecated
public static NaturalIdentifier naturalId() {
return new NaturalIdentifier();
}

View File

@ -1785,22 +1785,19 @@ public class StatefulPersistenceContext implements PersistenceContext {
@Override
public boolean equals(Object obj) {
if ( this == obj )
if ( this == obj ) {
return true;
if ( obj == null )
return false;
if ( getClass() != obj.getClass() )
return false;
LocalNaturalIdCacheKey other = (LocalNaturalIdCacheKey) obj;
if ( persister == null ) {
if ( other.persister != null )
return false;
}
else if ( !persister.equals( other.persister ) )
if ( obj == null ) {
return false;
if ( !Arrays.equals( values, other.values ) )
}
if ( getClass() != obj.getClass() ) {
return false;
return true;
}
final LocalNaturalIdCacheKey other = (LocalNaturalIdCacheKey) obj;
return persister.equals( other.persister )
&& Arrays.equals( values, other.values );
}
}
@ -1858,11 +1855,13 @@ public class StatefulPersistenceContext implements PersistenceContext {
// Found in session cache
if ( pk != null ) {
if ( LOG.isTraceEnabled() )
LOG.tracev(
"Resolved primary key in session cache: {0}",
MessageHelper.infoString( persister, Arrays.toString( naturalIdValues ),
session.getFactory() ) );
if ( LOG.isTraceEnabled() ) {
LOG.trace(
"Resolved natural key -> primary key resolution in session cache: " +
persister.getRootEntityName() + "#[" +
Arrays.toString( naturalIdValues ) + "]"
);
}
return pk;
}
@ -1884,12 +1883,16 @@ public class StatefulPersistenceContext implements PersistenceContext {
if ( pk != null ) {
if ( factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().naturalIdCacheHit(
naturalIdCacheAccessStrategy.getRegion().getName() );
naturalIdCacheAccessStrategy.getRegion().getName()
);
}
if ( LOG.isTraceEnabled() )
LOG.tracev( "Resolved primary key in second-level cache: {0}",
MessageHelper.infoString( persister, naturalIdCacheKey.getNaturalId(), session.getFactory() ) );
LOG.trace(
"Resolved natural key -> primary key resolution in second-level cache: " +
persister.getRootEntityName() + "#[" +
Arrays.toString( naturalIdValues ) + "]"
);
if ( entityNaturalIdResolutionCache == null ) {
entityNaturalIdResolutionCache = new NaturalIdResolutionCache( persister );
@ -1929,54 +1932,60 @@ public class StatefulPersistenceContext implements PersistenceContext {
final SessionFactoryImplementor factory = getSession().getFactory();
switch ( valueSource ) {
case LOAD: {
final boolean put = naturalIdCacheAccessStrategy.putFromLoad( naturalIdCacheKey, pk, session.getTimestamp(), null );
case LOAD: {
final boolean put = naturalIdCacheAccessStrategy.putFromLoad(
naturalIdCacheKey,
pk,
session.getTimestamp(),
null
);
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().naturalIdCachePut(
naturalIdCacheAccessStrategy.getRegion().getName() );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor()
.naturalIdCachePut( naturalIdCacheAccessStrategy.getRegion().getName() );
}
break;
}
case INSERT: {
naturalIdCacheAccessStrategy.insert( naturalIdCacheKey, pk );
break;
}
case INSERT: {
naturalIdCacheAccessStrategy.insert( naturalIdCacheKey, pk );
( (EventSource) this.session ).getActionQueue().registerProcess(
new AfterTransactionCompletionProcess() {
@Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
final boolean put = naturalIdCacheAccessStrategy.afterInsert( naturalIdCacheKey, pk );
( (EventSource) this.session ).getActionQueue().registerProcess(
new AfterTransactionCompletionProcess() {
@Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
final boolean put = naturalIdCacheAccessStrategy.afterInsert( naturalIdCacheKey, pk );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().naturalIdCachePut(
naturalIdCacheAccessStrategy.getRegion().getName() );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().naturalIdCachePut(
naturalIdCacheAccessStrategy.getRegion().getName() );
}
}
}
} );
);
break;
}
case UPDATE: {
final SoftLock lock = naturalIdCacheAccessStrategy.lockItem( naturalIdCacheKey, null );
break;
}
case UPDATE: {
final SoftLock lock = naturalIdCacheAccessStrategy.lockItem( naturalIdCacheKey, null );
naturalIdCacheAccessStrategy.update( naturalIdCacheKey, pk );
naturalIdCacheAccessStrategy.update( naturalIdCacheKey, pk );
( (EventSource) this.session ).getActionQueue().registerProcess(
new AfterTransactionCompletionProcess() {
@Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
final boolean put = naturalIdCacheAccessStrategy.afterUpdate( naturalIdCacheKey, pk, lock );
( (EventSource) this.session ).getActionQueue().registerProcess(
new AfterTransactionCompletionProcess() {
@Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
final boolean put = naturalIdCacheAccessStrategy.afterUpdate( naturalIdCacheKey, pk, lock );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().naturalIdCachePut(
naturalIdCacheAccessStrategy.getRegion().getName() );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().naturalIdCachePut(
naturalIdCacheAccessStrategy.getRegion().getName() );
}
}
}
} );
);
break;
}
break;
}
}
}
}