Skip to content

Commit

Permalink
update DefaultReactiveListeners
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinking committed Apr 9, 2023
1 parent b1f63b6 commit 2558493
Show file tree
Hide file tree
Showing 15 changed files with 1,092 additions and 864 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ public ReactiveCollectionRemoveAction(
this.affectedOwner = session.getPersistenceContextInternal().getLoadedCollectionOwnerOrNull( collection );
}

/**
* Removes a persistent collection for an unloaded proxy.
*
* Use this constructor when the owning entity is has not been loaded.
* @param persister The collection's persister
* @param id The collection key
* @param session The session
*/
public ReactiveCollectionRemoveAction(
final CollectionPersister persister,
final Object id,
final EventSource session) {
super( persister, null, id, session );
emptySnapshot = false;
affectedOwner = null;
}

@Override
public CompletionStage<Void> reactiveExecute() {
final Object key = getKey();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.hibernate.action.internal.EntityDeleteAction;
import org.hibernate.cache.spi.access.EntityDataAccess;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventSource;
Expand Down Expand Up @@ -43,71 +44,119 @@ public ReactiveEntityDeleteAction(
super( id, state, version, instance, persister, isCascadeDeleteEnabled, session );
}

public ReactiveEntityDeleteAction(Object id, EntityPersister persister, EventSource session) {
super( id, persister, session );
}

@Override
public void execute() throws HibernateException {
throw LOG.nonReactiveMethodCall( "reactiveExecute" );
}

private boolean isInstanceLoaded() {
// A null instance signals that we're deleting an unloaded proxy.
return getInstance() != null;
}

@Override
public CompletionStage<Void> reactiveExecute() throws HibernateException {
final Object id = getId();
final Object version = getCurrentVersion();
final EntityPersister persister = getPersister();
final SharedSessionContractImplementor session = getSession();
final Object instance = getInstance();

final boolean veto = preDelete();
final boolean veto = isInstanceLoaded() && preDelete();

Object version = getVersion();
if ( persister.isVersionPropertyGenerated() ) {
// we need to grab the version value from the entity, otherwise
// we have issues with generated-version entities that may have
// multiple actions queued during the same flush
version = persister.getVersion( instance );
}
final Object ck = lockCacheItem();

final Object ck;
if ( persister.canWriteToCache() ) {
final EntityDataAccess cache = persister.getCacheAccessStrategy();
ck = cache.generateCacheKey( id, persister, session.getFactory(), session.getTenantIdentifier() );
setLock( cache.lockItem( session, ck, version ) );
}
else {
ck = null;
}

CompletionStage<Void> deleteStep = !isCascadeDeleteEnabled() && !veto
final CompletionStage<Void> deleteStep = !isCascadeDeleteEnabled() && !veto
? ( (ReactiveEntityPersister) persister ).deleteReactive( id, version, instance, session )
: voidFuture();

return deleteStep.thenAccept( v -> {
//postDelete:
// After actually deleting a row, record the fact that the instance no longer
// exists on the database (needed for identity-column key generation), and
// remove it from the session cache
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityEntry entry = persistenceContext.removeEntry( instance );
if ( entry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to session" );
if ( isInstanceLoaded() ) {
postDeleteLoaded( id, persister, session, instance, ck );
}
entry.postDelete();

persistenceContext.removeEntity( entry.getEntityKey() );
persistenceContext.removeProxy( entry.getEntityKey() );

if ( persister.canWriteToCache() ) {
persister.getCacheAccessStrategy().remove( session, ck );
else {
// we're deleting an unloaded proxy
postDeleteUnloaded( id, persister, session, ck );
}

persistenceContext.getNaturalIdResolutions()
.removeSharedResolution( id, getNaturalIdValues(), persister );

postDelete();

final StatisticsImplementor statistics = getSession().getFactory().getStatistics();
if ( statistics.isStatisticsEnabled() && !veto ) {
statistics.deleteEntity( getPersister().getEntityName() );
}
} );
}

//TODO: copy/paste from superclass (make it protected!)
private Object getCurrentVersion() {
return getPersister().isVersionPropertyGenerated()
// skip if we're deleting an unloaded proxy, no need for the version
&& isInstanceLoaded()
// we need to grab the version value from the entity, otherwise
// we have issues with generated-version entities that may have
// multiple actions queued during the same flush
? getPersister().getVersion( getInstance() )
: getVersion();
}

//TODO: copy/paste of postDeleteLoaded() from superclass (make it protected!)
private void postDeleteLoaded(
Object id,
EntityPersister persister,
SharedSessionContractImplementor session,
Object instance,
Object ck) {
// After actually deleting a row, record the fact that the instance no longer
// exists on the database (needed for identity-column key generation), and
// remove it from the session cache
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityEntry entry = persistenceContext.removeEntry(instance);
if ( entry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to session" );
}
entry.postDelete();
final EntityKey key = entry.getEntityKey();
persistenceContext.removeEntity( key );
persistenceContext.removeProxy( key );
removeCacheItem( ck );
persistenceContext.getNaturalIdResolutions().removeSharedResolution( id, getNaturalIdValues(), persister );
postDelete();
}

//TODO: copy/paste of postDeleteUnloaded() from superclass (make it protected!)
private void postDeleteUnloaded(Object id, EntityPersister persister, SharedSessionContractImplementor session, Object ck) {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityKey key = session.generateEntityKey( id, persister );
if ( !persistenceContext.containsDeletedUnloadedEntityKey( key ) ) {
throw new AssertionFailure( "deleted proxy should be for an unloaded entity: " + key );
}
persistenceContext.removeProxy( key );
removeCacheItem( ck );
}

//TODO: copy/paste from superclass (make it protected!)
private Object lockCacheItem() {
final EntityPersister persister = getPersister();
if ( persister.canWriteToCache() ) {
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final SharedSessionContractImplementor session = getSession();
final Object ck = cache.generateCacheKey( getId(), persister, session.getFactory(), session.getTenantIdentifier() );
setLock( cache.lockItem( session, ck, getCurrentVersion() ) );
return ck;
}
else {
return null;
}
}

//TODO: copy/paste from superclass (make it protected!)
private void removeCacheItem(Object ck) {
final EntityPersister persister = getPersister();
if ( persister.canWriteToCache() ) {
persister.getCacheAccessStrategy().remove( getSession(), ck);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private ReactiveActionQueue reactiveActionQueue(AutoFlushEvent event) {

private boolean flushIsReallyNeeded(AutoFlushEvent event, final EventSource source) {
return source.getHibernateFlushMode() == FlushMode.ALWAYS
|| reactiveActionQueue( source ).areTablesToBeUpdated( event.getQuerySpaces() );
|| reactiveActionQueue( source ).areTablesToBeUpdated( event.getQuerySpaces() );
}

private ReactiveActionQueue reactiveActionQueue(EventSource source) {
Expand Down
Loading

0 comments on commit 2558493

Please sign in to comment.