You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2010/06/28 12:05:09 UTC

svn commit: r958529 - in /db/derby/code/trunk/java/engine/org/apache/derby: iapi/sql/PreparedStatement.java impl/sql/GenericActivationHolder.java impl/sql/GenericPreparedStatement.java impl/sql/GenericStatement.java

Author: kahatlen
Date: Mon Jun 28 10:05:09 2010
New Revision: 958529

URL: http://svn.apache.org/viewvc?rev=958529&view=rev
Log:
DERBY-4279: Statement cache deadlock

Backing out revision 956504 while investigating problems that appeared
after the change.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java?rev=958529&r1=958528&r2=958529&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/PreparedStatement.java Mon Jun 28 10:05:09 2010
@@ -70,10 +70,10 @@ public interface PreparedStatement
 	 * then we will not be able to recompile the statement.
 	 *
 	 * @param lcc			The LanguageConnectionContext.
-	 * @return the re-prepared statement (may be a new PreparedStatement)
+	 *
 	 * @exception StandardException thrown if unable to perform
 	 */
-	PreparedStatement rePrepare(LanguageConnectionContext lcc)
+	void rePrepare(LanguageConnectionContext lcc) 
 		throws StandardException;
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java?rev=958529&r1=958528&r2=958529&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java Mon Jun 28 10:05:09 2010
@@ -258,81 +258,82 @@ final public class GenericActivationHold
 		** the statement at the same time we're trying to execute it.
 		*/
 		// synchronized (ps)
-
-		/* Has the activation class changed or has the activation been
-		 * invalidated? */
-		if (gc != ps.getActivationClass() || !ac.isValid())
 		{
-	        GeneratedClass newGC;
-	        ExecPreparedStatement newPS;
+			/* Has the activation class changed or has the activation been
+			 * invalidated? */
+			if (gc != ps.getActivationClass() || !ac.isValid())
+			{
 
-			if (gc != ps.getActivationClass()) {
-				// ensure the statement is valid by rePreparing it.
-				// DERBY-3260: If someone else reprepares the statement at
-				// the same time as we do, there's a window between the
-				// calls to rePrepare() and getActivationClass() when the
-				// activation class can be set to null, leading to
-				// NullPointerException being thrown later. Therefore,
-				// synchronize on ps to close the window.
-				synchronized (ps) {
-					newPS = (ExecPreparedStatement) ps.rePrepare(getLanguageConnectionContext());
-					newGC = newPS.getActivationClass();
+                GeneratedClass newGC;
+
+				if (gc != ps.getActivationClass()) {
+					// ensure the statement is valid by rePreparing it.
+					// DERBY-3260: If someone else reprepares the statement at
+					// the same time as we do, there's a window between the
+					// calls to rePrepare() and getActivationClass() when the
+					// activation class can be set to null, leading to
+					// NullPointerException being thrown later. Therefore,
+					// synchronize on ps to close the window.
+					synchronized (ps) {
+						ps.rePrepare(getLanguageConnectionContext());
+						newGC = ps.getActivationClass();
+					}
+				} else {
+					// Reuse the generated class, we just want a new activation
+					// since the old is no longer valid.
+					newGC = gc;
 				}
-			}
-			else
-			{
-				newGC = gc;
-				newPS = ps;
-			}
 
-			/*
-			** If we get here, it means the Activation has been invalidated
-			** or the PreparedStatement has been recompiled.  Get a new
-			** Activation and check whether the parameters are compatible.
-			** If so, transfer the parameters from the old Activation to
-			** the new one, and make that the current Activation.  If not,
-			** throw an exception.
-			*/
-			BaseActivation newAC = (BaseActivation) newGC.newInstance(lcc);
-
-			DataTypeDescriptor[] newParamTypes = newPS.getParameterTypes();
-
-			/*
-			** Link the new activation to the prepared statement.
-			*/
-			newAC.setupActivation(newPS, ac.getScrollable());
-
-			newAC.setParameters(ac.getParameterValueSet(), paramTypes);
-
-			/*
-			** IMPORTANT
-			**
-			** Copy any essential state from the old activation
-			** to the new activation. This must match the state
-			** setup in EmbedStatement.
-			** singleExecution, cursorName, holdability, maxRows.
-			*/
-
-			if (ac.isSingleExecution())
-				newAC.setSingleExecution();
-
-			newAC.setCursorName(ac.getCursorName());
-
-			newAC.setResultSetHoldability(ac.getResultSetHoldability());
-			if (ac.getAutoGeneratedKeysResultsetMode()) //Need to do copy only if auto generated mode is on
-				newAC.setAutoGeneratedKeysResultsetInfo(ac.getAutoGeneratedKeysColumnIndexes(),
-						ac.getAutoGeneratedKeysColumnNames());
-			newAC.setMaxRows(ac.getMaxRows());
-
-			// break the link with the prepared statement
-			ac.setupActivation(null, false);
-			ac.close();
-
-			/* Remember the new class information */
-			ac = newAC;
-			gc = newGC;
-			ps = newPS;
-			paramTypes = newParamTypes;
+
+				/*
+				** If we get here, it means the Activation has been invalidated
+				** or the PreparedStatement has been recompiled.  Get a new
+				** Activation and check whether the parameters are compatible.
+				** If so, transfer the parameters from the old Activation to
+				** the new one, and make that the current Activation.  If not,
+				** throw an exception.
+				*/
+				BaseActivation		newAC = (BaseActivation) newGC.newInstance(lcc);
+
+				DataTypeDescriptor[]	newParamTypes = ps.getParameterTypes();
+
+				/*
+				** Link the new activation to the prepared statement.
+				*/
+				newAC.setupActivation(ps, ac.getScrollable());
+
+				newAC.setParameters(ac.getParameterValueSet(), paramTypes);
+
+
+				/*
+				** IMPORTANT
+				**
+				** Copy any essential state from the old activation
+				** to the new activation. This must match the state
+				** setup in EmbedStatement.
+				** singleExecution, cursorName, holdability, maxRows.
+				*/
+
+				if (ac.isSingleExecution())
+					newAC.setSingleExecution();
+
+				newAC.setCursorName(ac.getCursorName());
+
+				newAC.setResultSetHoldability(ac.getResultSetHoldability());
+				if (ac.getAutoGeneratedKeysResultsetMode()) //Need to do copy only if auto generated mode is on
+					newAC.setAutoGeneratedKeysResultsetInfo(ac.getAutoGeneratedKeysColumnIndexes(),
+					ac.getAutoGeneratedKeysColumnNames());
+				newAC.setMaxRows(ac.getMaxRows());
+
+				// break the link with the prepared statement
+				ac.setupActivation(null, false);
+				ac.close();
+
+				/* Remember the new class information */
+				ac = newAC;
+				gc = newGC;
+				paramTypes = newParamTypes;
+			}
 		}
 
 		String cursorName = ac.getCursorName();

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java?rev=958529&r1=958528&r2=958529&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java Mon Jun 28 10:05:09 2010
@@ -223,14 +223,14 @@ public class GenericPreparedStatement
         return isValid && (activationClass != null) && !compilingStatement;
     }
 
