From c1fbee79ae01fa2344e521c79e55a25a3436590a Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 9 Mar 2018 14:09:00 +0000 Subject: [PATCH] HHH-12376 Apply some ThreadLocal optimisations made possible by new Java 8 API --- .../internal/ManagedSessionContext.java | 6 +- .../internal/ThreadLocalSessionContext.java | 62 +++++++++---------- .../PooledLoThreadLocalOptimizer.java | 14 ++--- 3 files changed, 35 insertions(+), 47 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/context/internal/ManagedSessionContext.java b/hibernate-core/src/main/java/org/hibernate/context/internal/ManagedSessionContext.java index 2db54a542c..cd954eb172 100644 --- a/hibernate-core/src/main/java/org/hibernate/context/internal/ManagedSessionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/context/internal/ManagedSessionContext.java @@ -103,12 +103,12 @@ public class ManagedSessionContext extends AbstractCurrentSessionContext { } private static Session existingSession(SessionFactory factory) { - final Map sessionMap = sessionMap(); + final Map sessionMap = sessionMap(); if ( sessionMap == null ) { return null; } else { - return (Session) sessionMap.get( factory ); + return sessionMap.get( factory ); } } @@ -129,7 +129,7 @@ public class ManagedSessionContext extends AbstractCurrentSessionContext { final Map sessionMap = sessionMap( false ); if ( sessionMap != null ) { if ( sessionMap.isEmpty() ) { - CONTEXT_TL.set( null ); + CONTEXT_TL.remove(); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/context/internal/ThreadLocalSessionContext.java b/hibernate-core/src/main/java/org/hibernate/context/internal/ThreadLocalSessionContext.java index c9387a14df..85cc4334dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/context/internal/ThreadLocalSessionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/context/internal/ThreadLocalSessionContext.java @@ -23,6 +23,7 @@ import org.hibernate.ConnectionReleaseMode; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; +import org.hibernate.Transaction; import org.hibernate.context.spi.AbstractCurrentSessionContext; import org.hibernate.engine.jdbc.LobCreationContext; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -54,6 +55,7 @@ import org.jboss.logging.Logger; * subclassing (for long-running session scenarios, for example). * * @author Steve Ebersole + * @author Sanne Grinovero */ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext { private static final CoreMessageLogger LOG = Logger.getMessageLogger( @@ -74,7 +76,7 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext { * the possibility for multiple SessionFactory instances being used during execution * of the given thread. */ - private static final ThreadLocal CONTEXT_TL = new ThreadLocal(); + private static final ThreadLocal> CONTEXT_TL = ThreadLocal.withInitial( HashMap::new ); /** * Constructs a ThreadLocal @@ -107,12 +109,10 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext { private boolean needsWrapping(Session session) { // try to make sure we don't wrap and already wrapped session - if ( session != null ) { - if ( Proxy.isProxyClass( session.getClass() ) ) { - final InvocationHandler invocationHandler = Proxy.getInvocationHandler( session ); - if ( invocationHandler != null && TransactionProtectionWrapper.class.isInstance( invocationHandler ) ) { - return false; - } + if ( Proxy.isProxyClass( session.getClass() ) ) { + final InvocationHandler invocationHandler = Proxy.getInvocationHandler( session ); + if ( invocationHandler != null && TransactionProtectionWrapper.class.isInstance( invocationHandler ) ) { + return false; } } return true; @@ -194,28 +194,32 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext { */ public static void bind(org.hibernate.Session session) { final SessionFactory factory = session.getSessionFactory(); - cleanupAnyOrphanedSession( factory ); doBind( session, factory ); } - private static void cleanupAnyOrphanedSession(SessionFactory factory) { - final Session orphan = doUnbind( factory, false ); + private static void terminateOrphanedSession(Session orphan) { if ( orphan != null ) { LOG.alreadySessionBound(); try { - if ( orphan.getTransaction() != null && orphan.getTransaction().getStatus() == TransactionStatus.ACTIVE ) { + final Transaction orphanTransaction = orphan.getTransaction(); + if ( orphanTransaction != null && orphanTransaction.getStatus() == TransactionStatus.ACTIVE ) { try { - orphan.getTransaction().rollback(); + orphanTransaction.rollback(); } catch( Throwable t ) { LOG.debug( "Unable to rollback transaction for orphaned session", t ); } } - orphan.close(); } - catch( Throwable t ) { - LOG.debug( "Unable to close orphaned session", t ); + finally { + try { + orphan.close(); + } + catch( Throwable t ) { + LOG.debug( "Unable to close orphaned session", t ); + } } + } } @@ -230,35 +234,25 @@ public class ThreadLocalSessionContext extends AbstractCurrentSessionContext { } private static Session existingSession(SessionFactory factory) { - final Map sessionMap = sessionMap(); - if ( sessionMap == null ) { - return null; - } - return (Session) sessionMap.get( factory ); + return sessionMap().get( factory ); } - protected static Map sessionMap() { + protected static Map sessionMap() { return CONTEXT_TL.get(); } @SuppressWarnings({"unchecked"}) private static void doBind(org.hibernate.Session session, SessionFactory factory) { - Map sessionMap = sessionMap(); - if ( sessionMap == null ) { - sessionMap = new HashMap(); - CONTEXT_TL.set( sessionMap ); - } - sessionMap.put( factory, session ); + Session orphanedPreviousSession = sessionMap().put( factory, session ); + terminateOrphanedSession( orphanedPreviousSession ); } private static Session doUnbind(SessionFactory factory, boolean releaseMapIfEmpty) { - Session session = null; - final Map sessionMap = sessionMap(); - if ( sessionMap != null ) { - session = (Session) sessionMap.remove( factory ); - if ( releaseMapIfEmpty && sessionMap.isEmpty() ) { - CONTEXT_TL.set( null ); - } + final Map sessionMap = sessionMap(); + final Session session = sessionMap.remove( factory ); + if ( releaseMapIfEmpty && sessionMap.isEmpty() ) { + //Do not use set(null) as it would prevent the initialValue to be invoked again in case of need. + CONTEXT_TL.remove(); } return session; } diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java index 03525773b4..e54af6d148 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java @@ -56,10 +56,9 @@ public class PooledLoThreadLocalOptimizer extends AbstractOptimizer { @Override public Serializable generate(AccessCallback callback) { - GenerationState local = null; if ( callback.getTenantIdentifier() == null ) { - local = localAssignedIds.get(); - if ( local != null && local.value.lt( local.upperLimitValue ) ) { + final GenerationState local = localAssignedIds.get(); + if ( local.value != null && local.value.lt( local.upperLimitValue ) ) { return local.value.makeValueThenIncrement(); } } @@ -82,16 +81,11 @@ public class PooledLoThreadLocalOptimizer extends AbstractOptimizer { } private Map tenantSpecificState; - private final ThreadLocal localAssignedIds = new ThreadLocal(); + private final ThreadLocal localAssignedIds = ThreadLocal.withInitial( GenerationState::new ); private GenerationState locateGenerationState(String tenantIdentifier) { if ( tenantIdentifier == null ) { - GenerationState noTenantState = localAssignedIds.get(); - if ( noTenantState == null ) { - noTenantState = new GenerationState(); - localAssignedIds.set(noTenantState); - } - return noTenantState; + return localAssignedIds.get(); } else { GenerationState state;