HHH-13565 Session opening efficiency: introduce FastSessionServices and design for shared services among sessions

This commit is contained in:
Sanne Grinovero 2019-08-09 10:28:18 +01:00
parent 408275ddec
commit 5eaa1498df
4 changed files with 209 additions and 39 deletions

View File

@ -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 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
// -- see above
factory = SessionFactoryImpl.deserialize( ois );
fastSessionServices = factory.getFastSessionServices();
jdbcSessionContext = new JdbcSessionContextImpl( this, (StatementInspector) ois.readObject() );
jdbcCoordinator = JdbcCoordinatorImpl.deserialize( ois, this );

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<ClearEventListener> clearEventListeners;
private final Iterable<SaveOrUpdateEventListener> saveUpdateEventListeners;
private final Iterable<EvictEventListener> evictEventListeners;
private final Iterable<SaveOrUpdateEventListener> saveEventListeners;
private final Iterable<SaveOrUpdateEventListener> updateEventListeners;
private final Iterable<LockEventListener> lockEventListeners;
private final Iterable<PersistEventListener> persistEventListeners;
private final Iterable<PersistEventListener> persistOnFlushEventListeners;
private final Iterable<MergeEventListener> mergeEventListeners;
private final Iterable<DeleteEventListener> deleteEventListeners;
private final Iterable<LoadEventListener> loadEventListeners;
private final Iterable<RefreshEventListener> refreshEventListeners;
private final Iterable<ReplicateEventListener> replicateEventListeners;
private final Iterable<AutoFlushEventListener> autoFlushEventListeners;
private final Iterable<DirtyCheckEventListener> dirtyCheckEventListeners;
private final Iterable<FlushEventListener> flushEventListeners;
private final Iterable<InitializeCollectionEventListener> initCollectionEventListeners;
private final Iterable<ResolveNaturalIdEventListener> 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<ClearEventListener> getClearEventListeners() {
return clearEventListeners;
}
Iterable<EvictEventListener> getEvictEventListeners() {
return this.evictEventListeners;
}
Iterable<DirtyCheckEventListener> getDirtyCheckEventListeners() {
return this.dirtyCheckEventListeners;
}
Iterable<SaveOrUpdateEventListener> getSaveUpdateEventListeners() {
return this.saveUpdateEventListeners;
}
Iterable<SaveOrUpdateEventListener> getSaveEventListeners() {
return this.saveEventListeners;
}
Iterable<SaveOrUpdateEventListener> getUpdateEventListeners() {
return this.updateEventListeners;
}
Iterable<LockEventListener> getLockEventListeners() {
return this.lockEventListeners;
}
Iterable<PersistEventListener> getPersistEventListeners() {
return persistEventListeners;
}
Iterable<FlushEventListener> getFlushEventListeners() {
return flushEventListeners;
}
Iterable<PersistEventListener> getPersistOnFlushEventListeners() {
return persistOnFlushEventListeners;
}
Iterable<InitializeCollectionEventListener> getInitCollectionEventListeners() {
return initCollectionEventListeners;
}
Iterable<LoadEventListener> getLoadEventListeners() {
return loadEventListeners;
}
Iterable<MergeEventListener> getMergeEventListeners() {
return mergeEventListeners;
}
Iterable<RefreshEventListener> getRefreshEventListeners() {
return refreshEventListeners;
}
Iterable<DeleteEventListener> getDeleteEventListeners() {
return deleteEventListeners;
}
Iterable<AutoFlushEventListener> getAutoFlushEventListeners() {
return autoFlushEventListeners;
}
Iterable<ReplicateEventListener> getReplicateEventListeners() {
return replicateEventListeners;
}
Iterable<ResolveNaturalIdEventListener> getResolveNaturalIdEventListeners() {
return resolveNaturalIdEventListeners;
}
private static <T> Iterable<T> listeners(EventListenerRegistry elr, EventType<T> type) {
return elr.getEventListenerGroup( type ).listeners();
}
}

View File

@ -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 final class SessionFactoryImpl implements SessionFactoryImplementor {
fetchProfiles.put( fetchProfile.getName(), fetchProfile );
}
this.fastSessionServices = new FastSessionServices( this );
this.observer.sessionFactoryCreated( this );
SessionFactoryRegistry.INSTANCE.addSessionFactory(
@ -1645,4 +1649,12 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
LOG.emptyCompositesEnabled();
}
}
/**
* @return the FastSessionServices for this SessionFactory.
*/
FastSessionServices getFastSessionServices() {
return this.fastSessionServices;
}
}

View File

