From 8bc344d3e87c76a7810ff4590564326b05c38748 Mon Sep 17 00:00:00 2001 From: Radek Felcman Date: Tue, 19 Nov 2024 15:08:51 +0100 Subject: [PATCH] Cache DeadLock Detection test move from org.eclipse.persistence.jpa.jse.test into new org.eclipse.persistence.jpa.testapps.deadlock.diagnostic Maven module There is move into new Maven module some test refactor and new test for WriteLockManager.acquireLocksForClone(...) method call and logging. Signed-off-by: Radek Felcman --- .../internal/helper/WriteLockManager.java | 5 +- jpa/eclipselink.jpa.test.jse/pom.xml | 26 +-- .../CacheDeadLockDetectionTest.java | 172 --------------- .../src/it/resources/META-INF/persistence.xml | 40 ---- .../jpa.test.diagnostic.deadlock/pom.xml | 109 +++++++++ .../CacheDeadLockDetectionDetail.java | 11 +- .../CacheDeadLockDetectionMaster.java | 11 +- .../DeadLockDiagnosticTableCreator.java | 103 +++++++++ .../jpa/deadlock/diagnostic}/MainThread.java | 8 +- .../diagnostic}/event/EventObserver.java | 8 +- .../diagnostic}/event/EventProducer.java | 6 +- .../diagnostic}/event/EventProducerImpl.java | 6 +- .../src/main}/resources/META-INF/beans.xml | 2 +- .../main/resources/META-INF/persistence.xml | 56 +++++ .../CacheDeadLockDetectionTest.java | 207 ++++++++++++++++++ .../diagnostic/CacheDeadLockManagersTest.java | 132 +++++++++++ .../jpa/deadlock/diagnostic/LogWrapper.java | 50 +++++ jpa/eclipselink.jpa.testapps/pom.xml | 1 + 18 files changed, 690 insertions(+), 263 deletions(-) delete mode 100644 jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/CacheDeadLockDetectionTest.java create mode 100644 jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/pom.xml rename jpa/{eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/model => eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic}/CacheDeadLockDetectionDetail.java (85%) rename jpa/{eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/model => eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic}/CacheDeadLockDetectionMaster.java (85%) create mode 100644 jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/DeadLockDiagnosticTableCreator.java rename jpa/{eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock => eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic}/MainThread.java (85%) rename jpa/{eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi => eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic}/event/EventObserver.java (81%) rename jpa/{eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi => eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic}/event/EventProducer.java (68%) rename jpa/{eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi => eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic}/event/EventProducerImpl.java (76%) rename jpa/{eclipselink.jpa.test.jse/src/it => eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main}/resources/META-INF/beans.xml (89%) create mode 100644 jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/resources/META-INF/persistence.xml create mode 100644 jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/CacheDeadLockDetectionTest.java create mode 100644 jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/CacheDeadLockManagersTest.java create mode 100644 jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/LogWrapper.java diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/WriteLockManager.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/WriteLockManager.java index 05bc45a7900..8e89c6185e6 100644 --- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/WriteLockManager.java +++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/WriteLockManager.java @@ -135,6 +135,8 @@ public class WriteLockManager { private final Lock instancePrevailingQueueLock = new ReentrantLock(); private final Condition toWaitOnLockCondition = toWaitOnLock.newCondition(); + private static final String ACQUIRE_LOCK_FOR_CLONE_METHOD_NAME = WriteLockManager.class.getName() + ".acquireLocksForClone(...)"; + public WriteLockManager() { this.prevailingQueue = new ExposedNodeLinkedList(); } @@ -170,9 +172,8 @@ public Map acquireLocksForClone(Object objectForClone, ClassDescriptor descripto // of the concurrency manager that we use for creating the massive log dump // to indicate that the current thread is now stuck trying to acquire some arbitrary // cache key for writing - StackTraceElement stackTraceElement = Thread.currentThread().getStackTrace()[1]; lastCacheKeyWeNeededToWaitToAcquire = toWaitOn; - lastCacheKeyWeNeededToWaitToAcquire.putThreadAsWaitingToAcquireLockForWriting(currentThread, stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + "(...)"); + lastCacheKeyWeNeededToWaitToAcquire.putThreadAsWaitingToAcquireLockForWriting(currentThread, ACQUIRE_LOCK_FOR_CLONE_METHOD_NAME); // Since we know this one of those methods that can appear in the dead locks // we threads frozen here forever inside of the wait that used to have no timeout diff --git a/jpa/eclipselink.jpa.test.jse/pom.xml b/jpa/eclipselink.jpa.test.jse/pom.xml index bdea2e7e125..d03a34f812e 100644 --- a/jpa/eclipselink.jpa.test.jse/pom.xml +++ b/jpa/eclipselink.jpa.test.jse/pom.xml @@ -41,16 +41,6 @@ junit test - - jakarta.enterprise - jakarta.enterprise.cdi-api - test - - - org.jboss.weld.se - weld-se-core - test - @@ -210,32 +200,18 @@ - test-jpa-jse-without-deadlock + test-jpa-jse integration-test ${test-skip-jpa-jse} test-jpa-jse - - CacheDeadLockDetectionTest* - *.Test* - - test-jpa-jse-deadlock - - integration-test - - - - CacheDeadLockDetectionTest* - - - verify-integration-tests diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/CacheDeadLockDetectionTest.java b/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/CacheDeadLockDetectionTest.java deleted file mode 100644 index e4e34fad4c2..00000000000 --- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/CacheDeadLockDetectionTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -// Contributors: -// Oracle - initial API and implementation -package org.eclipse.persistence.jpa.test.cachedeadlock; - -import jakarta.enterprise.inject.se.SeContainer; -import jakarta.enterprise.inject.se.SeContainerInitializer; - -import jakarta.persistence.*; - -import org.eclipse.persistence.internal.helper.ConcurrencyUtil; -import org.eclipse.persistence.internal.jpa.EntityManagerImpl; -import org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionDetail; -import org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionMaster; -import org.eclipse.persistence.jpa.test.cachedeadlock.cdi.event.EventProducer; - -import org.eclipse.persistence.sessions.DatabaseSession; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -public class CacheDeadLockDetectionTest { - - public static final int RECORDS_NO = 10; - public static final int NO_OF_THREADS = 100; - - public static EntityManagerFactory emf = Persistence.createEntityManagerFactory("cachedeadlockdetection-pu"); - public static EntityManagerFactory emfSemaphore = Persistence.createEntityManagerFactory("cachedeadlocksemaphore-pu"); - - SeContainer container; - - EventProducer eventProducer; - - @Test - public void bugTest() { - EntityManager em = emf.createEntityManager(); - verifyPersistenceProperties(); - setup(); - try { - em.getTransaction().begin(); - initData(em); - em.getTransaction().commit(); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(); - } finally { - if (em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - } - threadExecution(em); - try { - Thread.sleep(7000L); - } catch (InterruptedException e) { - e.printStackTrace(); - } - System.out.println("##########################Test with semaphores - begin###########################"); - EntityManager emSemaphore = emfSemaphore.createEntityManager(); - verifySemaphoreProperties(); - threadExecution(emSemaphore); - System.out.println("##########################Test with semaphores - end###########################"); - } - - private void threadExecution(EntityManager em) { - ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(NO_OF_THREADS); - for (int i = 1; i <= NO_OF_THREADS; i++) { - Thread thread = new Thread(new MainThread(container, emf, em)); - thread.setName("MainThread: " + i); - executor.execute(thread); - } - executor.shutdown(); - // Wait for everything to finish. - try { - executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - Assert.fail(); - } - } - - @Before - public void initContainer() { - container = SeContainerInitializer.newInstance().initialize(); - eventProducer = container.select(EventProducer.class).get(); - } - - private static void initData(EntityManager em) { - for (int i = 1, j = 1; i <= RECORDS_NO; i++, j = j +2) { - CacheDeadLockDetectionMaster cacheDeadLockDetectionMaster = new CacheDeadLockDetectionMaster(i, "M" + i); - CacheDeadLockDetectionDetail cacheDeadLockDetectionDetail1 = new CacheDeadLockDetectionDetail(j, "D" + j); - CacheDeadLockDetectionDetail cacheDeadLockDetectionDetail2 = new CacheDeadLockDetectionDetail(j + 1, "D" + (j + 1)); - cacheDeadLockDetectionDetail1.setMaster(cacheDeadLockDetectionMaster); - cacheDeadLockDetectionDetail2.setMaster(cacheDeadLockDetectionMaster); - em.persist(cacheDeadLockDetectionMaster); - em.persist(cacheDeadLockDetectionDetail1); - em.persist(cacheDeadLockDetectionDetail2); - } - } - - - public void setup() { - EntityManager em = emf.createEntityManager(); - try { - DatabaseSession session = ((EntityManagerImpl) em).getDatabaseSession(); - try { - session.executeNonSelectingSQL("DROP TABLE cachedeadlock_detail"); - } catch (Exception ignore) { - } - try { - session.executeNonSelectingSQL("DROP TABLE cachedeadlock_master"); - } catch (Exception ignore) { - } - try { - session.executeNonSelectingSQL("CREATE TABLE cachedeadlock_master (id integer NOT NULL, name varchar(200), PRIMARY KEY(id))"); - session.executeNonSelectingSQL("CREATE TABLE cachedeadlock_detail (id integer NOT NULL, id_fk integer , name varchar(200), PRIMARY KEY(id))"); - session.executeNonSelectingSQL("ALTER TABLE cachedeadlock_detail ADD CONSTRAINT fk_cachedeadlock_detail FOREIGN KEY ( id_fk ) REFERENCES cachedeadlock_master (ID)"); - } catch (Exception ignore) { - } - } finally { - if (em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - if (em.isOpen()) { - em.close(); - } - } - } - - private void verifyPersistenceProperties() { - assertEquals(1L, ConcurrencyUtil.SINGLETON.getAcquireWaitTime()); - assertEquals(2L, ConcurrencyUtil.SINGLETON.getMaxAllowedSleepTime()); - assertEquals(800L, ConcurrencyUtil.SINGLETON.getMaxAllowedFrequencyToProduceTinyDumpLogMessage()); - assertEquals(1000L, ConcurrencyUtil.SINGLETON.getMaxAllowedFrequencyToProduceMassiveDumpLogMessage()); - assertEquals(5L, ConcurrencyUtil.SINGLETON.getBuildObjectCompleteWaitTime()); - assertTrue(ConcurrencyUtil.SINGLETON.isAllowTakingStackTraceDuringReadLockAcquisition()); - assertTrue(ConcurrencyUtil.SINGLETON.isAllowConcurrencyExceptionToBeFiredUp()); - assertTrue(ConcurrencyUtil.SINGLETON.isAllowInterruptedExceptionFired()); - } - - private void verifySemaphoreProperties() { - assertEquals(1L, ConcurrencyUtil.SINGLETON.getAcquireWaitTime()); - assertEquals(2L, ConcurrencyUtil.SINGLETON.getMaxAllowedSleepTime()); - assertEquals(1000L, ConcurrencyUtil.SINGLETON.getMaxAllowedFrequencyToProduceTinyDumpLogMessage()); - assertEquals(2000L, ConcurrencyUtil.SINGLETON.getMaxAllowedFrequencyToProduceMassiveDumpLogMessage()); - assertTrue(ConcurrencyUtil.SINGLETON.isAllowTakingStackTraceDuringReadLockAcquisition()); - assertTrue(ConcurrencyUtil.SINGLETON.isAllowConcurrencyExceptionToBeFiredUp()); - assertTrue(ConcurrencyUtil.SINGLETON.isAllowInterruptedExceptionFired()); - assertTrue(ConcurrencyUtil.SINGLETON.isUseSemaphoreInObjectBuilder()); - assertEquals(5L, ConcurrencyUtil.SINGLETON.getNoOfThreadsAllowedToObjectBuildInParallel()); - assertTrue(ConcurrencyUtil.SINGLETON.isUseSemaphoreToLimitConcurrencyOnWriteLockManagerAcquireRequiredLocks()); - assertEquals(6L, ConcurrencyUtil.SINGLETON.getNoOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel()); - assertEquals(7L, ConcurrencyUtil.SINGLETON.getConcurrencySemaphoreMaxTimePermit()); - assertEquals(8L, ConcurrencyUtil.SINGLETON.getConcurrencySemaphoreLogTimeout()); - } -} diff --git a/jpa/eclipselink.jpa.test.jse/src/it/resources/META-INF/persistence.xml b/jpa/eclipselink.jpa.test.jse/src/it/resources/META-INF/persistence.xml index dda1d7565bd..54b559b24be 100644 --- a/jpa/eclipselink.jpa.test.jse/src/it/resources/META-INF/persistence.xml +++ b/jpa/eclipselink.jpa.test.jse/src/it/resources/META-INF/persistence.xml @@ -60,44 +60,4 @@ true - - - org.eclipse.persistence.jpa.PersistenceProvider - org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionMaster - org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionDetail - true - - - - - - - - - - - - - - org.eclipse.persistence.jpa.PersistenceProvider - org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionMaster - org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionDetail - true - - - - - - - - - - - - - - - - - diff --git a/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/pom.xml b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/pom.xml new file mode 100644 index 00000000000..ce6127331eb --- /dev/null +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/pom.xml @@ -0,0 +1,109 @@ + + + + + + org.eclipse.persistence.jpa.testapps + org.eclipse.persistence + 5.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + org.eclipse.persistence.jpa.testapps.deadlock.diagnostic + + Test - deadlock diagnostic framework + + + + + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + org.jboss.weld.se + weld-se-core + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + get-test-classpath-to-properties + process-test-classes + + + + + org.carlspring.maven + derby-maven-plugin + + + start-derby + process-test-classes + + + stop-derby + prepare-package + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + default-test + + -javaagent:${org.eclipse.persistence:org.eclipse.persistence.jpa:jar} @{argLine} + + CacheDeadLockDetectionTest* + + + + + dead-lock-managers-test + + test + + + + CacheDeadLockManagersTest* + + + + ${db.driver} + ${db.url} + ${db.user} + ${db.pwd} + ${db.platform} + + + + + + + + diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/model/CacheDeadLockDetectionDetail.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/CacheDeadLockDetectionDetail.java similarity index 85% rename from jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/model/CacheDeadLockDetectionDetail.java rename to jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/CacheDeadLockDetectionDetail.java index f209cbc277d..2ca9a7986a2 100644 --- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/model/CacheDeadLockDetectionDetail.java +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/CacheDeadLockDetectionDetail.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -12,22 +12,25 @@ // Contributors: // Oracle - initial API and implementation -package org.eclipse.persistence.jpa.test.cachedeadlock.model; +package org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic; import jakarta.persistence.*; @Entity -@Table(name = "cachedeadlock_detail") +@Table(name = "CACHEDEADLOCK_DETAIL") @Cacheable(true) @NamedQuery(name="DetailEntity.findById", query="SELECT t FROM CacheDeadLockDetectionDetail t WHERE t.id = :id") public class CacheDeadLockDetectionDetail { + @Id + @Column(name = "ID") private long id; + @Column(name = "NAME") private String name; @ManyToOne - @JoinColumn(name = "id_fk") + @JoinColumn(name = "CACHEDEADLOCK_MASTER_FK") private CacheDeadLockDetectionMaster master; public CacheDeadLockDetectionDetail() { diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/model/CacheDeadLockDetectionMaster.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/CacheDeadLockDetectionMaster.java similarity index 85% rename from jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/model/CacheDeadLockDetectionMaster.java rename to jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/CacheDeadLockDetectionMaster.java index 6505b96c1ee..173a231393d 100644 --- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/model/CacheDeadLockDetectionMaster.java +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/CacheDeadLockDetectionMaster.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -12,20 +12,23 @@ // Contributors: // Oracle - initial API and implementation -package org.eclipse.persistence.jpa.test.cachedeadlock.model; +package org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic; import jakarta.persistence.*; import java.util.ArrayList; import java.util.List; @Entity -@Table(name = "cachedeadlock_master") +@Table(name = "CACHEDEADLOCK_MASTER") @Cacheable(true) @NamedQuery(name="MasterEntity.findById", query="SELECT t FROM CacheDeadLockDetectionMaster t WHERE t.id = :id") public class CacheDeadLockDetectionMaster { + @Id + @Column(name = "ID") private long id; + @Column(name = "NAME") private String name; private List details = new ArrayList<>(); @@ -60,7 +63,7 @@ public void setName(String name) { } @OneToMany(fetch = FetchType.LAZY, mappedBy = "master", cascade = CascadeType.ALL) - @JoinColumn(name = "id_fk", referencedColumnName = "id") + @JoinColumn(name = "CACHEDEADLOCK_MASTER_FK", referencedColumnName = "ID") public List getDetails() { return details; } diff --git a/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/DeadLockDiagnosticTableCreator.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/DeadLockDiagnosticTableCreator.java new file mode 100644 index 00000000000..035707a9fe3 --- /dev/null +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/DeadLockDiagnosticTableCreator.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Oracle - initial API and implementation from Oracle TopLink +package org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic; + +import org.eclipse.persistence.tools.schemaframework.FieldDefinition; +import org.eclipse.persistence.tools.schemaframework.ForeignKeyConstraint; +import org.eclipse.persistence.tools.schemaframework.TableDefinition; + +public class DeadLockDiagnosticTableCreator extends org.eclipse.persistence.tools.schemaframework.TableCreator { + + public DeadLockDiagnosticTableCreator() { + setName("DeadLockDiagnostic"); + + addTableDefinition(buildCACHEDEADLOCK_MASTERTable()); + addTableDefinition(buildCACHEDEADLOCK_DETAILTable()); + } + + public TableDefinition buildCACHEDEADLOCK_MASTERTable() { + TableDefinition table = new TableDefinition(); + table.setName("CACHEDEADLOCK_MASTER"); + + FieldDefinition fieldID = new FieldDefinition(); + fieldID.setName("ID"); + fieldID.setTypeName("NUMBER"); + fieldID.setSize(0); + fieldID.setSubSize(0); + fieldID.setIsPrimaryKey(true); + fieldID.setIsIdentity(false); + fieldID.setUnique(false); + fieldID.setShouldAllowNull(false); + table.addField(fieldID); + + FieldDefinition fieldNAME = new FieldDefinition(); + fieldNAME.setName("NAME"); + fieldNAME.setTypeName("VARCHAR"); + fieldNAME.setSize(400); + fieldNAME.setShouldAllowNull(true); + fieldNAME.setIsPrimaryKey(false); + fieldNAME.setUnique(false); + fieldNAME.setIsIdentity(false); + table.addField(fieldNAME); + + return table; + } + + public TableDefinition buildCACHEDEADLOCK_DETAILTable() { + TableDefinition table = new TableDefinition(); + table.setName("CACHEDEADLOCK_DETAIL"); + + FieldDefinition fieldID = new FieldDefinition(); + fieldID.setName("ID"); + fieldID.setTypeName("NUMBER"); + fieldID.setSize(0); + fieldID.setSubSize(0); + fieldID.setIsPrimaryKey(true); + fieldID.setIsIdentity(false); + fieldID.setUnique(false); + fieldID.setShouldAllowNull(false); + table.addField(fieldID); + + FieldDefinition fieldNAME = new FieldDefinition(); + fieldNAME.setName("NAME"); + fieldNAME.setTypeName("VARCHAR"); + fieldNAME.setSize(400); + fieldNAME.setShouldAllowNull(true); + fieldNAME.setIsPrimaryKey(false); + fieldNAME.setUnique(false); + fieldNAME.setIsIdentity(false); + table.addField(fieldNAME); + + FieldDefinition fieldCACHEDEADLOCK_MASTER_FK = new FieldDefinition(); + fieldCACHEDEADLOCK_MASTER_FK.setName("CACHEDEADLOCK_MASTER_FK"); + fieldCACHEDEADLOCK_MASTER_FK.setTypeName("NUMBER"); + fieldCACHEDEADLOCK_MASTER_FK.setSize(0); + fieldCACHEDEADLOCK_MASTER_FK.setSubSize(0); + fieldCACHEDEADLOCK_MASTER_FK.setIsPrimaryKey(false); + fieldCACHEDEADLOCK_MASTER_FK.setIsIdentity(false); + fieldCACHEDEADLOCK_MASTER_FK.setUnique(false); + fieldCACHEDEADLOCK_MASTER_FK.setShouldAllowNull(true); + table.addField(fieldCACHEDEADLOCK_MASTER_FK); + + ForeignKeyConstraint foreignKeyM_CACHEDEADLOCK_MASTER = new ForeignKeyConstraint(); + foreignKeyM_CACHEDEADLOCK_MASTER.setName("M_CACHEDEADLOCK_MASTER_FK"); + foreignKeyM_CACHEDEADLOCK_MASTER.setTargetTable("CACHEDEADLOCK_MASTER"); + foreignKeyM_CACHEDEADLOCK_MASTER.addSourceField("CACHEDEADLOCK_MASTER_FK"); + foreignKeyM_CACHEDEADLOCK_MASTER.addTargetField("ID"); + table.addForeignKeyConstraint(foreignKeyM_CACHEDEADLOCK_MASTER); + + return table; + } +} diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/MainThread.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/MainThread.java similarity index 85% rename from jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/MainThread.java rename to jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/MainThread.java index c7bdf72e143..006268f98a4 100644 --- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/MainThread.java +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/MainThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -12,11 +12,9 @@ // Contributors: // Oracle - initial API and implementation -package org.eclipse.persistence.jpa.test.cachedeadlock; +package org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic; -import org.eclipse.persistence.jpa.test.cachedeadlock.cdi.event.EventProducer; -import org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionMaster; -import org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionDetail; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.event.EventProducer; import jakarta.enterprise.inject.se.SeContainer; import jakarta.inject.Inject; diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventObserver.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventObserver.java similarity index 81% rename from jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventObserver.java rename to jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventObserver.java index fb2951d6db2..41f06d70db0 100644 --- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventObserver.java +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventObserver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -12,10 +12,10 @@ // Contributors: // Oracle - initial API and implementation -package org.eclipse.persistence.jpa.test.cachedeadlock.cdi.event; +package org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.event; -import org.eclipse.persistence.jpa.test.cachedeadlock.MainThread; -import org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionMaster; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.MainThread; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionMaster; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventProducer.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventProducer.java similarity index 68% rename from jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventProducer.java rename to jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventProducer.java index 6f1a1945830..4471d821be7 100644 --- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventProducer.java +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventProducer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -12,9 +12,9 @@ // Contributors: // Oracle - initial API and implementation -package org.eclipse.persistence.jpa.test.cachedeadlock.cdi.event; +package org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.event; -import org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionMaster; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionMaster; public interface EventProducer { diff --git a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventProducerImpl.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventProducerImpl.java similarity index 76% rename from jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventProducerImpl.java rename to jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventProducerImpl.java index bfbf42b05b3..1416fe6480d 100644 --- a/jpa/eclipselink.jpa.test.jse/src/it/java/org/eclipse/persistence/jpa/test/cachedeadlock/cdi/event/EventProducerImpl.java +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/java/org/eclipse/persistence/testing/models/jpa/deadlock/diagnostic/event/EventProducerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -12,9 +12,9 @@ // Contributors: // Oracle - initial API and implementation -package org.eclipse.persistence.jpa.test.cachedeadlock.cdi.event; +package org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.event; -import org.eclipse.persistence.jpa.test.cachedeadlock.model.CacheDeadLockDetectionMaster; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionMaster; import jakarta.enterprise.event.Event; import jakarta.enterprise.inject.Any; diff --git a/jpa/eclipselink.jpa.test.jse/src/it/resources/META-INF/beans.xml b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/resources/META-INF/beans.xml similarity index 89% rename from jpa/eclipselink.jpa.test.jse/src/it/resources/META-INF/beans.xml rename to jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/resources/META-INF/beans.xml index 0ea132eff10..b54469f18ad 100644 --- a/jpa/eclipselink.jpa.test.jse/src/it/resources/META-INF/beans.xml +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/main/resources/META-INF/beans.xml @@ -1,7 +1,7 @@ + + + + + org.eclipse.persistence.jpa.PersistenceProvider + org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionMaster + org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionDetail + true + + + + + + + + + + + + + + org.eclipse.persistence.jpa.PersistenceProvider + org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionMaster + org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionDetail + true + + + + + + + + + + + + + + + + + diff --git a/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/CacheDeadLockDetectionTest.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/CacheDeadLockDetectionTest.java new file mode 100644 index 00000000000..9db2003bca4 --- /dev/null +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/CacheDeadLockDetectionTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Oracle - initial API and implementation +package org.eclipse.persistence.testing.tests.jpa.deadlock.diagnostic; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import jakarta.enterprise.inject.se.SeContainer; +import jakarta.enterprise.inject.se.SeContainerInitializer; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Persistence; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.junit.Assert; + +import org.eclipse.persistence.internal.sessions.AbstractSession; +import org.eclipse.persistence.jpa.JpaEntityManager; +import org.eclipse.persistence.logging.AbstractSessionLog; + +import org.eclipse.persistence.internal.helper.ConcurrencyUtil; +import org.eclipse.persistence.testing.framework.jpa.junit.JUnitTestCase; +import org.eclipse.persistence.testing.framework.junit.JUnitTestCaseHelper; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionDetail; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionMaster; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.DeadLockDiagnosticTableCreator; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.MainThread; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.event.EventProducer; + +public class CacheDeadLockDetectionTest extends JUnitTestCase { + + public static final int RECORDS_NO = 10; + public static final int NO_OF_THREADS = 100; + + SeContainer container; + + EventProducer eventProducer; + + public CacheDeadLockDetectionTest() { + } + + public CacheDeadLockDetectionTest(String name) { + super(name); + setPuName(getPersistenceUnitName()); + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.setName("CacheDeadLockDetectionTest"); + suite.addTest(new CacheDeadLockDetectionTest("testSetup")); + suite.addTest(new CacheDeadLockDetectionTest("testVerifyPersistenceAndBasicLogOutput")); + suite.addTest(new CacheDeadLockDetectionTest("testVerifySemaphorePersistenceProperties")); + return suite; + } + + /** + * The setup is done as a test, both to record its failure, and to allow + * execution in the server. + */ + public void testSetup() { + EntityManagerFactory emf = Persistence.createEntityManagerFactory("cachedeadlockdetection-pu", JUnitTestCaseHelper.getDatabaseProperties()); + EntityManager em = emf.createEntityManager(); + new DeadLockDiagnosticTableCreator().replaceTables(((JpaEntityManager)em).getServerSession()); + clearCache("cachedeadlockdetection-pu"); + try { + em.getTransaction().begin(); + initData(em); + em.getTransaction().commit(); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(); + } finally { + if (em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + if (em.isOpen()) { + em.close(); + } + if (emf.isOpen()) { + emf.close(); + } + } + } + + public void testVerifyPersistenceAndBasicLogOutput() { + initContainer(); + EntityManagerFactory emf = Persistence.createEntityManagerFactory("cachedeadlockdetection-pu", JUnitTestCaseHelper.getDatabaseProperties()); + EntityManager em = emf.createEntityManager(); + AbstractSession serverSession = ((JpaEntityManager)em).getServerSession(); + LogWrapper logWrapper = new LogWrapper(); + serverSession.setSessionLog(logWrapper); + AbstractSessionLog.setLog(logWrapper); + verifyPersistenceProperties(); + threadExecution(em, emf); + try { + Thread.sleep(7000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + if (em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + if (em.isOpen()) { + em.close(); + } + if (emf.isOpen()) { + emf.close(); + } + closeContainer(); + } + //Check if at least one log message is generated + assertTrue(logWrapper.getMessageCount("Stuck thread problem: unique tiny message number") > 0); + assertTrue(logWrapper.getMessageCount("Start full concurrency manager state \\(massive\\) dump No") > 0); + } + + public void testVerifySemaphorePersistenceProperties() { + EntityManagerFactory emfSemaphore = Persistence.createEntityManagerFactory("cachedeadlocksemaphore-pu", JUnitTestCaseHelper.getDatabaseProperties()); + EntityManager emSemaphore = emfSemaphore.createEntityManager(); + verifySemaphoreProperties(); + } + + private void initContainer() { + container = SeContainerInitializer.newInstance().initialize(); + eventProducer = container.select(EventProducer.class).get(); + } + + private void closeContainer() { + if (container != null && container.isRunning()) { + container.close(); + } + } + + private void threadExecution(EntityManager em, EntityManagerFactory emf) { + ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(NO_OF_THREADS); + for (int i = 1; i <= NO_OF_THREADS; i++) { + Thread thread = new Thread(new MainThread(container, emf, em)); + thread.setName("MainThread: " + i); + executor.execute(thread); + } + executor.shutdown(); + // Wait for everything to finish. + try { + if (!executor.awaitTermination(10000, TimeUnit.MILLISECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + e.printStackTrace(); + Assert.fail(); + } + } + + private static void initData(EntityManager em) { + for (int i = 1, j = 1; i <= RECORDS_NO; i++, j = j + 2) { + CacheDeadLockDetectionMaster cacheDeadLockDetectionMaster = new CacheDeadLockDetectionMaster(i, "M" + i); + CacheDeadLockDetectionDetail cacheDeadLockDetectionDetail1 = new CacheDeadLockDetectionDetail(j, "D" + j); + CacheDeadLockDetectionDetail cacheDeadLockDetectionDetail2 = new CacheDeadLockDetectionDetail(j + 1, "D" + (j + 1)); + cacheDeadLockDetectionDetail1.setMaster(cacheDeadLockDetectionMaster); + cacheDeadLockDetectionDetail2.setMaster(cacheDeadLockDetectionMaster); + em.persist(cacheDeadLockDetectionMaster); + em.persist(cacheDeadLockDetectionDetail1); + em.persist(cacheDeadLockDetectionDetail2); + } + } + + private void verifyPersistenceProperties() { + Assert.assertEquals(1L, ConcurrencyUtil.SINGLETON.getAcquireWaitTime()); + Assert.assertEquals(2L, ConcurrencyUtil.SINGLETON.getMaxAllowedSleepTime()); + Assert.assertEquals(800L, ConcurrencyUtil.SINGLETON.getMaxAllowedFrequencyToProduceTinyDumpLogMessage()); + Assert.assertEquals(1000L, ConcurrencyUtil.SINGLETON.getMaxAllowedFrequencyToProduceMassiveDumpLogMessage()); + Assert.assertEquals(5L, ConcurrencyUtil.SINGLETON.getBuildObjectCompleteWaitTime()); + Assert.assertTrue(ConcurrencyUtil.SINGLETON.isAllowTakingStackTraceDuringReadLockAcquisition()); + Assert.assertTrue(ConcurrencyUtil.SINGLETON.isAllowConcurrencyExceptionToBeFiredUp()); + Assert.assertTrue(ConcurrencyUtil.SINGLETON.isAllowInterruptedExceptionFired()); + } + + private void verifySemaphoreProperties() { + Assert.assertEquals(1L, ConcurrencyUtil.SINGLETON.getAcquireWaitTime()); + Assert.assertEquals(2L, ConcurrencyUtil.SINGLETON.getMaxAllowedSleepTime()); + Assert.assertEquals(1000L, ConcurrencyUtil.SINGLETON.getMaxAllowedFrequencyToProduceTinyDumpLogMessage()); + Assert.assertEquals(2000L, ConcurrencyUtil.SINGLETON.getMaxAllowedFrequencyToProduceMassiveDumpLogMessage()); + Assert.assertTrue(ConcurrencyUtil.SINGLETON.isAllowTakingStackTraceDuringReadLockAcquisition()); + Assert.assertTrue(ConcurrencyUtil.SINGLETON.isAllowConcurrencyExceptionToBeFiredUp()); + Assert.assertTrue(ConcurrencyUtil.SINGLETON.isAllowInterruptedExceptionFired()); + Assert.assertTrue(ConcurrencyUtil.SINGLETON.isUseSemaphoreInObjectBuilder()); + Assert.assertEquals(5L, ConcurrencyUtil.SINGLETON.getNoOfThreadsAllowedToObjectBuildInParallel()); + Assert.assertTrue(ConcurrencyUtil.SINGLETON.isUseSemaphoreToLimitConcurrencyOnWriteLockManagerAcquireRequiredLocks()); + Assert.assertEquals(6L, ConcurrencyUtil.SINGLETON.getNoOfThreadsAllowedToDoWriteLockManagerAcquireRequiredLocksInParallel()); + Assert.assertEquals(7L, ConcurrencyUtil.SINGLETON.getConcurrencySemaphoreMaxTimePermit()); + Assert.assertEquals(8L, ConcurrencyUtil.SINGLETON.getConcurrencySemaphoreLogTimeout()); + } +} diff --git a/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/CacheDeadLockManagersTest.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/CacheDeadLockManagersTest.java new file mode 100644 index 00000000000..9881f802b91 --- /dev/null +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/CacheDeadLockManagersTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Oracle - initial API and implementation +package org.eclipse.persistence.testing.tests.jpa.deadlock.diagnostic; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.Persistence; +import jakarta.persistence.Query; +import junit.framework.Test; +import junit.framework.TestSuite; +import org.eclipse.persistence.descriptors.ClassDescriptor; +import org.eclipse.persistence.internal.helper.ConcurrencyUtil; +import org.eclipse.persistence.internal.helper.WriteLockManager; +import org.eclipse.persistence.internal.identitymaps.CacheKey; +import org.eclipse.persistence.internal.jpa.EJBQueryImpl; +import org.eclipse.persistence.internal.sessions.AbstractSession; +import org.eclipse.persistence.jpa.JpaEntityManager; +import org.eclipse.persistence.logging.AbstractSessionLog; +import org.eclipse.persistence.queries.ObjectBuildingQuery; +import org.eclipse.persistence.testing.framework.jpa.junit.JUnitTestCase; +import org.eclipse.persistence.testing.framework.junit.JUnitTestCaseHelper; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionDetail; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.CacheDeadLockDetectionMaster; +import org.eclipse.persistence.testing.models.jpa.deadlock.diagnostic.DeadLockDiagnosticTableCreator; + +import java.util.Map; + +public class CacheDeadLockManagersTest extends JUnitTestCase { + + public static final int RECORDS_NO = 10; + + public CacheDeadLockManagersTest() { + } + + public CacheDeadLockManagersTest(String name) { + super(name); + setPuName(getPersistenceUnitName()); + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.setName("CacheDeadLockDetectionTest"); + suite.addTest(new CacheDeadLockManagersTest("testSetup")); + suite.addTest(new CacheDeadLockManagersTest("testWriteLockManagerAcquireLocksForClone")); + return suite; + } + + /** + * The setup is done as a test, both to record its failure, and to allow + * execution in the server. + */ + public void testSetup() { + EntityManagerFactory emf = Persistence.createEntityManagerFactory("cachedeadlockdetection-pu", JUnitTestCaseHelper.getDatabaseProperties()); + EntityManager em = emf.createEntityManager(); + new DeadLockDiagnosticTableCreator().replaceTables(((JpaEntityManager)em).getServerSession()); + clearCache("cachedeadlockdetection-pu"); + try { + em.getTransaction().begin(); + initData(em); + em.getTransaction().commit(); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(); + } finally { + if (em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + if (em.isOpen()) { + em.close(); + } + if (emf.isOpen()) { + emf.close(); + } + } + } + + public void testWriteLockManagerAcquireLocksForClone() { + EntityManagerFactory emf = Persistence.createEntityManagerFactory("cachedeadlockdetection-pu", JUnitTestCaseHelper.getDatabaseProperties()); + EntityManager em = emf.createEntityManager(); + AbstractSession serverSession = ((JpaEntityManager)em).getServerSession(); + LogWrapper logWrapper = new LogWrapper(); + serverSession.setSessionLog(logWrapper); + AbstractSessionLog.setLog(logWrapper); + try { + Long primaryKey = Long.valueOf(1L); + Query query = em.createQuery("SELECT c FROM CacheDeadLockDetectionMaster c WHERE c.id = :id"); + query.setParameter("id", primaryKey); + CacheDeadLockDetectionMaster result = (CacheDeadLockDetectionMaster) query.getSingleResult(); + ClassDescriptor descriptor = serverSession.getDescriptor(CacheDeadLockDetectionMaster.class); + CacheKey cacheKey = serverSession.retrieveCacheKey(primaryKey, descriptor, null, (ObjectBuildingQuery) ((EJBQueryImpl)query).getDatabaseQuery()); + cacheKey.setInvalidationState(CacheKey.CACHE_KEY_INVALID); + //Tricky part with some negative value to simulate deadlock detection. + ConcurrencyUtil.SINGLETON.setMaxAllowedSleepTime(-1000000); + ConcurrencyUtil.SINGLETON.setAllowConcurrencyExceptionToBeFiredUp(true); + WriteLockManager writeLockManager = new WriteLockManager(); + Map map = writeLockManager.acquireLocksForClone(result, descriptor, cacheKey, serverSession); + } catch (Exception e) { + assertEquals(2, logWrapper.getMessageCount(WriteLockManager.class.getName() + ".acquireLocksForClone")); + } finally { + if (em != null) { + if (em.isOpen()) { + em.close(); + } + } + } + } + + private static void initData(EntityManager em) { + for (int i = 1, j = 1; i <= RECORDS_NO; i++, j = j + 2) { + CacheDeadLockDetectionMaster cacheDeadLockDetectionMaster = new CacheDeadLockDetectionMaster(i, "M" + i); + CacheDeadLockDetectionDetail cacheDeadLockDetectionDetail1 = new CacheDeadLockDetectionDetail(j, "D" + j); + CacheDeadLockDetectionDetail cacheDeadLockDetectionDetail2 = new CacheDeadLockDetectionDetail(j + 1, "D" + (j + 1)); + cacheDeadLockDetectionDetail1.setMaster(cacheDeadLockDetectionMaster); + cacheDeadLockDetectionDetail2.setMaster(cacheDeadLockDetectionMaster); + em.persist(cacheDeadLockDetectionMaster); + em.persist(cacheDeadLockDetectionDetail1); + em.persist(cacheDeadLockDetectionDetail2); + } + } +} diff --git a/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/LogWrapper.java b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/LogWrapper.java new file mode 100644 index 00000000000..f6e0d481fad --- /dev/null +++ b/jpa/eclipselink.jpa.testapps/jpa.test.diagnostic.deadlock/src/test/java/org/eclipse/persistence/testing/tests/jpa/deadlock/diagnostic/LogWrapper.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Oracle - initial API and implementation from Oracle TopLink +package org.eclipse.persistence.testing.tests.jpa.deadlock.diagnostic; + +import org.eclipse.persistence.logging.DefaultSessionLog; +import org.eclipse.persistence.logging.SessionLogEntry; + +import java.io.StringWriter; +import java.util.regex.Pattern; + +//Simple log handler which counts selected messages. +public class LogWrapper extends DefaultSessionLog { + + private StringWriter sw = new StringWriter(); + + public LogWrapper() { + super.setWriter(sw); + } + + + @Override + public synchronized void log(SessionLogEntry entry) { + super.log(entry); + } + + @Override + public boolean shouldLog(int level, String category) { + return true; + } + + public long getMessageCount(String checkedMessage) { + String logOutput = sw.toString(); + return Pattern.compile(checkedMessage) + .matcher(logOutput) + .results() + .count(); + } +} diff --git a/jpa/eclipselink.jpa.testapps/pom.xml b/jpa/eclipselink.jpa.testapps/pom.xml index 0fc9582dbd3..60c1859c8fe 100644 --- a/jpa/eclipselink.jpa.testapps/pom.xml +++ b/jpa/eclipselink.jpa.testapps/pom.xml @@ -306,6 +306,7 @@ jpa.test.ddlgeneration jpa.test.delimited jpa.test.diagnostic + jpa.test.diagnostic.deadlock jpa.test.extensibility jpa.test.fetchgroups jpa.test.fieldaccess.advanced