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/21 11:05:48 UTC
svn commit: r956504 - 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 21 09:05:47 2010
New Revision: 956504
URL: http://svn.apache.org/viewvc?rev=956504&view=rev
Log:
DERBY-4279: Statement cache deadlock
When requesting a recompile of a statement, don't wait for other
threads compiling the same statement, but instead create a new
instance of the statement.
Patch contributed by Brett Wooldridge <br...@gmail.com>.
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=956504&r1=956503&r2=956504&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 21 09:05:47 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
*/
- void rePrepare(LanguageConnectionContext lcc)
+ PreparedStatement 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=956504&r1=956503&r2=956504&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 21 09:05:47 2010
@@ -258,82 +258,81 @@ 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;
+ /* Has the activation class changed or has the activation been
+ * invalidated? */
+ if (gc != ps.getActivationClass() || !ac.isValid())
+ {
+ GeneratedClass newGC;
+ ExecPreparedStatement newPS;
- 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;
+ 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();
}
-
-
- /*
- ** 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;
}
+ 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;
}
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=956504&r1=956503&r2=956504&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 21 09:05:47 2010
@@ -223,14 +223,14 @@ public class GenericPreparedStatement
return isValid && (activationClass != null) && !compilingStatement;
}
- public void rePrepare(LanguageConnectionContext lcc)
+ public PreparedStatement rePrepare(LanguageConnectionContext lcc)
throws StandardException {
if (!upToDate()) {
PreparedStatement ps = statement.prepare(lcc);
-
- if (SanityManager.DEBUG)
- SanityManager.ASSERT(ps == this, "ps != this");
+ return ps;
}
+
+ return this;
}
/**
@@ -247,7 +247,10 @@ public class GenericPreparedStatement
GeneratedClass gc = getActivationClass();
if (gc == null) {
- rePrepare(lcc);
+ PreparedStatement ps = rePrepare(lcc);
+
+ if (SanityManager.DEBUG)
+ SanityManager.ASSERT(ps == this, "ps != this");
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=956504&r1=956503&r2=956504&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 21 09:05:47 2010
@@ -171,11 +171,18 @@ public class GenericStatement
// cache of prepared statement objects...
synchronized (preparedStmt)
{
+ for (;;)
+ {
+ if (preparedStmt.compilingStatement)
+ {
+ preparedStmt = new GenericPreparedStatement(this);
+ break;
+ }
- for (;;) {
-
- if (foundInCache) {
- if (preparedStmt.referencesSessionSchema()) {
+ if (foundInCache)
+ {
+ if (preparedStmt.referencesSessionSchema())
+ {
// cannot use this state since it is private to a connection.
// switch to a new statement.
foundInCache = false;
@@ -189,15 +196,7 @@ public class GenericStatement
return preparedStmt;
}
- if (!preparedStmt.compilingStatement) {
- break;
- }
-
- try {
- preparedStmt.wait();
- } catch (InterruptedException ie) {
- throw StandardException.interrupt(ie);
- }
+ break;
}
preparedStmt.compilingStatement = true;
@@ -542,7 +541,6 @@ public class GenericStatement
{
synchronized (preparedStmt) {
preparedStmt.compilingStatement = false;
- preparedStmt.notifyAll();
}
}