-	public PreparedStatement rePrepare(LanguageConnectionContext lcc)
+	public void rePrepare(LanguageConnectionContext lcc) 
 		throws StandardException {
 		if (!upToDate()) {
 			PreparedStatement ps = statement.prepare(lcc);
-			return ps;
-		}
 
-		return this;
+			if (SanityManager.DEBUG)
+				SanityManager.ASSERT(ps == this, "ps != this");
+		}
 	}
 
 	/**
@@ -247,10 +247,7 @@ public class GenericPreparedStatement
 			GeneratedClass gc = getActivationClass();
 
 			if (gc == null) {
-				PreparedStatement ps = rePrepare(lcc);
-
-				if (SanityManager.DEBUG)
-					SanityManager.ASSERT(ps == this, "ps != this");
+				rePrepare(lcc);
 				gc = getActivationClass();
 			}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java?rev=958529&r1=958528&r2=958529&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericStatement.java Mon Jun 28 10:05:09 2010
@@ -171,18 +171,11 @@ public class GenericStatement
 		// cache of prepared statement objects...
 		synchronized (preparedStmt) 
 		{
-			for (;;)
-			{
-				if (preparedStmt.compilingStatement)
-				{
-					preparedStmt = new GenericPreparedStatement(this);
-					break;
-				}
 
-				if (foundInCache)
-				{
-					if (preparedStmt.referencesSessionSchema())
-					{
+			for (;;) {
+
+				if (foundInCache) {
+					if (preparedStmt.referencesSessionSchema()) {
 						// cannot use this state since it is private to a connection.
 						// switch to a new statement.
 						foundInCache = false;
@@ -196,7 +189,15 @@ public class GenericStatement
 					return preparedStmt;
 				}
 
-				break;
+				if (!preparedStmt.compilingStatement) {
+					break;
+				}
+
+				try {
+					preparedStmt.wait();
+				} catch (InterruptedException ie) {
+					throw StandardException.interrupt(ie);
+				}
 			}
 
 			preparedStmt.compilingStatement = true;
@@ -541,6 +542,7 @@ public class GenericStatement
 		{
 			synchronized (preparedStmt) {
 				preparedStmt.compilingStatement = false;
+				preparedStmt.notifyAll();
 			}
 		}