HHH-18942 JFR events for collection recreate/update/remove

This commit is contained in:
Gavin King 2024-12-15 17:09:07 +01:00
parent ad1a86f570
commit caed673720
9 changed files with 339 additions and 49 deletions

View File

@ -7,7 +7,9 @@ package org.hibernate.action.internal;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventManager;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.HibernateMonitoringEvent;
import org.hibernate.event.spi.PostCollectionRecreateEvent; import org.hibernate.event.spi.PostCollectionRecreateEvent;
import org.hibernate.event.spi.PostCollectionRecreateEventListener; import org.hibernate.event.spi.PostCollectionRecreateEventListener;
import org.hibernate.event.spi.PreCollectionRecreateEvent; import org.hibernate.event.spi.PreCollectionRecreateEvent;
@ -42,14 +44,26 @@ public final class CollectionRecreateAction extends CollectionAction {
final PersistentCollection<?> collection = getCollection(); final PersistentCollection<?> collection = getCollection();
preRecreate(); preRecreate();
final SharedSessionContractImplementor session = getSession(); final SharedSessionContractImplementor session = getSession();
getPersister().recreate( collection, getKey(), session); final CollectionPersister persister = getPersister();
final Object key = getKey();
final EventManager eventManager = session.getEventManager();
final HibernateMonitoringEvent event = eventManager.beginCollectionRecreateEvent();
boolean success = false;
try {
persister.recreate( collection, key, session );
success = true;
}
finally {
eventManager.completeCollectionRecreateEvent( event, key, persister.getRole(), success, session );
}
session.getPersistenceContextInternal().getCollectionEntry( collection ).afterAction( collection ); session.getPersistenceContextInternal().getCollectionEntry( collection ).afterAction( collection );
evict(); evict();
postRecreate(); postRecreate();
final StatisticsImplementor statistics = session.getFactory().getStatistics(); final StatisticsImplementor statistics = session.getFactory().getStatistics();
if ( statistics.isStatisticsEnabled() ) { if ( statistics.isStatisticsEnabled() ) {
statistics.recreateCollection( getPersister().getRole() ); statistics.recreateCollection( persister.getRole() );
} }
} }

View File

@ -8,7 +8,9 @@ import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventManager;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.HibernateMonitoringEvent;
import org.hibernate.event.spi.PostCollectionRemoveEvent; import org.hibernate.event.spi.PostCollectionRemoveEvent;
import org.hibernate.event.spi.PostCollectionRemoveEventListener; import org.hibernate.event.spi.PostCollectionRemoveEventListener;
import org.hibernate.event.spi.PreCollectionRemoveEvent; import org.hibernate.event.spi.PreCollectionRemoveEvent;
@ -108,8 +110,20 @@ public final class CollectionRemoveAction extends CollectionAction {
// is replaced by null or a different collection // is replaced by null or a different collection
// (if the collection is uninitialized, Hibernate has no way of // (if the collection is uninitialized, Hibernate has no way of
// knowing if the collection is actually empty without querying the db) // knowing if the collection is actually empty without querying the db)
getPersister().remove( getKey(), session ); final CollectionPersister persister = getPersister();
final Object key = getKey();
final EventManager eventManager = session.getEventManager();
final HibernateMonitoringEvent event = eventManager.beginCollectionRemoveEvent();
boolean success = false;
try {
persister.remove( key, session );
success = true;
} }
finally {
eventManager.completeCollectionRemoveEvent( event, key, persister.getRole(), success, session );
}
}
final PersistentCollection<?> collection = getCollection(); final PersistentCollection<?> collection = getCollection();
if ( collection != null ) { if ( collection != null ) {
session.getPersistenceContextInternal().getCollectionEntry( collection ).afterAction( collection ); session.getPersistenceContextInternal().getCollectionEntry( collection ).afterAction( collection );
@ -130,12 +144,7 @@ public final class CollectionRemoveAction extends CollectionAction {
} }
private PreCollectionRemoveEvent newPreCollectionRemoveEvent() { private PreCollectionRemoveEvent newPreCollectionRemoveEvent() {
return new PreCollectionRemoveEvent( return new PreCollectionRemoveEvent( getPersister(), getCollection(), eventSource(), affectedOwner );
getPersister(),
getCollection(),
eventSource(),
affectedOwner
);
} }
private void postRemove() { private void postRemove() {
@ -145,12 +154,7 @@ public final class CollectionRemoveAction extends CollectionAction {
} }
private PostCollectionRemoveEvent newPostCollectionRemoveEvent() { private PostCollectionRemoveEvent newPostCollectionRemoveEvent() {
return new PostCollectionRemoveEvent( return new PostCollectionRemoveEvent( getPersister(), getCollection(), eventSource(), affectedOwner );
getPersister(),
getCollection(),
eventSource(),
affectedOwner
);
} }
public Object getAffectedOwner() { public Object getAffectedOwner() {

View File

@ -8,7 +8,9 @@ import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.EventManager;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.HibernateMonitoringEvent;
import org.hibernate.event.spi.PostCollectionUpdateEvent; import org.hibernate.event.spi.PostCollectionUpdateEvent;
import org.hibernate.event.spi.PostCollectionUpdateEventListener; import org.hibernate.event.spi.PostCollectionUpdateEventListener;
import org.hibernate.event.spi.PreCollectionUpdateEvent; import org.hibernate.event.spi.PreCollectionUpdateEvent;
@ -45,7 +47,7 @@ public final class CollectionUpdateAction extends CollectionAction {
@Override @Override
public void execute() throws HibernateException { public void execute() throws HibernateException {
final Object id = getKey(); final Object key = getKey();
final SharedSessionContractImplementor session = getSession(); final SharedSessionContractImplementor session = getSession();
final CollectionPersister persister = getPersister(); final CollectionPersister persister = getPersister();
final PersistentCollection<?> collection = getCollection(); final PersistentCollection<?> collection = getCollection();
@ -54,34 +56,45 @@ public final class CollectionUpdateAction extends CollectionAction {
preUpdate(); preUpdate();
if ( !collection.wasInitialized() ) { if ( !collection.wasInitialized() ) {
// If there were queued operations, they would have been processed // If there were queued operations, they would have
// and cleared by now. // been processed and cleared by now.
// The collection should still be dirty.
if ( !collection.isDirty() ) { if ( !collection.isDirty() ) {
// The collection should still be dirty.
throw new AssertionFailure( "collection is not dirty" ); throw new AssertionFailure( "collection is not dirty" );
} }
//do nothing - we only need to notify the cache... // Do nothing - we only need to notify the cache
} }
else if ( !affectedByFilters && collection.empty() ) { else {
final EventManager eventManager = session.getEventManager();
final HibernateMonitoringEvent event = eventManager.beginCollectionUpdateEvent();
boolean success = false;
try {
if ( !affectedByFilters && collection.empty() ) {
if ( !emptySnapshot ) { if ( !emptySnapshot ) {
persister.remove( id, session ); persister.remove( key, session );
} }
//TODO: else we really shouldn't have sent an update event to JFR
} }
else if ( collection.needsRecreate( persister ) ) { else if ( collection.needsRecreate( persister ) ) {
if ( affectedByFilters ) { if ( affectedByFilters ) {
throw new HibernateException( "cannot recreate collection while filter is enabled: " throw new HibernateException( "cannot recreate collection while filter is enabled: "
+ collectionInfoString( persister, collection, id, session ) + collectionInfoString( persister, collection, key, session ) );
);
} }
if ( !emptySnapshot ) { if ( !emptySnapshot ) {
persister.remove( id, session ); persister.remove( key, session );
} }
persister.recreate( collection, id, session ); persister.recreate( collection, key, session );
} }
else { else {
persister.deleteRows( collection, id, session ); persister.deleteRows( collection, key, session );
persister.updateRows( collection, id, session ); persister.updateRows( collection, key, session );
persister.insertRows( collection, id, session ); persister.insertRows( collection, key, session );
}
success = true;
}
finally {
eventManager.completeCollectionUpdateEvent( event, key, persister.getRole(), success, session );
}
} }
session.getPersistenceContextInternal().getCollectionEntry( collection ).afterAction( collection ); session.getPersistenceContextInternal().getCollectionEntry( collection ).afterAction( collection );
@ -101,11 +114,7 @@ public final class CollectionUpdateAction extends CollectionAction {
} }
private PreCollectionUpdateEvent newPreCollectionUpdateEvent() { private PreCollectionUpdateEvent newPreCollectionUpdateEvent() {
return new PreCollectionUpdateEvent( return new PreCollectionUpdateEvent( getPersister(), getCollection(), eventSource() );
getPersister(),
getCollection(),
eventSource()
);
} }
private void postUpdate() { private void postUpdate() {
@ -115,11 +124,7 @@ public final class CollectionUpdateAction extends CollectionAction {
} }
private PostCollectionUpdateEvent newPostCollectionUpdateEvent() { private PostCollectionUpdateEvent newPostCollectionUpdateEvent() {
return new PostCollectionUpdateEvent( return new PostCollectionUpdateEvent( getPersister(), getCollection(), eventSource() );
getPersister(),
getCollection(),
eventSource()
);
} }
} }

View File

@ -15,6 +15,9 @@ import org.hibernate.event.spi.FlushEvent;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/**
* An {@link EventManager} that ignores all events.
*/
public final class EmptyEventManager implements EventManager { public final class EmptyEventManager implements EventManager {
@Override @Override
@ -276,4 +279,34 @@ public final class EmptyEventManager implements EventManager {
SharedSessionContractImplementor session) { SharedSessionContractImplementor session) {
} }
@Override
public HibernateMonitoringEvent beginCollectionRecreateEvent() {
return null;
}
@Override
public void completeCollectionRecreateEvent(HibernateMonitoringEvent event, Object id, String role, boolean success, SharedSessionContractImplementor session) {
}
@Override
public HibernateMonitoringEvent beginCollectionUpdateEvent() {
return null;
}
@Override
public void completeCollectionUpdateEvent(HibernateMonitoringEvent event, Object id, String role, boolean success, SharedSessionContractImplementor session) {
}
@Override
public HibernateMonitoringEvent beginCollectionRemoveEvent() {
return null;
}
@Override
public void completeCollectionRemoveEvent(HibernateMonitoringEvent event, Object id, String role, boolean success, SharedSessionContractImplementor session) {
}
} }

View File

@ -169,6 +169,18 @@ public interface EventManager {
void completeEntityDeleteEvent(HibernateMonitoringEvent event, Object id, String entityName, boolean success, SharedSessionContractImplementor session); void completeEntityDeleteEvent(HibernateMonitoringEvent event, Object id, String entityName, boolean success, SharedSessionContractImplementor session);
HibernateMonitoringEvent beginCollectionRecreateEvent();
void completeCollectionRecreateEvent(HibernateMonitoringEvent event, Object id, String role, boolean success, SharedSessionContractImplementor session);
HibernateMonitoringEvent beginCollectionUpdateEvent();
void completeCollectionUpdateEvent(HibernateMonitoringEvent event, Object id, String role, boolean success, SharedSessionContractImplementor session);
HibernateMonitoringEvent beginCollectionRemoveEvent();
void completeCollectionRemoveEvent(HibernateMonitoringEvent event, Object id, String role, boolean success, SharedSessionContractImplementor session);
enum CacheActionDescription { enum CacheActionDescription {
ENTITY_INSERT( "Entity Insert" ), ENTITY_INSERT( "Entity Insert" ),
ENTITY_AFTER_INSERT( "Entity After Insert" ), ENTITY_AFTER_INSERT( "Entity After Insert" ),

View File

@ -0,0 +1,42 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.event.jfr.internal;
import jdk.jfr.Category;
import jdk.jfr.Description;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.StackTrace;
import org.hibernate.event.spi.HibernateMonitoringEvent;
import org.hibernate.internal.build.AllowNonPortable;
@Name(CollectionRecreateEvent.NAME)
@Label("Collection Recreate")
@Category("Hibernate ORM")
@Description("Collection Recreate")
@StackTrace
@AllowNonPortable
public class CollectionRecreateEvent extends Event implements HibernateMonitoringEvent {
public static final String NAME = "org.hibernate.orm.CollectionRecreateEvent";
@Label("Session Identifier")
public String sessionIdentifier;
@Label("Entity Identifier")
public String id;
@Label("Collection Role")
public String role;
@Label("Success")
public boolean success;
@Override
public String toString() {
return NAME;
}
}

View File

@ -0,0 +1,42 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.event.jfr.internal;
import jdk.jfr.Category;
import jdk.jfr.Description;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.StackTrace;
import org.hibernate.event.spi.HibernateMonitoringEvent;
import org.hibernate.internal.build.AllowNonPortable;
@Name(CollectionRemoveEvent.NAME)
@Label("Collection Remove")
@Category("Hibernate ORM")
@Description("Collection Remove")
@StackTrace
@AllowNonPortable
public class CollectionRemoveEvent extends Event implements HibernateMonitoringEvent {
public static final String NAME = "org.hibernate.orm.CollectionRemoveEvent";
@Label("Session Identifier")
public String sessionIdentifier;
@Label("Entity Identifier")
public String id;
@Label("Collection Role")
public String role;
@Label("Success")
public boolean success;
@Override
public String toString() {
return NAME;
}
}

View File

@ -0,0 +1,42 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.event.jfr.internal;
import jdk.jfr.Category;
import jdk.jfr.Description;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.StackTrace;
import org.hibernate.event.spi.HibernateMonitoringEvent;
import org.hibernate.internal.build.AllowNonPortable;
@Name(CollectionUpdateEvent.NAME)
@Label("Collection Update")
@Category("Hibernate ORM")
@Description("Collection Update")
@StackTrace
@AllowNonPortable
public class CollectionUpdateEvent extends Event implements HibernateMonitoringEvent {
public static final String NAME = "org.hibernate.orm.CollectionUpdateEvent";
@Label("Session Identifier")
public String sessionIdentifier;
@Label("Entity Identifier")
public String id;
@Label("Collection Role")
public String role;
@Label("Success")
public boolean success;
@Override
public String toString() {
return NAME;
}
}

View File

@ -44,6 +44,9 @@ public class JfrEventManager implements EventManager {
private static final EventType entityInsertEventType = EventType.getEventType( EntityInsertEvent.class ); private static final EventType entityInsertEventType = EventType.getEventType( EntityInsertEvent.class );
private static final EventType entityUpdateEventType = EventType.getEventType( EntityUpdateEvent.class ); private static final EventType entityUpdateEventType = EventType.getEventType( EntityUpdateEvent.class );
private static final EventType entityDeleteEventType = EventType.getEventType( EntityDeleteEvent.class ); private static final EventType entityDeleteEventType = EventType.getEventType( EntityDeleteEvent.class );
private static final EventType collectionRecreateEventType = EventType.getEventType( CollectionRecreateEvent.class );
private static final EventType collectionUpdateEventType = EventType.getEventType( CollectionUpdateEvent.class );
private static final EventType collectionRemoveEventType = EventType.getEventType( CollectionRemoveEvent.class );
@Override @Override
public SessionOpenEvent beginSessionOpenEvent() { public SessionOpenEvent beginSessionOpenEvent() {
@ -621,6 +624,99 @@ public class JfrEventManager implements EventManager {
} }
} }
@Override
public HibernateMonitoringEvent beginCollectionRecreateEvent() {
if ( collectionRecreateEventType.isEnabled() ) {
final CollectionRecreateEvent event = new CollectionRecreateEvent();
event.begin();
return event;
}
else {
return null;
}
}
@Override
public void completeCollectionRecreateEvent(
HibernateMonitoringEvent event,
Object id, String role,
boolean success,
SharedSessionContractImplementor session) {
if ( event != null ) {
final CollectionRecreateEvent entityInsertEvent = (CollectionRecreateEvent) event;
entityInsertEvent.end();
if ( entityInsertEvent.shouldCommit() ) {
entityInsertEvent.sessionIdentifier = getSessionIdentifier( session );
entityInsertEvent.role = role;
entityInsertEvent.id = Objects.toString(id);
entityInsertEvent.success = success;
entityInsertEvent.commit();
}
}
}
@Override
public HibernateMonitoringEvent beginCollectionUpdateEvent() {
if ( collectionUpdateEventType.isEnabled() ) {
final CollectionUpdateEvent event = new CollectionUpdateEvent();
event.begin();
return event;
}
else {
return null;
}
}
@Override
public void completeCollectionUpdateEvent(
HibernateMonitoringEvent event,
Object id, String role,
boolean success,
SharedSessionContractImplementor session) {
if ( event != null ) {
final CollectionUpdateEvent entityUpdateEvent = (CollectionUpdateEvent) event;
entityUpdateEvent.end();
if ( entityUpdateEvent.shouldCommit() ) {
entityUpdateEvent.sessionIdentifier = getSessionIdentifier( session );
entityUpdateEvent.role = role;
entityUpdateEvent.id = Objects.toString(id);
entityUpdateEvent.success = success;
entityUpdateEvent.commit();
}
}
}
@Override
public HibernateMonitoringEvent beginCollectionRemoveEvent() {
if ( collectionRemoveEventType.isEnabled() ) {
final CollectionRemoveEvent event = new CollectionRemoveEvent();
event.begin();
return event;
}
else {
return null;
}
}
@Override
public void completeCollectionRemoveEvent(
HibernateMonitoringEvent event,
Object id, String role,
boolean success,
SharedSessionContractImplementor session) {
if ( event != null ) {
final CollectionRemoveEvent entityDeleteEvent = (CollectionRemoveEvent) event;
entityDeleteEvent.end();
if ( entityDeleteEvent.shouldCommit() ) {
entityDeleteEvent.sessionIdentifier = getSessionIdentifier( session );
entityDeleteEvent.role = role;
entityDeleteEvent.id = Objects.toString(id);
entityDeleteEvent.success = success;
entityDeleteEvent.commit();
}
}
}
private String getSessionIdentifier(SharedSessionContractImplementor session) { private String getSessionIdentifier(SharedSessionContractImplementor session) {
if ( session == null ) { if ( session == null ) {
return null; return null;