From 5eaa1498df0f8f5f7f00515fb9bb2960b2ac489b Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 9 Aug 2019 10:28:18 +0100 Subject: [PATCH] HHH-13565 Session opening efficiency: introduce FastSessionServices and design for shared services among sessions --- .../AbstractSharedSessionContract.java | 3 + .../internal/FastSessionServices.java | 171 ++++++++++++++++++ .../internal/SessionFactoryImpl.java | 12 ++ .../org/hibernate/internal/SessionImpl.java | 62 +++---- 4 files changed, 209 insertions(+), 39 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index bf37e43d55..4cc33fa7ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -116,6 +116,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont private transient SessionFactoryImpl factory; private final String tenantIdentifier; + protected transient FastSessionServices fastSessionServices; private UUID sessionIdentifier; private transient JdbcConnectionAccess jdbcConnectionAccess; @@ -154,6 +155,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreationOptions options) { this.factory = factory; + this.fastSessionServices = factory.getFastSessionServices(); this.cacheTransactionSync = factory.getCache().getRegionFactory().createTransactionContext( this ); this.disallowOutOfTransactionUpdateOperations = !factory.getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations(); @@ -1226,6 +1228,7 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound // -- see above factory = SessionFactoryImpl.deserialize( ois ); + fastSessionServices = factory.getFastSessionServices(); jdbcSessionContext = new JdbcSessionContextImpl( this, (StatementInspector) ois.readObject() ); jdbcCoordinator = JdbcCoordinatorImpl.deserialize( ois, this ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java new file mode 100644 index 0000000000..020d05c7e1 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java @@ -0,0 +1,171 @@ +/* + * 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 . + */ +package org.hibernate.internal; + +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.AutoFlushEventListener; +import org.hibernate.event.spi.ClearEventListener; +import org.hibernate.event.spi.DeleteEventListener; +import org.hibernate.event.spi.DirtyCheckEventListener; +import org.hibernate.event.spi.EventType; +import org.hibernate.event.spi.EvictEventListener; +import org.hibernate.event.spi.FlushEventListener; +import org.hibernate.event.spi.InitializeCollectionEventListener; +import org.hibernate.event.spi.LoadEventListener; +import org.hibernate.event.spi.LockEventListener; +import org.hibernate.event.spi.MergeEventListener; +import org.hibernate.event.spi.PersistEventListener; +import org.hibernate.event.spi.RefreshEventListener; +import org.hibernate.event.spi.ReplicateEventListener; +import org.hibernate.event.spi.ResolveNaturalIdEventListener; +import org.hibernate.event.spi.SaveOrUpdateEventListener; +import org.hibernate.service.spi.ServiceRegistryImplementor; + +import java.util.Objects; + +/** + * Internal component. + * + * Collects any components that any Session implementation will likely need + * for faster access and reduced allocations. + * Conceptually this acts as an immutable caching intermediary between Session + * and SessionFactory. + * Designed to be immutable, and shared across Session instances. + * + * Assumes to be created infrequently, possibly only once per SessionFactory. + * + * If the Session is requiring to retrieve (or compute) anything from the SessionFactory, + * and this computation would result in the same outcome for any Session created on + * this same SessionFactory, then it belongs in a final field of this class. + * + * Finally, consider also limiting the size of each Session: some fields could be good + * candidates to be replaced with access via this object. + * + * @author Sanne Grinovero + */ +final class FastSessionServices { + + private final Iterable clearEventListeners; + private final Iterable saveUpdateEventListeners; + private final Iterable evictEventListeners; + private final Iterable saveEventListeners; + private final Iterable updateEventListeners; + private final Iterable lockEventListeners; + private final Iterable persistEventListeners; + private final Iterable persistOnFlushEventListeners; + private final Iterable mergeEventListeners; + private final Iterable deleteEventListeners; + private final Iterable loadEventListeners; + private final Iterable refreshEventListeners; + private final Iterable replicateEventListeners; + private final Iterable autoFlushEventListeners; + private final Iterable dirtyCheckEventListeners; + private final Iterable flushEventListeners; + private final Iterable initCollectionEventListeners; + private final Iterable resolveNaturalIdEventListeners; + + FastSessionServices(SessionFactoryImpl sf) { + Objects.requireNonNull( sf ); + final ServiceRegistryImplementor sr = sf.getServiceRegistry(); + final EventListenerRegistry eventListenerRegistry = sr.getService( EventListenerRegistry.class ); + this.clearEventListeners = listeners( eventListenerRegistry, EventType.CLEAR ); + this.saveUpdateEventListeners = listeners( eventListenerRegistry, EventType.SAVE_UPDATE ); + this.evictEventListeners = listeners( eventListenerRegistry, EventType.EVICT ); + this.saveEventListeners = listeners( eventListenerRegistry, EventType.SAVE ); + this.updateEventListeners = listeners( eventListenerRegistry, EventType.UPDATE ); + this.lockEventListeners = listeners( eventListenerRegistry, EventType.LOCK ); + this.persistEventListeners = listeners( eventListenerRegistry, EventType.PERSIST ); + this.persistOnFlushEventListeners = listeners( eventListenerRegistry, EventType.PERSIST_ONFLUSH ); + this.mergeEventListeners = listeners( eventListenerRegistry, EventType.MERGE ); + this.deleteEventListeners = listeners( eventListenerRegistry, EventType.DELETE ); + this.loadEventListeners = listeners( eventListenerRegistry, EventType.LOAD ); + this.refreshEventListeners = listeners( eventListenerRegistry, EventType.REFRESH ); + this.replicateEventListeners = listeners( eventListenerRegistry, EventType.REPLICATE ); + this.autoFlushEventListeners = listeners( eventListenerRegistry, EventType.AUTO_FLUSH ); + this.dirtyCheckEventListeners = listeners( eventListenerRegistry, EventType.DIRTY_CHECK ); + this.flushEventListeners = listeners( eventListenerRegistry, EventType.FLUSH ); + this.initCollectionEventListeners = listeners( eventListenerRegistry, EventType.INIT_COLLECTION ); + this.resolveNaturalIdEventListeners = listeners( eventListenerRegistry, EventType.RESOLVE_NATURAL_ID ); + } + + Iterable getClearEventListeners() { + return clearEventListeners; + } + + Iterable getEvictEventListeners() { + return this.evictEventListeners; + } + + Iterable getDirtyCheckEventListeners() { + return this.dirtyCheckEventListeners; + } + + Iterable getSaveUpdateEventListeners() { + return this.saveUpdateEventListeners; + } + + Iterable getSaveEventListeners() { + return this.saveEventListeners; + } + + Iterable getUpdateEventListeners() { + return this.updateEventListeners; + } + + Iterable getLockEventListeners() { + return this.lockEventListeners; + } + + Iterable getPersistEventListeners() { + return persistEventListeners; + } + + Iterable getFlushEventListeners() { + return flushEventListeners; + } + + Iterable getPersistOnFlushEventListeners() { + return persistOnFlushEventListeners; + } + + Iterable getInitCollectionEventListeners() { + return initCollectionEventListeners; + } + + Iterable getLoadEventListeners() { + return loadEventListeners; + } + + Iterable getMergeEventListeners() { + return mergeEventListeners; + } + + Iterable getRefreshEventListeners() { + return refreshEventListeners; + } + + Iterable getDeleteEventListeners() { + return deleteEventListeners; + } + + Iterable getAutoFlushEventListeners() { + return autoFlushEventListeners; + } + + Iterable getReplicateEventListeners() { + return replicateEventListeners; + } + + Iterable getResolveNaturalIdEventListeners() { + return resolveNaturalIdEventListeners; + } + + private static Iterable listeners(EventListenerRegistry elr, EventType type) { + return elr.getEventListenerGroup( type ).listeners(); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index d311b4d18a..5af883fcf4 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -197,6 +197,8 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor { private final transient TypeHelper typeHelper; + private final transient FastSessionServices fastSessionServices; + public SessionFactoryImpl( final MetadataImplementor metadata, SessionFactoryOptions options) { @@ -375,6 +377,8 @@ public void sessionFactoryClosed(SessionFactory factory) { fetchProfiles.put( fetchProfile.getName(), fetchProfile ); } + this.fastSessionServices = new FastSessionServices( this ); + this.observer.sessionFactoryCreated( this ); SessionFactoryRegistry.INSTANCE.addSessionFactory( @@ -1645,4 +1649,12 @@ private void logIfEmptyCompositesEnabled(Map props ) { LOG.emptyCompositesEnabled(); } } + + /** + * @return the FastSessionServices for this SessionFactory. + */ + FastSessionServices getFastSessionServices() { + return this.fastSessionServices; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index f7b17e2bcb..f2e1e0db2c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -96,8 +96,6 @@ import org.hibernate.engine.spi.TypedValue; import org.hibernate.engine.transaction.spi.TransactionImplementor; import org.hibernate.engine.transaction.spi.TransactionObserver; -import org.hibernate.event.service.spi.EventListenerGroup; -import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.AutoFlushEvent; import org.hibernate.event.spi.AutoFlushEventListener; import org.hibernate.event.spi.ClearEvent; @@ -107,7 +105,6 @@ import org.hibernate.event.spi.DirtyCheckEvent; import org.hibernate.event.spi.DirtyCheckEventListener; import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.EvictEvent; import org.hibernate.event.spi.EvictEventListener; import org.hibernate.event.spi.FlushEvent; @@ -234,7 +231,6 @@ public final class SessionImpl private transient boolean discardOnClose; private transient TransactionObserver transactionObserver; - private transient EventListenerRegistry eventListenerRegistry; public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { super( factory, options ); @@ -355,7 +351,7 @@ private void internalClear() { actionQueue.clear(); final ClearEvent event = new ClearEvent( this ); - for ( ClearEventListener listener : listeners( EventType.CLEAR ) ) { + for ( ClearEventListener listener : fastSessionServices.getClearEventListeners() ) { listener.onClear( event ); } } @@ -633,24 +629,12 @@ private void fireSaveOrUpdate(SaveOrUpdateEvent event) { checkOpen(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); - for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE_UPDATE ) ) { + for ( SaveOrUpdateEventListener listener : fastSessionServices.getSaveUpdateEventListeners() ) { listener.onSaveOrUpdate( event ); } checkNoUnresolvedActionsAfterOperation(); } - private Iterable listeners(EventType type) { - return eventListenerGroup( type ).listeners(); - } - - private EventListenerGroup eventListenerGroup(EventType type) { - if ( this.eventListenerRegistry == null ) { - this.eventListenerRegistry = getFactory().getServiceRegistry().getService( EventListenerRegistry.class ); - } - return eventListenerRegistry.getEventListenerGroup( type ); - } - - // save() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override @@ -667,7 +651,7 @@ private Serializable fireSave(SaveOrUpdateEvent event) { checkOpen(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); - for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE ) ) { + for ( SaveOrUpdateEventListener listener : fastSessionServices.getSaveEventListeners() ) { listener.onSaveOrUpdate( event ); } checkNoUnresolvedActionsAfterOperation(); @@ -691,7 +675,7 @@ private void fireUpdate(SaveOrUpdateEvent event) { checkOpen(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); - for ( SaveOrUpdateEventListener listener : listeners( EventType.UPDATE ) ) { + for ( SaveOrUpdateEventListener listener : fastSessionServices.getUpdateEventListeners() ) { listener.onSaveOrUpdate( event ); } checkNoUnresolvedActionsAfterOperation(); @@ -726,7 +710,7 @@ private void fireLock(Object object, LockOptions options) { private void fireLock(LockEvent event) { checkOpen(); pulseTransactionCoordinator(); - for ( LockEventListener listener : listeners( EventType.LOCK ) ) { + for ( LockEventListener listener : fastSessionServices.getLockEventListeners() ) { listener.onLock( event ); } delayedAfterCompletion(); @@ -758,7 +742,7 @@ private void firePersist(PersistEvent event) { checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); - for ( PersistEventListener listener : listeners( EventType.PERSIST ) ) { + for ( PersistEventListener listener : fastSessionServices.getPersistEventListeners() ) { listener.onPersist( event ); } } @@ -782,7 +766,7 @@ private void firePersist(Map copiedAlready, PersistEvent event) { pulseTransactionCoordinator(); try { - for ( PersistEventListener listener : listeners( EventType.PERSIST ) ) { + for ( PersistEventListener listener : fastSessionServices.getPersistEventListeners() ) { listener.onPersist( event, copiedAlready ); } } @@ -818,7 +802,7 @@ public void persistOnFlush(String entityName, Object object, Map copiedAlready) private void firePersistOnFlush(Map copiedAlready, PersistEvent event) { checkOpenOrWaitingForAutoClose(); pulseTransactionCoordinator(); - for ( PersistEventListener listener : listeners( EventType.PERSIST_ONFLUSH ) ) { + for ( PersistEventListener listener : fastSessionServices.getPersistOnFlushEventListeners() ) { listener.onPersist( event, copiedAlready ); } delayedAfterCompletion(); @@ -828,7 +812,7 @@ private void firePersistOnFlush(PersistEvent event) { checkOpen(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); - for ( PersistEventListener listener : listeners( EventType.PERSIST_ONFLUSH ) ) { + for ( PersistEventListener listener : fastSessionServices.getPersistOnFlushEventListeners() ) { listener.onPersist( event ); } checkNoUnresolvedActionsAfterOperation(); @@ -859,7 +843,7 @@ private Object fireMerge(MergeEvent event) { try { checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); - for ( MergeEventListener listener : listeners( EventType.MERGE ) ) { + for ( MergeEventListener listener : fastSessionServices.getMergeEventListeners() ) { listener.onMerge( event ); } checkNoUnresolvedActionsAfterOperation(); @@ -881,7 +865,7 @@ private Object fireMerge(MergeEvent event) { private void fireMerge(Map copiedAlready, MergeEvent event) { try { pulseTransactionCoordinator(); - for ( MergeEventListener listener : listeners( EventType.MERGE ) ) { + for ( MergeEventListener listener : fastSessionServices.getMergeEventListeners() ) { listener.onMerge( event, copiedAlready ); } } @@ -971,7 +955,7 @@ private void logRemoveOrphanBeforeUpdates(String timing, String entityName, Obje private void fireDelete(DeleteEvent event) { try{ pulseTransactionCoordinator(); - for ( DeleteEventListener listener : listeners( EventType.DELETE ) ) { + for ( DeleteEventListener listener : fastSessionServices.getDeleteEventListeners() ) { listener.onDelete( event ); } } @@ -993,7 +977,7 @@ private void fireDelete(DeleteEvent event) { private void fireDelete(DeleteEvent event, Set transientEntities) { try{ pulseTransactionCoordinator(); - for ( DeleteEventListener listener : listeners( EventType.DELETE ) ) { + for ( DeleteEventListener listener : fastSessionServices.getDeleteEventListeners() ) { listener.onDelete( event, transientEntities ); } } @@ -1270,7 +1254,7 @@ private void fireLoad(LoadEvent event, LoadType loadType) { // it seems they prevent these hot methods from being inlined. private void fireLoadNoChecks(LoadEvent event, LoadType loadType) { pulseTransactionCoordinator(); - for ( LoadEventListener listener : listeners( EventType.LOAD ) ) { + for ( LoadEventListener listener : fastSessionServices.getLoadEventListeners() ) { listener.onLoad( event, loadType ); } } @@ -1278,7 +1262,7 @@ private void fireLoadNoChecks(LoadEvent event, LoadType loadType) { private void fireResolveNaturalId(ResolveNaturalIdEvent event) { checkOpenOrWaitingForAutoClose(); pulseTransactionCoordinator(); - for ( ResolveNaturalIdEventListener listener : listeners( EventType.RESOLVE_NATURAL_ID ) ) { + for ( ResolveNaturalIdEventListener listener : fastSessionServices.getResolveNaturalIdEventListeners() ) { listener.onResolveNaturalId( event ); } delayedAfterCompletion(); @@ -1338,7 +1322,7 @@ private void fireRefresh(RefreshEvent event) { } } pulseTransactionCoordinator(); - for ( RefreshEventListener listener : listeners( EventType.REFRESH ) ) { + for ( RefreshEventListener listener : fastSessionServices.getRefreshEventListeners() ) { listener.onRefresh( event ); } } @@ -1359,7 +1343,7 @@ private void fireRefresh(RefreshEvent event) { private void fireRefresh(Map refreshedAlready, RefreshEvent event) { try { pulseTransactionCoordinator(); - for ( RefreshEventListener listener : listeners( EventType.REFRESH ) ) { + for ( RefreshEventListener listener : fastSessionServices.getRefreshEventListeners() ) { listener.onRefresh( event, refreshedAlready ); } } @@ -1388,7 +1372,7 @@ public void replicate(String entityName, Object obj, ReplicationMode replication private void fireReplicate(ReplicateEvent event) { checkOpen(); pulseTransactionCoordinator(); - for ( ReplicateEventListener listener : listeners( EventType.REPLICATE ) ) { + for ( ReplicateEventListener listener : fastSessionServices.getReplicateEventListeners() ) { listener.onReplicate( event ); } delayedAfterCompletion(); @@ -1409,7 +1393,7 @@ public void evict(Object object) throws HibernateException { private void fireEvict(EvictEvent event) { checkOpen(); pulseTransactionCoordinator(); - for ( EvictEventListener listener : listeners( EventType.EVICT ) ) { + for ( EvictEventListener listener : fastSessionServices.getEvictEventListeners() ) { listener.onEvict( event ); } delayedAfterCompletion(); @@ -1426,7 +1410,7 @@ protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException return false; } AutoFlushEvent event = new AutoFlushEvent( querySpaces, this ); - for ( AutoFlushEventListener listener : listeners( EventType.AUTO_FLUSH ) ) { + for ( AutoFlushEventListener listener : fastSessionServices.getAutoFlushEventListeners() ) { listener.onAutoFlush( event ); } return event.isFlushRequired(); @@ -1442,7 +1426,7 @@ public boolean isDirty() throws HibernateException { return true; } DirtyCheckEvent event = new DirtyCheckEvent( this ); - for ( DirtyCheckEventListener listener : listeners( EventType.DIRTY_CHECK ) ) { + for ( DirtyCheckEventListener listener : fastSessionServices.getDirtyCheckEventListeners() ) { listener.onDirtyCheck( event ); } delayedAfterCompletion(); @@ -1465,7 +1449,7 @@ private void doFlush() { } FlushEvent flushEvent = new FlushEvent( this ); - for ( FlushEventListener listener : listeners( EventType.FLUSH ) ) { + for ( FlushEventListener listener : fastSessionServices.getFlushEventListeners() ) { listener.onFlush( flushEvent ); } @@ -2269,7 +2253,7 @@ public void initializeCollection(PersistentCollection collection, boolean writin checkOpenOrWaitingForAutoClose(); pulseTransactionCoordinator(); InitializeCollectionEvent event = new InitializeCollectionEvent( collection, this ); - for ( InitializeCollectionEventListener listener : listeners( EventType.INIT_COLLECTION ) ) { + for ( InitializeCollectionEventListener listener : fastSessionServices.getInitCollectionEventListeners() ) { listener.onInitializeCollection( event ); } delayedAfterCompletion();