attempt to reduce allocations of LockOptions
- Sanne says we were allocating too many of these, so add a static instance of LockOptions for each LockMode - just generally rationalize the code that deals with defaulting LockOptions - change the impl of CascadingActions.LOCK because lock scope has nothing to do with cascading, and I don't see any reason why the LockOptions should not simply propagate if cascading is explicitly turned on
This commit is contained in:
parent
39bef7bc70
commit
3f7133f80b
|
@ -208,4 +208,37 @@ public enum LockMode {
|
|||
|
||||
throw new IllegalArgumentException( "Unable to interpret LockMode reference from incoming external form : " + externalForm );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an instance of {@link LockOptions} with this lock mode, and
|
||||
* all other settings defaulted.
|
||||
*/
|
||||
public LockOptions toLockOptions() {
|
||||
// we have to do this in a big switch to
|
||||
// avoid circularities in the constructor
|
||||
switch (this) {
|
||||
case NONE:
|
||||
return LockOptions.NONE;
|
||||
case READ:
|
||||
return LockOptions.READ;
|
||||
case OPTIMISTIC:
|
||||
return LockOptions.OPTIMISTIC;
|
||||
case OPTIMISTIC_FORCE_INCREMENT:
|
||||
return LockOptions.OPTIMISTIC_FORCE_INCREMENT;
|
||||
case UPGRADE_NOWAIT:
|
||||
return LockOptions.UPGRADE_NOWAIT;
|
||||
case UPGRADE_SKIPLOCKED:
|
||||
return LockOptions.UPGRADE_SKIPLOCKED;
|
||||
case PESSIMISTIC_READ:
|
||||
return LockOptions.PESSIMISTIC_READ;
|
||||
case PESSIMISTIC_WRITE:
|
||||
return LockOptions.PESSIMISTIC_WRITE;
|
||||
case PESSIMISTIC_FORCE_INCREMENT:
|
||||
return LockOptions.PESSIMISTIC_FORCE_INCREMENT;
|
||||
case WRITE:
|
||||
throw new UnsupportedOperationException("WRITE is not a valid LockMode as an argument");
|
||||
default:
|
||||
throw new IllegalStateException( "Unexpected value: " + this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,13 +55,49 @@ public class LockOptions implements Serializable {
|
|||
* Represents {@link LockMode#NONE}, to which timeout and scope are
|
||||
* not applicable.
|
||||
*/
|
||||
public static final LockOptions NONE = new LockOptions(true, LockMode.NONE);
|
||||
public static final LockOptions NONE = new LockOptions( true, LockMode.NONE );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#READ}, to which timeout and scope are
|
||||
* not applicable.
|
||||
*/
|
||||
public static final LockOptions READ = new LockOptions(true, LockMode.READ);
|
||||
public static final LockOptions READ = new LockOptions( true, LockMode.READ );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#OPTIMISTIC}.
|
||||
*/
|
||||
static final LockOptions OPTIMISTIC = new LockOptions( true, LockMode.OPTIMISTIC );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#OPTIMISTIC_FORCE_INCREMENT}, to which
|
||||
* timeout and scope are not applicable.
|
||||
*/
|
||||
static final LockOptions OPTIMISTIC_FORCE_INCREMENT = new LockOptions( true, LockMode.OPTIMISTIC_FORCE_INCREMENT );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#PESSIMISTIC_READ}.
|
||||
*/
|
||||
static final LockOptions PESSIMISTIC_READ = new LockOptions( true, LockMode.PESSIMISTIC_READ );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#PESSIMISTIC_WRITE}.
|
||||
*/
|
||||
static final LockOptions PESSIMISTIC_WRITE = new LockOptions( true, LockMode.PESSIMISTIC_WRITE );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#PESSIMISTIC_FORCE_INCREMENT}.
|
||||
*/
|
||||
static final LockOptions PESSIMISTIC_FORCE_INCREMENT = new LockOptions( true, LockMode.PESSIMISTIC_FORCE_INCREMENT );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#UPGRADE_NOWAIT}.
|
||||
*/
|
||||
static final LockOptions UPGRADE_NOWAIT = new LockOptions( true, LockMode.UPGRADE_NOWAIT );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#UPGRADE_SKIPLOCKED}.
|
||||
*/
|
||||
static final LockOptions UPGRADE_SKIPLOCKED = new LockOptions( true, LockMode.UPGRADE_SKIPLOCKED );
|
||||
|
||||
/**
|
||||
* Represents {@link LockMode#PESSIMISTIC_WRITE} with
|
||||
|
@ -69,7 +105,7 @@ public class LockOptions implements Serializable {
|
|||
* {@linkplain PessimisticLockScope#NORMAL no extension of the
|
||||
* lock to owned collections}.
|
||||
*/
|
||||
public static final LockOptions UPGRADE = new LockOptions(true, LockMode.PESSIMISTIC_WRITE);
|
||||
public static final LockOptions UPGRADE = PESSIMISTIC_WRITE;
|
||||
|
||||
/**
|
||||
* Indicates that the database should not wait at all to acquire
|
||||
|
|
|
@ -92,18 +92,7 @@ public class CascadingActions {
|
|||
LockOptions lockOptions,
|
||||
boolean isCascadeDeleteEnabled) {
|
||||
LOG.tracev( "Cascading to lock: {0}", entityName );
|
||||
LockMode lockMode = LockMode.NONE;
|
||||
LockOptions lr = new LockOptions();
|
||||
if ( lockOptions != null ) {
|
||||
lr.setTimeOut( lockOptions.getTimeOut() );
|
||||
lr.setScope( lockOptions.getScope() );
|
||||
lr.setFollowOnLocking( lockOptions.getFollowOnLocking() );
|
||||
if ( lockOptions.getScope() ) {
|
||||
lockMode = lockOptions.getLockMode();
|
||||
}
|
||||
}
|
||||
lr.setLockMode( lockMode );
|
||||
session.buildLockRequest( lr ).lock( entityName, child );
|
||||
session.lock( entityName, child, lockOptions );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -189,7 +189,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
|
|||
if ( currentLockMode.greaterThan( requestedLockMode ) ) {
|
||||
// the requested lock-mode is less restrictive than the current one
|
||||
// - pass along the current lock-mode (after accounting for WRITE)
|
||||
lockOptionsToUse = LockOptions.copy( event.getLockOptions(), new LockOptions() );
|
||||
lockOptionsToUse = event.getLockOptions().makeCopy();
|
||||
if ( currentLockMode == LockMode.WRITE
|
||||
|| currentLockMode == LockMode.PESSIMISTIC_WRITE
|
||||
|| currentLockMode == LockMode.PESSIMISTIC_READ ) {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.event.spi;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
|
||||
|
@ -16,38 +15,20 @@ import org.hibernate.LockOptions;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LoadEvent extends AbstractEvent {
|
||||
public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE;
|
||||
//Performance hotspot: avoid allocating unneeded LockOptions
|
||||
public static final LockOptions DEFAULT_LOCK_OPTIONS = new LockOptions() {
|
||||
@Override
|
||||
public LockOptions setLockMode(LockMode lockMode) {
|
||||
throw new AssertionFailure( "Should not be invoked: DEFAULT_LOCK_OPTIONS needs to be treated as immutable." );
|
||||
}
|
||||
@Override
|
||||
public LockOptions setAliasSpecificLockMode(String alias, LockMode lockMode) {
|
||||
throw new AssertionFailure( "Should not be invoked: DEFAULT_LOCK_OPTIONS needs to be treated as immutable." );
|
||||
}
|
||||
@Override
|
||||
public LockOptions setTimeOut(int timeout) {
|
||||
throw new AssertionFailure( "Should not be invoked: DEFAULT_LOCK_OPTIONS needs to be treated as immutable." );
|
||||
}
|
||||
@Override
|
||||
public LockOptions setScope(boolean scope) {
|
||||
throw new AssertionFailure( "Should not be invoked: DEFAULT_LOCK_OPTIONS needs to be treated as immutable." );
|
||||
}
|
||||
};
|
||||
// public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE;
|
||||
// public static final LockOptions DEFAULT_LOCK_OPTIONS = DEFAULT_LOCK_MODE.toLockOptions();
|
||||
|
||||
private Object entityId;
|
||||
private String entityClassName;
|
||||
private Object instanceToLoad;
|
||||
private LockOptions lockOptions;
|
||||
private final LockOptions lockOptions;
|
||||
private final boolean isAssociationFetch;
|
||||
private Object result;
|
||||
private PostLoadEvent postLoadEvent;
|
||||
private Boolean readOnly;
|
||||
|
||||
public LoadEvent(Object entityId, Object instanceToLoad, EventSource source, Boolean readOnly) {
|
||||
this( entityId, null, instanceToLoad, DEFAULT_LOCK_OPTIONS, false, source, readOnly );
|
||||
this( entityId, null, instanceToLoad, LockMode.NONE.toLockOptions(), false, source, readOnly );
|
||||
}
|
||||
|
||||
public LoadEvent(Object entityId, String entityClassName, LockMode lockMode, EventSource source, Boolean readOnly) {
|
||||
|
@ -59,7 +40,7 @@ public class LoadEvent extends AbstractEvent {
|
|||
}
|
||||
|
||||
public LoadEvent(Object entityId, String entityClassName, boolean isAssociationFetch, EventSource source, Boolean readOnly) {
|
||||
this( entityId, entityClassName, null, DEFAULT_LOCK_OPTIONS, isAssociationFetch, source, readOnly );
|
||||
this( entityId, entityClassName, null, LockMode.NONE.toLockOptions(), isAssociationFetch, source, readOnly );
|
||||
}
|
||||
|
||||
private LoadEvent(
|
||||
|
@ -74,7 +55,7 @@ public class LoadEvent extends AbstractEvent {
|
|||
entityId,
|
||||
entityClassName,
|
||||
instanceToLoad,
|
||||
lockMode == DEFAULT_LOCK_MODE ? DEFAULT_LOCK_OPTIONS : new LockOptions().setLockMode( lockMode ),
|
||||
lockMode.toLockOptions(),
|
||||
isAssociationFetch,
|
||||
source,
|
||||
readOnly
|
||||
|
@ -100,7 +81,7 @@ public class LoadEvent extends AbstractEvent {
|
|||
throw new IllegalArgumentException("Invalid lock mode for loading");
|
||||
}
|
||||
else if ( lockOptions.getLockMode() == null ) {
|
||||
lockOptions.setLockMode(DEFAULT_LOCK_MODE);
|
||||
lockOptions.setLockMode( LockMode.NONE );
|
||||
}
|
||||
|
||||
this.entityId = entityId;
|
||||
|
@ -148,37 +129,10 @@ public class LoadEvent extends AbstractEvent {
|
|||
return lockOptions.getLockMode();
|
||||
}
|
||||
|
||||
public void setLockMode(LockMode lockMode) {
|
||||
if ( lockMode != lockOptions.getLockMode() ) {
|
||||
writingOnLockOptions();
|
||||
this.lockOptions.setLockMode( lockMode );
|
||||
}
|
||||
}
|
||||
|
||||
private void writingOnLockOptions() {
|
||||
if ( lockOptions == DEFAULT_LOCK_OPTIONS ) {
|
||||
this.lockOptions = new LockOptions();
|
||||
}
|
||||
}
|
||||
|
||||
public void setLockTimeout(int timeout) {
|
||||
if ( timeout != lockOptions.getTimeOut() ) {
|
||||
writingOnLockOptions();
|
||||
this.lockOptions.setTimeOut( timeout );
|
||||
}
|
||||
}
|
||||
|
||||
public int getLockTimeout() {
|
||||
return this.lockOptions.getTimeOut();
|
||||
}
|
||||
|
||||
public void setLockScope(boolean cascade) {
|
||||
if ( lockOptions.getScope() != cascade ) {
|
||||
writingOnLockOptions();
|
||||
this.lockOptions.setScope( cascade );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getLockScope() {
|
||||
return this.lockOptions.getScope();
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ public class LockEvent extends AbstractEvent {
|
|||
public LockEvent(Object object, LockMode lockMode, EventSource source) {
|
||||
super(source);
|
||||
this.object = object;
|
||||
this.lockOptions = new LockOptions().setLockMode(lockMode);
|
||||
this.lockOptions = lockMode.toLockOptions();
|
||||
}
|
||||
|
||||
public LockEvent(Object object, LockOptions lockOptions, EventSource source) {
|
||||
|
@ -58,24 +58,12 @@ public class LockEvent extends AbstractEvent {
|
|||
return lockOptions.getLockMode();
|
||||
}
|
||||
|
||||
public void setLockMode(LockMode lockMode) {
|
||||
this.lockOptions.setLockMode(lockMode);
|
||||
}
|
||||
|
||||
public void setLockTimeout(int timeout) {
|
||||
this.lockOptions.setTimeOut(timeout);
|
||||
}
|
||||
|
||||
public int getLockTimeout() {
|
||||
return this.lockOptions.getTimeOut();
|
||||
}
|
||||
|
||||
public void setLockScope(boolean cascade) {
|
||||
this.lockOptions.setScope(cascade);
|
||||
return lockOptions.getTimeOut();
|
||||
}
|
||||
|
||||
public boolean getLockScope() {
|
||||
return this.lockOptions.getScope();
|
||||
return lockOptions.getScope();
|
||||
}
|
||||
|
||||
public String getEntityName() {
|
||||
|
|
|
@ -31,7 +31,7 @@ public class ResolveNaturalIdEvent extends AbstractEvent {
|
|||
private Object entityId;
|
||||
|
||||
public ResolveNaturalIdEvent(Map<String, Object> naturalIdValues, EntityPersister entityPersister, EventSource source) {
|
||||
this( naturalIdValues, entityPersister, new LockOptions(), source );
|
||||
this( naturalIdValues, entityPersister, LockOptions.NONE, source );
|
||||
}
|
||||
|
||||
public ResolveNaturalIdEvent(
|
||||
|
|
|
@ -991,29 +991,7 @@ public class SessionImpl
|
|||
|
||||
@Override
|
||||
public void load(Object object, Object id) throws HibernateException {
|
||||
LoadEvent event = loadEvent;
|
||||
loadEvent = null;
|
||||
if ( event == null ) {
|
||||
event = new LoadEvent( id, object, this, getReadOnlyFromLoadQueryInfluencers() );
|
||||
}
|
||||
else {
|
||||
event.setEntityClassName( null );
|
||||
event.setEntityId( id );
|
||||
event.setInstanceToLoad( object );
|
||||
event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE );
|
||||
event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() );
|
||||
event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() );
|
||||
}
|
||||
|
||||
fireLoad( event, LoadEventListener.RELOAD );
|
||||
|
||||
if ( loadEvent == null ) {
|
||||
event.setEntityClassName( null );
|
||||
event.setEntityId( null );
|
||||
event.setInstanceToLoad( null );
|
||||
event.setResult( null );
|
||||
loadEvent = event;
|
||||
}
|
||||
fireLoad( new LoadEvent( id, object, this, getReadOnlyFromLoadQueryInfluencers() ), LoadEventListener.RELOAD );
|
||||
}
|
||||
|
||||
@Override @Deprecated
|
||||
|
@ -1054,13 +1032,7 @@ public class SessionImpl
|
|||
event = recycleEventInstance( event, id, entityName );
|
||||
fireLoadNoChecks( event, LoadEventListener.IMMEDIATE_LOAD );
|
||||
Object result = event.getResult();
|
||||
if ( loadEvent == null ) {
|
||||
event.setEntityClassName( null );
|
||||
event.setEntityId( null );
|
||||
event.setInstanceToLoad( null );
|
||||
event.setResult( null );
|
||||
loadEvent = event;
|
||||
}
|
||||
finishWithEventInstance( event );
|
||||
if ( result instanceof HibernateProxy ) {
|
||||
return ( (HibernateProxy) result ).getHibernateLazyInitializer().getImplementation();
|
||||
}
|
||||
|
@ -1073,6 +1045,7 @@ public class SessionImpl
|
|||
Object id,
|
||||
boolean eager,
|
||||
boolean nullable) {
|
||||
final LoadType type = internalLoadType( eager, nullable );
|
||||
final EffectiveEntityGraph effectiveEntityGraph = getLoadQueryInfluencers().getEffectiveEntityGraph();
|
||||
final GraphSemantic semantic = effectiveEntityGraph.getSemantic();
|
||||
final RootGraphImplementor<?> graph = effectiveEntityGraph.getGraph();
|
||||
|
@ -1084,38 +1057,16 @@ public class SessionImpl
|
|||
effectiveEntityGraph.clear();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
final LoadType type;
|
||||
if ( nullable ) {
|
||||
type = LoadEventListener.INTERNAL_LOAD_NULLABLE;
|
||||
}
|
||||
else {
|
||||
type = eager
|
||||
? LoadEventListener.INTERNAL_LOAD_EAGER
|
||||
: LoadEventListener.INTERNAL_LOAD_LAZY;
|
||||
}
|
||||
|
||||
LoadEvent event = loadEvent;
|
||||
loadEvent = null;
|
||||
|
||||
event = recycleEventInstance( event, id, entityName );
|
||||
|
||||
fireLoadNoChecks( event, type );
|
||||
|
||||
Object result = event.getResult();
|
||||
|
||||
if ( !nullable ) {
|
||||
UnresolvableObjectException.throwIfNull( result, id, entityName );
|
||||
}
|
||||
|
||||
if ( loadEvent == null ) {
|
||||
event.setEntityClassName( null );
|
||||
event.setEntityId( null );
|
||||
event.setInstanceToLoad( null );
|
||||
event.setResult( null );
|
||||
loadEvent = event;
|
||||
}
|
||||
finishWithEventInstance( event );
|
||||
return result;
|
||||
}
|
||||
finally {
|
||||
|
@ -1125,6 +1076,17 @@ public class SessionImpl
|
|||
}
|
||||
}
|
||||
|
||||
private static LoadType internalLoadType(boolean eager, boolean nullable) {
|
||||
if ( nullable ) {
|
||||
return LoadEventListener.INTERNAL_LOAD_NULLABLE;
|
||||
}
|
||||
else {
|
||||
return eager
|
||||
? LoadEventListener.INTERNAL_LOAD_EAGER
|
||||
: LoadEventListener.INTERNAL_LOAD_LAZY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to avoid creating many new instances of LoadEvent: it's an allocation hot spot.
|
||||
*/
|
||||
|
@ -1136,13 +1098,20 @@ public class SessionImpl
|
|||
event.setEntityClassName( entityName );
|
||||
event.setEntityId( id );
|
||||
event.setInstanceToLoad( null );
|
||||
event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE );
|
||||
event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() );
|
||||
event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() );
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
private void finishWithEventInstance(LoadEvent event) {
|
||||
if ( loadEvent == null ) {
|
||||
event.setEntityClassName( null );
|
||||
event.setEntityId( null );
|
||||
event.setInstanceToLoad( null );
|
||||
event.setResult( null );
|
||||
loadEvent = event;
|
||||
}
|
||||
}
|
||||
|
||||
@Override @Deprecated
|
||||
public <T> T load(Class<T> entityClass, Object id, LockMode lockMode) throws HibernateException {
|
||||
return this.byId( entityClass ).with( new LockOptions( lockMode ) ).getReference( id );
|
||||
|
@ -2123,9 +2092,9 @@ public class SessionImpl
|
|||
private class LockRequestImpl implements LockRequest {
|
||||
private final LockOptions lockOptions;
|
||||
|
||||
private LockRequestImpl(LockOptions lo) {
|
||||
lockOptions = new LockOptions();
|
||||
LockOptions.copy( lo, lockOptions );
|
||||
private LockRequestImpl(LockOptions lockOptions) {
|
||||
this.lockOptions = new LockOptions();
|
||||
LockOptions.copy( lockOptions, this.lockOptions );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4356,7 +4356,7 @@ public abstract class AbstractEntityPersister
|
|||
*/
|
||||
@Override
|
||||
public Object load(Object id, Object optionalObject, LockMode lockMode, SharedSessionContractImplementor session) {
|
||||
return load( id, optionalObject, new LockOptions().setLockMode( lockMode ), session );
|
||||
return load( id, optionalObject, lockMode.toLockOptions(), session );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -309,8 +309,8 @@ public abstract class AbstractQuery<R>
|
|||
}
|
||||
|
||||
if ( getLockOptions().getScope() ) {
|
||||
hints.put( HINT_SPEC_LOCK_SCOPE, getLockOptions().getScope() );
|
||||
hints.put( HINT_JAVAEE_LOCK_SCOPE, getLockOptions().getScope() );
|
||||
hints.put( HINT_SPEC_LOCK_SCOPE, getLockOptions().getLockScope() );
|
||||
hints.put( HINT_JAVAEE_LOCK_SCOPE, getLockOptions().getLockScope() );
|
||||
}
|
||||
|
||||
if ( getLockOptions().hasAliasSpecificLockModes() ) {
|
||||
|
|
|
@ -37,7 +37,7 @@ public abstract class QueryOptionsAdapter implements QueryOptions {
|
|||
|
||||
@Override
|
||||
public LockOptions getLockOptions() {
|
||||
return new LockOptions();
|
||||
return LockOptions.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -304,7 +304,7 @@ public class MatchingIdSelectionHelper {
|
|||
,
|
||||
executionContext.getSession()
|
||||
);
|
||||
final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions();
|
||||
final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions().makeCopy();
|
||||
final LockMode lockMode = lockOptions.getLockMode();
|
||||
// Acquire a WRITE lock for the rows that are about to be modified
|
||||
lockOptions.setLockMode( LockMode.WRITE );
|
||||
|
|
|
@ -119,9 +119,10 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess {
|
|||
|
||||
executionContext.getCallback().registerAfterLoadAction(
|
||||
(session, entity, persister) -> {
|
||||
( (Session) session ).buildLockRequest( lockOptionsToUse ).lock(
|
||||
( (Session) session ).lock(
|
||||
persister.getEntityName(),
|
||||
entity
|
||||
entity,
|
||||
lockOptionsToUse
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue