forked from eclipse-ee4j/eclipselink
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fixes coalesce and case operators in multithreaded environments (ecli…
- Loading branch information
1 parent
e1d8076
commit 6b8c205
Showing
3 changed files
with
113 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
.../org/eclipse/persistence/jpa/test/jpql/TestArgumentListFunctionExpressionConcurrency.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package org.eclipse.persistence.jpa.test.jpql; | ||
|
||
|
||
import java.util.ArrayList; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
import java.util.function.ObjIntConsumer; | ||
|
||
import javax.persistence.EntityManager; | ||
import javax.persistence.EntityManagerFactory; | ||
|
||
import org.eclipse.persistence.jpa.test.framework.DDLGen; | ||
import org.eclipse.persistence.jpa.test.framework.Emf; | ||
import org.eclipse.persistence.jpa.test.framework.EmfRunner; | ||
import org.eclipse.persistence.jpa.test.jpql.model.JPQLEntity; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
|
||
/** | ||
* This test reproduces the issues #2136, #1867 and #1717. | ||
*/ | ||
@RunWith(EmfRunner.class) | ||
public class TestArgumentListFunctionExpressionConcurrency { | ||
|
||
private static final int MAX_THREADS = Math.min(Runtime.getRuntime().availableProcessors(), 4); | ||
private static final int ITERATIONS_PER_THREAD = 1000; | ||
|
||
@Emf(name = "argumentListFunctionExpressionConcurrencyEMF", createTables = DDLGen.DROP_CREATE, classes = { JPQLEntity.class }) | ||
private EntityManagerFactory emf; | ||
|
||
@Test | ||
public void testConcurrentUseOfCoalesce() throws Exception { | ||
runInParallel((em, i) -> { | ||
var jpql = "SELECT p FROM JPQLEntity p" | ||
+ " WHERE p.string1 = coalesce(p.string2, '" + cacheBuster(i) + "')"; | ||
|
||
em.createQuery(jpql, JPQLEntity.class).getResultList(); | ||
}); | ||
} | ||
|
||
@Test | ||
public void testConcurrentUseOfCaseCondition() throws Exception { | ||
runInParallel((em, i) -> { | ||
var jpql = "SELECT p FROM JPQLEntity p" | ||
+ " WHERE p.string1 = case when p.string2 = '" + cacheBuster(i) + "' then null else p.string1 end"; | ||
|
||
em.createQuery(jpql, JPQLEntity.class).getResultList(); | ||
}); | ||
} | ||
|
||
private static String cacheBuster(Integer i) { | ||
return "cacheBuster." + Thread.currentThread().getName() + "." + i; | ||
} | ||
|
||
private void runInParallel(ObjIntConsumer<EntityManager> runnable) throws Exception { | ||
var exception = new AtomicReference<Exception>(); | ||
|
||
// start all threads | ||
var threads = new ArrayList<Thread>(); | ||
for (int t = 0; t < MAX_THREADS; t++) { | ||
var thread = new Thread(() -> { | ||
try { | ||
for (int i = 0; i < ITERATIONS_PER_THREAD; i++) { | ||
if (exception.get() != null) { | ||
return; | ||
} | ||
|
||
var em = emf.createEntityManager(); | ||
try { | ||
runnable.accept(em, i); | ||
} finally { | ||
em.close(); | ||
} | ||
|
||
} | ||
} catch (Exception e) { | ||
exception.set(e); | ||
} | ||
}); | ||
threads.add(thread); | ||
thread.start(); | ||
} | ||
|
||
// wait for all threads to finish | ||
threads.forEach(thread -> { | ||
try { | ||
thread.join(); | ||
} catch (InterruptedException e) { | ||
exception.set(e); | ||
} | ||
}); | ||
|
||
// throw the first exception that occurred | ||
if (exception.get() != null) { | ||
throw exception.get(); | ||
} | ||
} | ||
} |