@ -96,8 +96,6 @@ import org.hibernate.engine.spi.Status;
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.DeleteEventListener;
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 @@ public final class SessionImpl
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 @@ public final class SessionImpl
checkOpen();
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE_UPDATE ) ) {
for ( SaveOrUpdateEventListener listener : fastSessionServices.getSaveUpdateEventListeners() ) {
listener.onSaveOrUpdate( event );
}
checkNoUnresolvedActionsAfterOperation();
}
private <T> Iterable<T> listeners(EventType<T> type) {
return eventListenerGroup( type ).listeners();
}
private <T> EventListenerGroup<T> eventListenerGroup(EventType<T> type) {
if ( this.eventListenerRegistry == null ) {
this.eventListenerRegistry = getFactory().getServiceRegistry().getService( EventListenerRegistry.class );
}
return eventListenerRegistry.getEventListenerGroup( type );
}
// save() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
@ -667,7 +651,7 @@ public final class SessionImpl
checkOpen();
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE ) ) {
for ( SaveOrUpdateEventListener listener : fastSessionServices.getSaveEventListeners() ) {
listener.onSaveOrUpdate( event );
}
checkNoUnresolvedActionsAfterOperation();
@ -691,7 +675,7 @@ public final class SessionImpl
checkOpen();
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
for ( SaveOrUpdateEventListener listener : listeners( EventType.UPDATE ) ) {
for ( SaveOrUpdateEventListener listener : fastSessionServices.getUpdateEventListeners() ) {
listener.onSaveOrUpdate( event );
}
checkNoUnresolvedActionsAfterOperation();
@ -726,7 +710,7 @@ public final class SessionImpl
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 @@ public final class SessionImpl
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
for ( PersistEventListener listener : listeners( EventType.PERSIST ) ) {
for ( PersistEventListener listener : fastSessionServices.getPersistEventListeners() ) {
listener.onPersist( event );
}
}
@ -782,7 +766,7 @@ public final class SessionImpl
pulseTransactionCoordinator();
try {
for ( PersistEventListener listener : listeners( EventType.PERSIST ) ) {
for ( PersistEventListener listener : fastSessionServices.getPersistEventListeners() ) {
listener.onPersist( event, copiedAlready );
}
}
@ -818,7 +802,7 @@ public final class SessionImpl
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 @@ public final class SessionImpl
checkOpen();
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
for ( PersistEventListener listener : listeners( EventType.PERSIST_ONFLUSH ) ) {
for ( PersistEventListener listener : fastSessionServices.getPersistOnFlushEventListeners() ) {
listener.onPersist( event );
}
checkNoUnresolvedActionsAfterOperation();
@ -859,7 +843,7 @@ public final class SessionImpl
try {
checkTransactionSynchStatus();
checkNoUnresolvedActionsBeforeOperation();
for ( MergeEventListener listener : listeners( EventType.MERGE ) ) {
for ( MergeEventListener listener : fastSessionServices.getMergeEventListeners() ) {
listener.onMerge( event );
}
checkNoUnresolvedActionsAfterOperation();
@ -881,7 +865,7 @@ public final class SessionImpl
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 @@ public final class SessionImpl
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 @@ public final class SessionImpl
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 @@ public final class SessionImpl
// 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 @@ public final class SessionImpl
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 @@ public final class SessionImpl
}
}
pulseTransactionCoordinator();
for ( RefreshEventListener listener : listeners( EventType.REFRESH ) ) {
for ( RefreshEventListener listener : fastSessionServices.getRefreshEventListeners() ) {
listener.onRefresh( event );
}
}
@ -1359,7 +1343,7 @@ public final class SessionImpl
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 final class SessionImpl
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 final class SessionImpl
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 @@ public final class SessionImpl
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 final class SessionImpl
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 @@ public final class SessionImpl
}
FlushEvent flushEvent = new FlushEvent( this );
for ( FlushEventListener listener : listeners( EventType.FLUSH ) ) {
for ( FlushEventListener listener : fastSessionServices.getFlushEventListeners() ) {
listener.onFlush( flushEvent );
}
@ -2269,7 +2253,7 @@ public final class SessionImpl
checkOpenOrWaitingForAutoClose();
pulseTransactionCoordinator();
InitializeCollectionEvent event = new InitializeCollectionEvent( collection, this );
for ( InitializeCollectionEventListener listener : listeners( EventType.INIT_COLLECTION ) ) {
for ( InitializeCollectionEventListener listener : fastSessionServices.getInitCollectionEventListeners() ) {
listener.onInitializeCollection( event );
}
delayedAfterCompletion();