[hibernate-commits] Hibernate SVN: r18681 - in core/trunk: entitymanager/src/test/java/org/hibernate/ejb/test and 1 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Feb 2 12:03:06 EST 2010


Author: smarlow at redhat.com
Date: 2010-02-02 12:03:05 -0500 (Tue, 02 Feb 2010)
New Revision: 18681

Modified:
   core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
Log:
HHH-4765 Enhance Dialect support for JPA-2 locking

Modified: core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java	2010-02-01 21:02:12 UTC (rev 18680)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java	2010-02-02 17:03:05 UTC (rev 18681)
@@ -30,6 +30,7 @@
 import java.sql.Types;
 
 import org.hibernate.Hibernate;
+import org.hibernate.LockOptions;
 import org.hibernate.cfg.Environment;
 import org.hibernate.dialect.function.NoArgSQLFunction;
 import org.hibernate.dialect.function.PositionSubstringFunction;
@@ -359,16 +360,23 @@
 		return false;
 	}
 
+	// locking support
 	public String getForUpdateString() {
 		return " for update";
 	}
 
 	public String getWriteLockString(int timeout) {
-		return " for update";
+		if ( timeout == LockOptions.NO_WAIT )
+			return " for update nowait";
+		else
+			return " for update";
 	}
 
 	public String getReadLockString(int timeout) {
-		return " for share";
+		if ( timeout == LockOptions.NO_WAIT )
+			return " for share nowait";
+		else
+			return " for share";
 	}
 
 }

Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java	2010-02-01 21:02:12 UTC (rev 18680)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/TestCase.java	2010-02-02 17:03:05 UTC (rev 18681)
@@ -28,6 +28,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Properties;
 import javax.persistence.EntityManager;
@@ -55,6 +56,7 @@
 
 	protected static EntityManagerFactory factory;
 	private EntityManager em;
+	private ArrayList isolatedEms = new ArrayList();
 
 
 	public TestCase() {
@@ -80,7 +82,7 @@
 		factory = ejbconfig.createEntityManagerFactory( getConfig() );
 	}
 
-	protected void handleUnclosedResources(){
+	private void cleanUnclosed(EntityManager em){
 		if(em == null) {
 			return;
 		}
@@ -94,6 +96,13 @@
 			em.close();
 			log.warn( "The EntityManager is not closed. Closing it." );
 		}
+	}
+	protected void handleUnclosedResources(){
+		cleanUnclosed( this.em );
+		for ( Iterator iter = isolatedEms.iterator(); iter.hasNext();) {
+			cleanUnclosed( (EntityManager)iter.next() );
+		}
+
 		cfg = null;
 	}
 
@@ -110,6 +119,12 @@
 		return em;
 	}
 
+	protected EntityManager createIsolatedEntityManager() {
+		EntityManager isolatedEm = factory.createEntityManager( );
+		isolatedEms.add( isolatedEm );
+		return isolatedEm;
+	}
+
 	/**
 	 * always reopen a new EM and clse the existing one
 	 */

Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java	2010-02-01 21:02:12 UTC (rev 18680)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java	2010-02-02 17:03:05 UTC (rev 18681)
@@ -5,13 +5,20 @@
 import javax.persistence.LockModeType;
 import javax.persistence.OptimisticLockException;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.dialect.HSQLDialect;
 import org.hibernate.ejb.test.TestCase;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * @author Emmanuel Bernard
  */
 public class LockTest extends TestCase {
 
+	private static final Log log = LogFactory.getLog( LockTest.class );
 	public void testLockRead() throws Exception {
 		Lock lock = new Lock();
 		lock.setName( "name" );
@@ -167,7 +174,77 @@
 		}
 		em.close();
 	}
-	
+
+	public void testContendedPessimisticLock() throws Exception {
+
+		EntityManager em = getOrCreateEntityManager();
+		final EntityManager em2 = createIsolatedEntityManager();
+		// TODO:  replace dialect instanceof test with a Dialect.hasCapability (e.g. supportsPessimisticWriteLock)
+		if ( getDialect() instanceof HSQLDialect) {
+			log.info("skipping testContendedPessimisticLock");
+			return;
+		}
+		Lock lock = new Lock();
+		Thread t = null;
+		try {
+			lock.setName( "contendedLock" );
+
+			em.getTransaction().begin();
+			em.persist( lock );
+			em.getTransaction().commit();
+			em.clear();
+
+			em.getTransaction().begin();
+			lock = em.getReference( Lock.class, lock.getId() );
+			em.lock( lock, LockModeType.PESSIMISTIC_WRITE );
+			final Integer id = lock.getId();
+			lock.getName();		// force entity to be read
+			log.info("testContendedPessimisticLock: got write lock");
+			final CountDownLatch latch = new CountDownLatch(1);
+
+			t = new Thread( new Runnable() {
+				public void run() {
+
+					em2.getTransaction().begin();
+					log.info("testContendedPessimisticLock: (BG) about to read write-locked entity");
+					// we should block on the following read
+					Lock lock2 = em2.getReference( Lock.class, id );
+					lock2.getName();		//  force entity to be read
+					log.info("testContendedPessimisticLock: (BG) read write-locked entity");
+					em2.lock( lock2, LockModeType.PESSIMISTIC_READ);
+					log.info("testContendedPessimisticLock: (BG) got read lock on entity");
+					em2.getTransaction().commit();
+					latch.countDown();	// signal that we got the read lock
+				}
+			} );
+
+			// t.setDaemon( true );
+			t.setName("LockTest read lock");
+			t.start();
+			log.info("testContendedPessimisticLock:  wait on BG thread");
+			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );
+			// latchSet should be false (timeout) because the background thread
+			// shouldn't be able to get a read lock on write locked entity.
+			log.info("testContendedPessimisticLock:  BG thread completed transaction");
+			assertFalse( "shouldn't be able to get read lock while another transaction has write lock",latchSet );
+			em.getTransaction().commit();
+		}
+		finally {
+			if ( em.getTransaction().isActive() ) {
+				em.getTransaction().rollback();
+			}
+			if ( t != null) {	  // wait for background thread to finish before deleting entity
+				t.join();
+			}
+			em.getTransaction().begin();
+			lock = em.getReference( Lock.class, lock.getId() );
+			em.remove( lock );
+			em.getTransaction().commit();
+			em.close();
+			em2.close();
+		}
+	}
+
 	public Class[] getAnnotatedClasses() {
 		return new Class[]{
 				Lock.class,



More information about the hibernate-commits mailing list