Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update DefaultReactiveListeners and Actions #1578

Merged
merged 3 commits into from
Apr 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -47,8 +47,7 @@ public void execute() throws HibernateException {

@Override
public CompletionStage<Void> reactiveExecute() throws HibernateException {

CompletionStage<Void> stage = reactiveNullifyTransientReferencesIfNotAlready();
final CompletionStage<Void> stage = reactiveNullifyTransientReferencesIfNotAlready();

final EntityPersister persister = getPersister();
final SharedSessionContractImplementor session = getSession();
Expand All @@ -60,12 +59,12 @@ public CompletionStage<Void> reactiveExecute() throws HibernateException {
// else inserted the same pk first, the insert would fail

if ( !isVeto() ) {
ReactiveEntityPersister reactivePersister = (ReactiveEntityPersister) persister;
final ReactiveEntityPersister reactivePersister = (ReactiveEntityPersister) persister;
return stage
.thenCompose( v -> reactivePersister.insertReactive( getState(), instance, session ) )
.thenCompose( generatedId -> {
setGeneratedId( generatedId );
return processInsertGenerated( reactivePersister, generatedId, instance, session )
return processInsertGeneratedProperties( reactivePersister, generatedId, instance, session )
.thenApply( v -> generatedId );
} )
.thenAccept( generatedId -> {
Expand All @@ -74,7 +73,7 @@ public CompletionStage<Void> reactiveExecute() throws HibernateException {
persister.setIdentifier( instance, generatedId, session );
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
persistenceContext.registerInsertedKey( getPersister(), generatedId );
EntityKey entityKey = session.generateEntityKey( generatedId, persister );
final EntityKey entityKey = session.generateEntityKey( generatedId, persister );
setEntityKey( entityKey );
persistenceContext.checkUniqueness( entityKey, getInstance() );

Expand All @@ -95,13 +94,13 @@ public CompletionStage<Void> reactiveExecute() throws HibernateException {
}
}

private CompletionStage<Void> processInsertGenerated(
ReactiveEntityPersister reactivePersister,
private CompletionStage<Void> processInsertGeneratedProperties(
ReactiveEntityPersister persister,
Object generatedId,
Object instance,
SharedSessionContractImplementor session) {
return reactivePersister.hasInsertGeneratedProperties()
? reactivePersister.reactiveProcessInsertGenerated( generatedId, instance, getState(), session )
return persister.hasInsertGeneratedProperties()
? persister.reactiveProcessInsertGenerated( generatedId, instance, getState(), session )
: voidFuture();
}

Expand Down
Loading