Skip to content

Commit 5c5442f

Browse files
committed
HHH-19898 Add test case
1 parent 9f39c0a commit 5c5442f

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.locking.jpa;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.Id;
9+
import jakarta.persistence.LockModeType;
10+
import jakarta.persistence.LockTimeoutException;
11+
import jakarta.persistence.Timeout;
12+
import org.hibernate.dialect.OracleDialect;
13+
import org.hibernate.dialect.PostgreSQLDialect;
14+
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
15+
import org.hibernate.testing.orm.junit.JiraKey;
16+
import org.hibernate.testing.orm.junit.Jpa;
17+
import org.hibernate.testing.orm.junit.RequiresDialect;
18+
import org.junit.jupiter.api.Test;
19+
20+
import java.util.concurrent.CountDownLatch;
21+
import java.util.concurrent.TimeUnit;
22+
23+
import static org.junit.jupiter.api.Assertions.assertEquals;
24+
import static org.junit.jupiter.api.Assertions.assertNotNull;
25+
import static org.junit.jupiter.api.Assertions.assertThrows;
26+
import static org.junit.jupiter.api.Assertions.assertTrue;
27+
28+
@Jpa(
29+
annotatedClasses = {
30+
NoWaitLockingTest.Foo.class
31+
}
32+
)
33+
public class NoWaitLockingTest {
34+
35+
@Entity
36+
public static class Foo {
37+
@Id
38+
public int id;
39+
}
40+
41+
// Add your tests, using standard JUnit.
42+
@Test
43+
@RequiresDialect(PostgreSQLDialect.class)
44+
@RequiresDialect(OracleDialect.class)
45+
@JiraKey( "HHH-19898" )
46+
void hhh19898Test(EntityManagerFactoryScope scope) throws Exception {
47+
scope.inTransaction( em -> {
48+
Foo foo = new Foo();
49+
foo.id = 1;
50+
em.persist( foo );
51+
});
52+
53+
final CountDownLatch lAcquireLock = new CountDownLatch( 1 );
54+
final CountDownLatch lPastNowait = new CountDownLatch( 1 );
55+
56+
final Thread t = new Thread(() -> {
57+
scope.inTransaction( em -> {
58+
Foo foo = em.find( Foo.class, 1, LockModeType.PESSIMISTIC_WRITE );
59+
assertEquals( LockModeType.PESSIMISTIC_WRITE, em.getLockMode( foo ) );
60+
assertNotNull( foo );
61+
62+
// We have the lock!
63+
lAcquireLock.countDown();
64+
65+
// Now wait until we are done with NOWAIT
66+
awaitLatch( lPastNowait );
67+
68+
// Now we are done, can commit, and free the lock
69+
} );
70+
});
71+
72+
// Start the thread that locks the entity and waits until we have executed the first LOCK NOWAIT
73+
t.start();
74+
75+
scope.inTransaction( em -> {
76+
// Wait until the thread has the lock
77+
awaitLatch( lAcquireLock );
78+
79+
Foo foo = em.find( Foo.class, 1 );
80+
81+
// Sanity check
82+
assertTrue( em.getTransaction().isActive() );
83+
84+
// Do the nowait!
85+
assertThrows( LockTimeoutException.class, () -> em.lock( foo, LockModeType.PESSIMISTIC_WRITE, Timeout.ms( 0 )) );
86+
assertEquals( LockModeType.NONE, em.getLockMode( foo ) );
87+
88+
lPastNowait.countDown();
89+
joinThread( t );
90+
91+
// Only the statement should be rolled back, not the transaction!
92+
assertTrue( em.getTransaction().isActive() );
93+
94+
// Try persisting a new entity to check that the transaction is stil alive
95+
Foo foo2 = new Foo();
96+
foo2.id = 42;
97+
em.persist( foo2 );
98+
em.flush(); // Force the insert
99+
100+
// Now try locking again!
101+
em.lock( foo, LockModeType.PESSIMISTIC_WRITE, Timeout.ms( 0 ));
102+
assertEquals( LockModeType.PESSIMISTIC_WRITE, em.getLockMode( foo ) );
103+
} );
104+
}
105+
106+
private static void awaitLatch(CountDownLatch l) {
107+
try {
108+
if(!l.await(1000, TimeUnit.MILLISECONDS)) {
109+
throw new RuntimeException("TIMEOUT!");
110+
}
111+
}
112+
catch (InterruptedException e) {
113+
Thread.currentThread().interrupt();
114+
throw new RuntimeException( e );
115+
}
116+
}
117+
118+
private static void joinThread(Thread t) {
119+
try {
120+
t.join(1000);
121+
}
122+
catch (InterruptedException e) {
123+
Thread.currentThread().interrupt();
124+
throw new RuntimeException( e );
125+
}
126+
}
127+
}

0 commit comments

Comments
 (0)