HHH-7085 Use the in-flight state for naturalId caching

Pass the current state Object[] from the event into the SPC to use
for naturalId caching
This commit is contained in:
Eric Dalquist 2012-02-20 10:52:41 -06:00 committed by Steve Ebersole
parent b5ba7bef42
commit f1a54aeadf
4 changed files with 44 additions and 35 deletions

View File

@ -92,7 +92,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction {
throw new AssertionFailure( "possible nonthreadsafe access to session" ); throw new AssertionFailure( "possible nonthreadsafe access to session" );
} }
entry.postInsert(); entry.postInsert( getState() );
if ( persister.hasInsertGeneratedProperties() ) { if ( persister.hasInsertGeneratedProperties() ) {
persister.processInsertGeneratedProperties( id, instance, getState(), session ); persister.processInsertGeneratedProperties( id, instance, getState(), session );

View File

@ -1705,54 +1705,53 @@ public class StatefulPersistenceContext implements PersistenceContext {
// NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override @Override
public void loadedStateInsertedNotification(EntityEntry entityEntry) { public void loadedStateInsertedNotification(EntityEntry entityEntry, Object[] state) {
final EntityPersister persister = entityEntry.getPersister(); final EntityPersister persister = entityEntry.getPersister();
if ( !persister.hasNaturalIdentifier() ) { if ( !persister.hasNaturalIdentifier() ) {
// nothing to do // nothing to do
return; return;
} }
final Object[] naturalIdValues = getNaturalIdValues( entityEntry, persister ); final Object[] naturalIdValues = getNaturalIdValues( state, persister );
// cache // cache
cacheNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues, CachedNaturalIdValueSource.INSERT ); cacheNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues, CachedNaturalIdValueSource.INSERT );
} }
@Override @Override
public void loadedStateUpdatedNotification(EntityEntry entityEntry) { public void loadedStateUpdatedNotification(EntityEntry entityEntry, Object[] state) {
final EntityPersister persister = entityEntry.getPersister(); final EntityPersister persister = entityEntry.getPersister();
if ( !persister.hasNaturalIdentifier() ) { if ( !persister.hasNaturalIdentifier() ) {
// nothing to do // nothing to do
return; return;
} }
final Object[] naturalIdValues = getNaturalIdValues( entityEntry, persister ); final Object[] naturalIdValues = getNaturalIdValues( state, persister );
// re-cache // re-cache
cacheNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues, CachedNaturalIdValueSource.UPDATE ); cacheNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues, CachedNaturalIdValueSource.UPDATE );
} }
@Override @Override
public void loadedStateDeletedNotification(EntityEntry entityEntry) { public void loadedStateDeletedNotification(EntityEntry entityEntry, Object[] deletedState) {
final EntityPersister persister = entityEntry.getPersister(); final EntityPersister persister = entityEntry.getPersister();
if ( !persister.hasNaturalIdentifier() ) { if ( !persister.hasNaturalIdentifier() ) {
// nothing to do // nothing to do
return; return;
} }
final Object[] naturalIdValues = getNaturalIdValues( entityEntry, persister ); final Object[] naturalIdValues = getNaturalIdValues( deletedState, persister );
// evict from cache // evict from cache
evictNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues ); evictNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues );
} }
private Object[] getNaturalIdValues(EntityEntry entityEntry, EntityPersister persister) { private Object[] getNaturalIdValues(Object[] state, EntityPersister persister) {
final int[] naturalIdPropertyIndexes = persister.getNaturalIdentifierProperties(); final int[] naturalIdPropertyIndexes = persister.getNaturalIdentifierProperties();
final Object[] naturalIdValues = new Object[naturalIdPropertyIndexes.length]; final Object[] naturalIdValues = new Object[naturalIdPropertyIndexes.length];
final Object[] loadedState = entityEntry.getLoadedState();
for ( int i = 0; i < naturalIdPropertyIndexes.length; i++ ) { for ( int i = 0; i < naturalIdPropertyIndexes.length; i++ ) {
naturalIdValues[i] = loadedState[naturalIdPropertyIndexes[i]]; naturalIdValues[i] = state[naturalIdPropertyIndexes[i]];
} }
return naturalIdValues; return naturalIdValues;
@ -1990,27 +1989,38 @@ public class StatefulPersistenceContext implements PersistenceContext {
} }
} }
@Override private void evictNaturalIdResolution(EntityPersister persister, final Serializable pk, Object[] deletedNaturalIdValues) {
public void evictNaturalIdResolution(EntityPersister persister, final Serializable pk, Object[] naturalIdValues) {
if ( !persister.hasNaturalIdentifier() ) { if ( !persister.hasNaturalIdentifier() ) {
throw new IllegalArgumentException( "Entity did not define a natural-id" ); throw new IllegalArgumentException( "Entity did not define a natrual-id" );
} }
if ( persister.getNaturalIdentifierProperties().length != naturalIdValues.length ) { if ( persister.getNaturalIdentifierProperties().length != deletedNaturalIdValues.length ) {
throw new IllegalArgumentException( "Mismatch between expected number of natural-id values and found." ); throw new IllegalArgumentException( "Mismatch between expected number of natural-id values and found." );
} }
NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister ); NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister );
Object[] sessionCachedNaturalIdValues = null;
if ( entityNaturalIdResolutionCache != null ) { if ( entityNaturalIdResolutionCache != null ) {
final LocalNaturalIdCacheKey localNaturalIdCacheKey = new LocalNaturalIdCacheKey( persister, final LocalNaturalIdCacheKey localNaturalIdCacheKey = entityNaturalIdResolutionCache.pkToNaturalIdMap
naturalIdValues ); .remove( pk );
entityNaturalIdResolutionCache.pkToNaturalIdMap.remove( pk ); if ( localNaturalIdCacheKey != null ) {
entityNaturalIdResolutionCache.naturalIdToPkMap.remove( localNaturalIdCacheKey ); entityNaturalIdResolutionCache.naturalIdToPkMap.remove( localNaturalIdCacheKey );
sessionCachedNaturalIdValues = localNaturalIdCacheKey.getValues();
}
} }
if ( persister.hasNaturalIdCache() ) { if ( persister.hasNaturalIdCache() ) {
final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy(); final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = persister
final NaturalIdCacheKey naturalIdCacheKey = new NaturalIdCacheKey( naturalIdValues, persister, session ); .getNaturalIdCacheAccessStrategy();
final NaturalIdCacheKey naturalIdCacheKey = new NaturalIdCacheKey( deletedNaturalIdValues, persister,
session );
naturalIdCacheAccessStrategy.evict( naturalIdCacheKey ); naturalIdCacheAccessStrategy.evict( naturalIdCacheKey );
if ( sessionCachedNaturalIdValues != null
&& !Arrays.equals( sessionCachedNaturalIdValues, deletedNaturalIdValues ) ) {
final NaturalIdCacheKey sessionNaturalIdCacheKey = new NaturalIdCacheKey( sessionCachedNaturalIdValues,
persister, session );
naturalIdCacheAccessStrategy.evict( sessionNaturalIdCacheKey );
}
} }
} }
} }

