[hibernate-commits] Hibernate SVN: r18852 - in core/trunk: core/src/main/java/org/hibernate/exception and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Feb 22 18:27:17 EST 2010


Author: smarlow at redhat.com
Date: 2010-02-22 18:27:16 -0500 (Mon, 22 Feb 2010)
New Revision: 18852

Modified:
   core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
   core/trunk/core/src/main/java/org/hibernate/exception/SQLStateConverter.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryHints.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java
Log:
HHH-4662 Implement javax.persistence.query.timeout

Modified: core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java	2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/annotations/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java	2010-02-22 23:27:16 UTC (rev 18852)
@@ -1,7 +1,7 @@
 /*
  * Hibernate, Relational Persistence for Idiomatic Java
  *
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as
  * indicated by the @author tags or express copyright attribution
  * statements applied by the authors.  All third-party contributions are
  * distributed under license by Red Hat Middleware LLC.
@@ -69,7 +69,7 @@
 				queryName,
 				getBoolean( queryName, "org.hibernate.cacheable", hints ),
 				getString( queryName, "org.hibernate.cacheRegion", hints ),
-				getInteger( queryName, "org.hibernate.timeout", hints ),
+				getTimeout( queryName, hints ),
 				getInteger( queryName, "org.hibernate.fetchSize", hints ),
 				getFlushMode( queryName, hints ),
 				getCacheMode( queryName, hints ),
@@ -105,7 +105,7 @@
 					null,
 					getBoolean( queryName, "org.hibernate.cacheable", hints ),
 					getString( queryName, "org.hibernate.cacheRegion", hints ),
-					getInteger( queryName, "org.hibernate.timeout", hints ),
+					getTimeout( queryName, hints ),
 					getInteger( queryName, "org.hibernate.fetchSize", hints ),
 					getFlushMode( queryName, hints ),
 					getCacheMode( queryName, hints ),
@@ -126,7 +126,7 @@
 					null,
 					getBoolean( queryName, "org.hibernate.cacheable", hints ),
 					getString( queryName, "org.hibernate.cacheRegion", hints ),
-					getInteger( queryName, "org.hibernate.timeout", hints ),
+					getTimeout( queryName, hints ),
 					getInteger( queryName, "org.hibernate.fetchSize", hints ),
 					getFlushMode( queryName, hints ),
 					getCacheMode( queryName, hints ),
@@ -407,4 +407,18 @@
 		}
 		return null;
 	}
+
+	private static Integer getTimeout(String queryName, QueryHint[] hints) {
+		Integer timeout = getInteger( queryName, "javax.persistence.query.timeout", hints );
+
+		if ( timeout != null ) {
+			// convert milliseconds to seconds
+			timeout = new Integer ((int)Math.round(timeout.doubleValue() / 1000.0 ) );
+		}
+		else {
+			// timeout is already in seconds
+			timeout = getInteger( queryName, "org.hibernate.timeout", hints );
+		}
+		return timeout;
+	}
 }

Modified: core/trunk/core/src/main/java/org/hibernate/exception/SQLStateConverter.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/exception/SQLStateConverter.java	2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/core/src/main/java/org/hibernate/exception/SQLStateConverter.java	2010-02-22 23:27:16 UTC (rev 18852)
@@ -1,7 +1,7 @@
 /*
  * Hibernate, Relational Persistence for Idiomatic Java
  *
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as
  * indicated by the @author tags or express copyright attribution
  * statements applied by the authors.  All third-party contributions are
  * distributed under license by Red Hat Middleware LLC.
@@ -26,6 +26,7 @@
 
 import org.hibernate.JDBCException;
 import org.hibernate.PessimisticLockException;
+import org.hibernate.QueryTimeoutException;
 
 import java.sql.SQLException;
 import java.util.HashSet;
@@ -115,6 +116,13 @@
 				// Derby "A lock could not be obtained within the time requested."
 				return new PessimisticLockException( message, sqlException, sql );
 			}
+
+			// MySQL Query execution was interrupted
+			if ( "70100".equals( sqlState ) ||
+				// Oracle user requested cancel of current operation
+				  "72000".equals( sqlState ) ) {
+				throw new QueryTimeoutException(  message, sqlException, sql );
+			}
 		}
 
 		return handledNonSpecificException( sqlException, message, sql );

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java	2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java	2010-02-22 23:27:16 UTC (rev 18852)
@@ -1130,6 +1130,11 @@
 			handlePersistenceException( converted );
 			return converted;
 		}
+		else if ( e instanceof org.hibernate.QueryTimeoutException ) {
+			QueryTimeoutException converted = new QueryTimeoutException(e.getMessage(), e);
+			handlePersistenceException( converted );
+			return converted;
+		}
 		else if ( e instanceof ObjectNotFoundException ) {
 			EntityNotFoundException converted = new EntityNotFoundException( e.getMessage() );
 			handlePersistenceException( converted );

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java	2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractQueryImpl.java	2010-02-22 23:27:16 UTC (rev 18852)
@@ -1,7 +1,7 @@
 /*
  * Hibernate, Relational Persistence for Idiomatic Java
  *
- * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
+ * Copyright (c) 2010 by Red Hat Inc and/or its affiliates or by
  * third-party contributors as indicated by either @author tags or express
  * copyright attribution statements applied by the authors.  All
  * third-party contributions are distributed under license by Red Hat Inc.
@@ -50,6 +50,7 @@
 import static org.hibernate.ejb.QueryHints.HINT_FLUSH_MODE;
 import static org.hibernate.ejb.QueryHints.HINT_READONLY;
 import static org.hibernate.ejb.QueryHints.HINT_TIMEOUT;
+import static org.hibernate.ejb.QueryHints.SPEC_HINT_TIMEOUT;
 
 import org.hibernate.ejb.util.CacheModeHelper;
 import org.hibernate.ejb.util.ConfigurationHelper;
@@ -204,6 +205,11 @@
 			if ( HINT_TIMEOUT.equals( hintName ) ) {
 				applyTimeout( ConfigurationHelper.getInteger( value ) );
 			}
+			else if ( SPEC_HINT_TIMEOUT.equals( hintName ) ) {
+				// convert milliseconds to seconds
+				int timeout = (int)Math.round(ConfigurationHelper.getInteger( value ).doubleValue() / 1000.0 ); 
+				applyTimeout( new Integer(timeout) );
+			}
 			else if ( HINT_COMMENT.equals( hintName ) ) {
 				applyComment( (String) value );
 			}

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryHints.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryHints.java	2010-02-22 21:59:43 UTC (rev 18851)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/QueryHints.java	2010-02-22 23:27:16 UTC (rev 18852)
@@ -1,7 +1,7 @@
 /*
  * Hibernate, Relational Persistence for Idiomatic Java
  *
- * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
+ * Copyright (c) 2010 by Red Hat Inc and/or its affiliates or by
  * third-party contributors as indicated by either @author tags or express
  * copyright attribution statements applied by the authors.  All
  * third-party contributions are distributed under license by Red Hat Inc.
@@ -32,7 +32,12 @@
  * @author Steve Ebersole
  */
 public class QueryHints {
-	public static final String HINT_TIMEOUT = "org.hibernate.timeout";
+	/**
+	 * @deprecated HINT_TIMEOUT (org.hibernate.timeout),
+	 * instead use SPEC_HINT_TIMEOUT (javax.persistence.query.timeout)
+	 */
+	public static final String HINT_TIMEOUT = "org.hibernate.timeout"; // Query timeout in seconds
+	public static final String SPEC_HINT_TIMEOUT = "javax.persistence.query.timeout"; // timeout in milliseconds
 	public static final String HINT_COMMENT = "org.hibernate.comment";
 	public static final String HINT_FETCH_SIZE = "org.hibernate.fetchSize";
 	public static final String HINT_CACHE_REGION = "org.hibernate.cacheRegion";
@@ -46,6 +51,7 @@
 	private static Set<String> buildHintsSet() {
 		HashSet<String> hints = new HashSet<String>();
 		hints.add( HINT_TIMEOUT );
+		hints.add( SPEC_HINT_TIMEOUT );
 		hints.add( HINT_COMMENT );
 		hints.add( HINT_FETCH_SIZE );
 		hints.add( HINT_CACHE_REGION );

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-22 21:59:43 UTC (rev 18851)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/test/lock/LockTest.java	2010-02-22 23:27:16 UTC (rev 18852)
@@ -6,6 +6,7 @@
 import javax.persistence.LockTimeoutException;
 import javax.persistence.OptimisticLockException;
 import javax.persistence.Query;
+import javax.persistence.QueryTimeoutException;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -511,8 +512,96 @@
 		}
 	}
 
+	public void testQueryTimeout() throws Exception {
 
+		EntityManager em = getOrCreateEntityManager();
+		final EntityManager em2 = createIsolatedEntityManager();
+		// TODO:  replace dialect instanceof test with a Dialect.hasCapability
+		if ( ! (getDialect() instanceof Oracle10gDialect)) {
+			log.info("skipping testQueryTimeout");
+			return;
+		}
+		Lock lock = new Lock();
+		Thread t = null;
+		FutureTask<Boolean> bgTask = null;
+		final CountDownLatch latch = new CountDownLatch(1);
+		try {
+			lock.setName( "testQueryTimeout" );
 
+			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("testQueryTimeout: got write lock");
+
+			bgTask = new FutureTask<Boolean>( new Callable() {
+				public Boolean call() {
+					try {
+						boolean timedOut = false;	// true (success) if LockTimeoutException occurred
+						em2.getTransaction().begin();
+						log.info( "testQueryTimeout: (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( "testQueryTimeout: (BG) read write-locked entity" );
+						try {
+							// we should block on the following read
+							Query query = em2.createQuery(
+									  "select L from Lock_ L where L.id < 10000 ");
+							query.setLockMode( LockModeType.PESSIMISTIC_READ );
+							query.setHint( "javax.persistence.query.timeout", new Integer(500) ); // 1 sec timeout
+							List<Lock> resultList = query.getResultList();
+							String name = resultList.get(0).getName(); //  force entity to be read
+							log.info( "testQueryTimeout: name read =" + name );
+						}
+						catch( QueryTimeoutException e) {
+							// success
+							log.info( "testQueryTimeout: (BG) got expected timeout exception" );
+							 timedOut = true;
+						}
+						catch ( Throwable e) {
+							log.info( "testQueryTimeout: Expected LockTimeoutException but got unexpected exception", e );
+						}
+						em2.getTransaction().commit();
+						return new Boolean( timedOut );
+					}
+					finally {
+						latch.countDown();	// signal that we finished
+					}
+				}
+			} );
+			t = new Thread(bgTask);
+			t.setDaemon( true );
+			t.setName( "testQueryTimeout (bg)" );
+			t.start();
+			boolean latchSet = latch.await( 10, TimeUnit.SECONDS );  // should return quickly on success
+			assertTrue( "background test thread finished (lock timeout is broken)", latchSet);
+			assertTrue( "background test thread timed out on lock attempt", bgTask.get().booleanValue() );
+			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