HHH-13565 Making SessionFactoryImpl#LockOptions lazily initialized as well

This commit is contained in:
Sanne Grinovero 2019-08-21 09:16:38 +01:00
parent 2de048fde5
commit 646a8756a9
3 changed files with 111 additions and 50 deletions

View File

@ -39,6 +39,7 @@ import org.hibernate.event.spi.SaveOrUpdateEventListener;
import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.internal.util.CacheModeHelper; import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.LockOptionsHelper;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
@ -118,6 +119,7 @@ final class FastSessionServices {
final CacheMode initialSessionCacheMode; final CacheMode initialSessionCacheMode;
final boolean discardOnClose; final boolean discardOnClose;
final BaselineSessionEventsListenerBuilder defaultSessionEventListeners; final BaselineSessionEventsListenerBuilder defaultSessionEventListeners;
final LockOptions defaultLockOptions;
//Private fields: //Private fields:
private final Dialect dialect; private final Dialect dialect;
@ -174,6 +176,13 @@ final class FastSessionServices {
this.discardOnClose = sessionFactoryOptions.isReleaseResourcesOnCloseEnabled(); this.discardOnClose = sessionFactoryOptions.isReleaseResourcesOnCloseEnabled();
this.defaultJdbcObservers = Collections.singletonList( new ConnectionObserverStatsBridge( sf ) ); this.defaultJdbcObservers = Collections.singletonList( new ConnectionObserverStatsBridge( sf ) );
this.defaultSessionEventListeners = sessionFactoryOptions.getBaselineSessionEventsListenerBuilder(); this.defaultSessionEventListeners = sessionFactoryOptions.getBaselineSessionEventsListenerBuilder();
this.defaultLockOptions = initializeDefaultLockOptions( defaultSessionProperties );
}
private static LockOptions initializeDefaultLockOptions(final Map<String, Object> defaultSessionProperties) {
LockOptions def = new LockOptions();
LockOptionsHelper.applyPropertiesToLockOptions( defaultSessionProperties, () -> def );
return def;
} }
private static <T> EventListenerGroup<T> listeners(EventListenerRegistry elr, EventType<T> type) { private static <T> EventListenerGroup<T> listeners(EventListenerRegistry elr, EventType<T> type) {

View File

@ -145,6 +145,7 @@ import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper; import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper; import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper; import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.jpa.internal.util.LockOptionsHelper;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor; import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.loader.criteria.CriteriaLoader; import org.hibernate.loader.criteria.CriteriaLoader;
import org.hibernate.loader.custom.CustomLoader; import org.hibernate.loader.custom.CustomLoader;
@ -207,8 +208,7 @@ public final class SessionImpl
private transient LoadQueryInfluencers loadQueryInfluencers; private transient LoadQueryInfluencers loadQueryInfluencers;
// todo : (5.2) HEM always initialized this. Is that really needed? private LockOptions lockOptions;
private LockOptions lockOptions = new LockOptions();
private boolean autoClear; private boolean autoClear;
private boolean autoClose; private boolean autoClose;
@ -248,7 +248,10 @@ public final class SessionImpl
statistics.openSession(); statistics.openSession();
} }
setLockOptions( this.properties == null ? fastSessionServices.defaultSessionProperties : this.properties, this.lockOptions ); if ( this.properties != null ) {
//There might be custom properties for this session that affect the LockOptions state
LockOptionsHelper.applyPropertiesToLockOptions( this.properties, this::getLockOptionsForWrite );
}
getSession().setCacheMode( fastSessionServices.initialSessionCacheMode ); getSession().setCacheMode( fastSessionServices.initialSessionCacheMode );
// NOTE : pulse() already handles auto-join-ability correctly // NOTE : pulse() already handles auto-join-ability correctly
@ -259,9 +262,21 @@ public final class SessionImpl
} }
} }
private LockOptions getLockOptionsForRead() {
return this.lockOptions == null ? fastSessionServices.defaultLockOptions : this.lockOptions;
}
private LockOptions getLockOptionsForWrite() {
if ( this.lockOptions == null ) {
this.lockOptions = new LockOptions();
}
return this.lockOptions;
}
protected void applyQuerySettingsAndHints(Query query) { protected void applyQuerySettingsAndHints(Query query) {
if ( lockOptions.getLockMode() != LockMode.NONE ) { final LockOptions lockOptionsForRead = getLockOptionsForRead();
query.setLockMode( getLockMode( lockOptions.getLockMode() ) ); if ( lockOptionsForRead.getLockMode() != LockMode.NONE ) {
query.setLockMode( getLockMode( lockOptionsForRead.getLockMode() ) );
} }
final Object queryTimeout; final Object queryTimeout;
if ( ( queryTimeout = getSessionProperty( QueryHints.SPEC_HINT_TIMEOUT ) ) != null ) { if ( ( queryTimeout = getSessionProperty( QueryHints.SPEC_HINT_TIMEOUT ) ) != null ) {
@ -3255,57 +3270,17 @@ public final class SessionImpl
@Override @Override
public LockOptions getLockRequest(LockModeType lockModeType, Map<String, Object> properties) { public LockOptions getLockRequest(LockModeType lockModeType, Map<String, Object> properties) {
LockOptions lockOptions = new LockOptions(); LockOptions lockOptions = new LockOptions();
LockOptions.copy( this.lockOptions, lockOptions ); if ( this.lockOptions != null ) { //otherwise the default LockOptions constructor is the same as DEFAULT_LOCK_OPTIONS
LockOptions.copy( this.lockOptions, lockOptions );
}
lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) ); lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
if ( properties != null ) { if ( properties != null ) {
setLockOptions( properties, lockOptions ); LockOptionsHelper.applyPropertiesToLockOptions( properties, () -> lockOptions );
} }
return lockOptions; return lockOptions;
} }
private void setLockOptions(Map<String, Object> props, LockOptions options) {
Object lockScope = props.get( JPA_LOCK_SCOPE );
if ( lockScope instanceof String && PessimisticLockScope.valueOf( ( String ) lockScope ) == PessimisticLockScope.EXTENDED ) {
options.setScope( true );
}
else if ( lockScope instanceof PessimisticLockScope ) {
boolean extended = PessimisticLockScope.EXTENDED.equals( lockScope );
options.setScope( extended );
}
else if ( lockScope != null ) {
throw new PersistenceException( "Unable to parse " + JPA_LOCK_SCOPE + ": " + lockScope );
}
Object lockTimeout = props.get( JPA_LOCK_TIMEOUT );
int timeout = 0;
boolean timeoutSet = false;
if ( lockTimeout instanceof String ) {
timeout = Integer.parseInt( ( String ) lockTimeout );
timeoutSet = true;
}
else if ( lockTimeout instanceof Number ) {
timeout = ( (Number) lockTimeout ).intValue();
timeoutSet = true;
}
else if ( lockTimeout != null ) {
throw new PersistenceException( "Unable to parse " + JPA_LOCK_TIMEOUT + ": " + lockTimeout );
}
if ( timeoutSet ) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
options.setTimeOut( LockOptions.SKIP_LOCKED );
}
else if ( timeout < 0 ) {
options.setTimeOut( LockOptions.WAIT_FOREVER );
}
else if ( timeout == 0 ) {
options.setTimeOut( LockOptions.NO_WAIT );
}
else {
options.setTimeOut( timeout );
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -3572,7 +3547,7 @@ public final class SessionImpl
setHibernateFlushMode( ConfigurationHelper.getFlushMode( value, FlushMode.AUTO ) ); setHibernateFlushMode( ConfigurationHelper.getFlushMode( value, FlushMode.AUTO ) );
} }
else if ( JPA_LOCK_SCOPE.equals( propertyName ) || JPA_LOCK_TIMEOUT.equals( propertyName ) ) { else if ( JPA_LOCK_SCOPE.equals( propertyName ) || JPA_LOCK_TIMEOUT.equals( propertyName ) ) {
setLockOptions( properties, this.lockOptions ); LockOptionsHelper.applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite );
} }
else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( propertyName ) || JPA_SHARED_CACHE_STORE_MODE.equals( propertyName ) ) { else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( propertyName ) || JPA_SHARED_CACHE_STORE_MODE.equals( propertyName ) ) {
getSession().setCacheMode( getSession().setCacheMode(

View File

@ -0,0 +1,77 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.jpa.internal.util;
import java.util.Map;
import java.util.function.Supplier;
import javax.persistence.PersistenceException;
import javax.persistence.PessimisticLockScope;
import org.hibernate.LockOptions;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
public final class LockOptionsHelper {
private LockOptionsHelper() {
//utility class, not to be constructed
}
/**
* Applies configuration properties on a {@link LockOptions} instance, passed as a supplier
* so to make it possible to skip allocating the {@link LockOptions} instance if there's
* nothing to set.
*
* @param props The configuration properties
* @param lockOptionsSupplier The reference to the lock to modify
*/
public static void applyPropertiesToLockOptions(final Map<String, Object> props, final Supplier<LockOptions> lockOptionsSupplier) {
Object lockScope = props.get( JPA_LOCK_SCOPE );
if ( lockScope instanceof String && PessimisticLockScope.valueOf( (String) lockScope ) == PessimisticLockScope.EXTENDED ) {
lockOptionsSupplier.get().setScope( true );
}
else if ( lockScope instanceof PessimisticLockScope ) {
boolean extended = PessimisticLockScope.EXTENDED.equals( lockScope );
lockOptionsSupplier.get().setScope( extended );
}
else if ( lockScope != null ) {
throw new PersistenceException( "Unable to parse " + JPA_LOCK_SCOPE + ": " + lockScope );
}
Object lockTimeout = props.get( JPA_LOCK_TIMEOUT );
int timeout = 0;
boolean timeoutSet = false;
if ( lockTimeout instanceof String ) {
timeout = Integer.parseInt( (String) lockTimeout );
timeoutSet = true;
}
else if ( lockTimeout instanceof Number ) {
timeout = ( (Number) lockTimeout ).intValue();
timeoutSet = true;
}
else if ( lockTimeout != null ) {
throw new PersistenceException( "Unable to parse " + JPA_LOCK_TIMEOUT + ": " + lockTimeout );
}
if ( timeoutSet ) {
if ( timeout == LockOptions.SKIP_LOCKED ) {
lockOptionsSupplier.get().setTimeOut( LockOptions.SKIP_LOCKED );
}
else if ( timeout < 0 ) {
lockOptionsSupplier.get().setTimeOut( LockOptions.WAIT_FOREVER );
}
else if ( timeout == 0 ) {
lockOptionsSupplier.get().setTimeOut( LockOptions.NO_WAIT );
}
else {
lockOptionsSupplier.get().setTimeOut( timeout );
}
}
}
}