View File

@ -241,7 +241,7 @@ public final class EntityEntry implements Serializable {
.getCustomEntityDirtinessStrategy() .getCustomEntityDirtinessStrategy()
.resetDirty( entity, getPersister(), (Session) persistenceContext.getSession() ); .resetDirty( entity, getPersister(), (Session) persistenceContext.getSession() );
notifyLoadedStateUpdated(); notifyLoadedStateUpdated( updatedState );
} }
/** /**
@ -253,17 +253,17 @@ public final class EntityEntry implements Serializable {
status = Status.GONE; status = Status.GONE;
existsInDatabase = false; existsInDatabase = false;
notifyLoadedStateDeleted(); notifyLoadedStateDeleted( deletedState );
} }
/** /**
* After actually inserting a row, record the fact that the instance exists on the * After actually inserting a row, record the fact that the instance exists on the
* database (needed for identity-column key generation) * database (needed for identity-column key generation)
*/ */
public void postInsert() { public void postInsert(Object[] insertedState) {
existsInDatabase = true; existsInDatabase = true;
notifyLoadedStateInserted(); notifyLoadedStateInserted( insertedState );
} }
public boolean isNullifiable(boolean earlyInsert, SessionImplementor session) { public boolean isNullifiable(boolean earlyInsert, SessionImplementor session) {
@ -360,7 +360,7 @@ public final class EntityEntry implements Serializable {
} }
setStatus( Status.MANAGED ); setStatus( Status.MANAGED );
loadedState = getPersister().getPropertyValues( entity ); loadedState = getPersister().getPropertyValues( entity );
notifyLoadedStateUpdated(); notifyLoadedStateUpdated( loadedState );
} }
} }
@ -374,28 +374,28 @@ public final class EntityEntry implements Serializable {
return loadedWithLazyPropertiesUnfetched; return loadedWithLazyPropertiesUnfetched;
} }
private void notifyLoadedStateUpdated() { private void notifyLoadedStateUpdated(Object[] state) {
if ( persistenceContext == null ) { if ( persistenceContext == null ) {
throw new HibernateException( "PersistenceContext was null on attempt to update loaded state" ); throw new HibernateException( "PersistenceContext was null on attempt to update loaded state" );
} }
persistenceContext.loadedStateUpdatedNotification( this ); persistenceContext.loadedStateUpdatedNotification( this, state );
} }
private void notifyLoadedStateInserted() { private void notifyLoadedStateInserted(Object[] state) {
if ( persistenceContext == null ) { if ( persistenceContext == null ) {
throw new HibernateException( "PersistenceContext was null on attempt to insert loaded state" ); throw new HibernateException( "PersistenceContext was null on attempt to insert loaded state" );
} }
persistenceContext.loadedStateInsertedNotification( this ); persistenceContext.loadedStateInsertedNotification( this, state );
} }
private void notifyLoadedStateDeleted() { private void notifyLoadedStateDeleted(Object[] deletedState) {
if ( persistenceContext == null ) { if ( persistenceContext == null ) {
throw new HibernateException( "PersistenceContext was null on attempt to delete loaded state" ); throw new HibernateException( "PersistenceContext was null on attempt to delete loaded state" );
} }
persistenceContext.loadedStateDeletedNotification( this ); persistenceContext.loadedStateDeletedNotification( this, deletedState );
} }
/** /**

View File

@ -683,11 +683,11 @@ public interface PersistenceContext {
*/ */
public boolean wasInsertedDuringTransaction(EntityPersister persister, Serializable id); public boolean wasInsertedDuringTransaction(EntityPersister persister, Serializable id);
public void loadedStateUpdatedNotification(EntityEntry entityEntry); public void loadedStateUpdatedNotification(EntityEntry entityEntry, Object[] state);
public void loadedStateInsertedNotification(EntityEntry entityEntry); public void loadedStateInsertedNotification(EntityEntry entityEntry, Object[] state);
public void loadedStateDeletedNotification(EntityEntry entityEntry); public void loadedStateDeletedNotification(EntityEntry entityEntry, Object[] deletedState);
public Object[] findCachedNaturalId(EntityPersister persister, Serializable pk); public Object[] findCachedNaturalId(EntityPersister persister, Serializable pk);
@ -704,5 +704,4 @@ public interface PersistenceContext {
public void cacheNaturalIdResolution(EntityPersister persister, Serializable pk, Object[] naturalId, CachedNaturalIdValueSource valueSource); public void cacheNaturalIdResolution(EntityPersister persister, Serializable pk, Object[] naturalId, CachedNaturalIdValueSource valueSource);
public void evictNaturalIdResolution(EntityPersister persister, final Serializable pk, Object[] naturalIdValues );
} }