You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jg...@apache.org on 2011/06/27 21:21:18 UTC
svn commit: r1140285 - in /karaf/branches/karaf-2.1.x/main/src:
main/java/org/apache/karaf/main/ test/java/org/apache/karaf/main/
Author: jgoodyear
Date: Mon Jun 27 19:21:18 2011
New Revision: 1140285
URL: http://svn.apache.org/viewvc?rev=1140285&view=rev
Log:
[KARAF-689] Karaf instance can wrongly obtain a lock when the locking table is empty on a Oracle DB
Applying patch from Ton Swieb, with thanks :)
Modified:
karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/OracleJDBCLock.java
karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/Statements.java
karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockIntegrationTest.java
karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockTest.java
karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/OracleJDBCLockTest.java
Modified: karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/OracleJDBCLock.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/OracleJDBCLock.java?rev=1140285&r1=1140284&r2=1140285&view=diff
==============================================================================
--- karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/OracleJDBCLock.java (original)
+++ karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/OracleJDBCLock.java Mon Jun 27 19:21:18 2011
@@ -18,6 +18,8 @@
*/
package org.apache.karaf.main;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.util.Properties;
/**
@@ -67,4 +69,37 @@ public class OracleJDBCLock extends Defa
boolean updateLock() {
return aquireLock();
}
+
+ /**
+ * A SELECT FOR UPDATE does not create a database lock when the SELECT FOR UPDATE is performed
+ * on an empty selection. So a succesfull call to {@link DefaultJDBCLock#aquireLock()} is not sufficient to
+ * ensure that we are the only one who have acquired the lock.
+ */
+ @Override
+ boolean aquireLock() {
+ return super.aquireLock() && lockAcquiredOnNonEmptySelection();
+ }
+
+ //Verify that we have a non empty record set.
+ private boolean lockAcquiredOnNonEmptySelection() {
+ String verifySelectionNotEmpytStatement = statements.getLockVerifySelectionNotEmptyStatement();
+ PreparedStatement preparedStatement = null;
+ boolean lockAquired = false;
+
+ try {
+ preparedStatement = getConnection().prepareStatement(verifySelectionNotEmpytStatement);
+ preparedStatement.setQueryTimeout(timeout);
+ ResultSet rs = preparedStatement.executeQuery();
+ if (rs.next()) {
+ lockAquired = rs.getInt(1) > 0;
+ } else {
+ LOG.warning("Failed to acquire database lock. Missing database lock record.");
+ }
+ } catch (Exception e) {
+ LOG.warning("Failed to acquire database lock: " + e);
+ }finally {
+ closeSafely(preparedStatement);
+ }
+ return lockAquired;
+ }
}
Modified: karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/Statements.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/Statements.java?rev=1140285&r1=1140284&r2=1140285&view=diff
==============================================================================
--- karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/Statements.java (original)
+++ karaf/branches/karaf-2.1.x/main/src/main/java/org/apache/karaf/main/Statements.java Mon Jun 27 19:21:18 2011
@@ -30,6 +30,7 @@ public class Statements {
private String[] lockCreateSchemaStatements;
private String lockCreateStatement;
private String lockUpdateStatement;
+ private String lockVerifySelectionNotEmptyStatement;
public String[] getLockCreateSchemaStatements(long moment) {
if (lockCreateSchemaStatements == null) {
@@ -67,6 +68,20 @@ public class Statements {
this.lockUpdateStatement = lockUpdateStatement;
}
+ public void setLockVerifySelectionNotEmptyStatement(String lockVerifySelectionNotEmptyStatement) {
+ this.lockVerifySelectionNotEmptyStatement = lockVerifySelectionNotEmptyStatement;
+ }
+
+ public String getLockVerifySelectionNotEmptyStatement() {
+ if (lockVerifySelectionNotEmptyStatement == null) {
+ //The lock create and lock update are perfomed on the whole table instead of
+ //the cluster. So not taking the node into account for now.
+ lockVerifySelectionNotEmptyStatement = "SELECT COUNT(*) FROM " + getFullLockTableName();
+ }
+ return lockVerifySelectionNotEmptyStatement;
+ }
+
+
long getCurrentTimeMillis() {
return System.currentTimeMillis();
}
Modified: karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockIntegrationTest.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockIntegrationTest.java?rev=1140285&r1=1140284&r2=1140285&view=diff
==============================================================================
--- karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockIntegrationTest.java (original)
+++ karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockIntegrationTest.java Mon Jun 27 19:21:18 2011
@@ -167,6 +167,20 @@ public abstract class BaseJDBCLockIntegr
}
@Test
+ public void lockShouldReturnFalseIfTheTableIsEmpty() throws Exception {
+ Connection connection = null;
+ try {
+ lock = createLock(props);
+ truncateTable(); //Empty the table
+ connection = lock(tableName, clustername);
+
+ assertFalse(lock.lock());
+ } finally {
+ close(connection);
+ }
+ }
+
+ @Test
public void release() throws Exception {
lock = createLock(props);
@@ -309,6 +323,11 @@ public abstract class BaseJDBCLockIntegr
executeStatement("UPDATE " + tableName + " SET MOMENT = " + System.currentTimeMillis());
}
+ void truncateTable() throws SQLException, ClassNotFoundException {
+ executeStatement("TRUNCATE TABLE " + tableName);
+ }
+
+
Connection lock(String table, String node) throws ClassNotFoundException, SQLException {
Connection connection = null;
Statement statement = null;
Modified: karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockTest.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockTest.java?rev=1140285&r1=1140284&r2=1140285&view=diff
==============================================================================
--- karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockTest.java (original)
+++ karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/BaseJDBCLockTest.java Mon Jun 27 19:21:18 2011
@@ -307,4 +307,28 @@ public abstract class BaseJDBCLockTest {
verify(connection, metaData, statement, preparedStatement, resultSet);
assertFalse(alive);
}
+
+ @Test
+ public void lockShouldReturnFalseIfTableIsEmpty() throws Exception {
+ initShouldNotCreateTheSchemaIfItAlreadyExists();
+ reset(connection, metaData, statement, preparedStatement, resultSet);
+
+ expect(connection.isClosed()).andReturn(false);
+ expect(connection.prepareStatement("SELECT * FROM " + tableName + " FOR UPDATE")).andReturn(preparedStatement);
+ preparedStatement.setQueryTimeout(10);
+ expect(preparedStatement.execute()).andReturn(true);
+ preparedStatement.close();
+ expect(connection.isClosed()).andReturn(false);
+ expect(connection.prepareStatement("UPDATE " + tableName + " SET MOMENT = 1")).andReturn(preparedStatement);
+ preparedStatement.setQueryTimeout(10);
+ expect(preparedStatement.executeUpdate()).andReturn(0);
+ preparedStatement.close();
+
+ replay(connection, metaData, statement, preparedStatement, resultSet);
+
+ boolean lockAquired = lock.lock();
+
+ verify(connection, metaData, statement, preparedStatement, resultSet);
+ assertFalse(lockAquired);
+ }
}
Modified: karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/OracleJDBCLockTest.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/OracleJDBCLockTest.java?rev=1140285&r1=1140284&r2=1140285&view=diff
==============================================================================
--- karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/OracleJDBCLockTest.java (original)
+++ karaf/branches/karaf-2.1.x/main/src/test/java/org/apache/karaf/main/OracleJDBCLockTest.java Mon Jun 27 19:21:18 2011
@@ -74,6 +74,13 @@ public class OracleJDBCLockTest extends
preparedStatement.setQueryTimeout(10);
expect(preparedStatement.execute()).andReturn(true);
preparedStatement.close();
+ expect(connection.isClosed()).andReturn(false);
+ expect(connection.prepareStatement("SELECT COUNT(*) FROM " + tableName)).andReturn(preparedStatement);
+ preparedStatement.setQueryTimeout(10);
+ expect(preparedStatement.executeQuery()).andReturn(resultSet);
+ expect(resultSet.next()).andReturn(Boolean.TRUE);
+ expect(resultSet.getInt(1)).andReturn(1);
+ preparedStatement.close();
replay(connection, metaData, statement, preparedStatement, resultSet);
@@ -134,6 +141,13 @@ public class OracleJDBCLockTest extends
preparedStatement.setQueryTimeout(10);
expect(preparedStatement.execute()).andReturn(true);
preparedStatement.close();
+ expect(connection.isClosed()).andReturn(false);
+ expect(connection.prepareStatement("SELECT COUNT(*) FROM " + tableName)).andReturn(preparedStatement);
+ preparedStatement.setQueryTimeout(10);
+ expect(preparedStatement.executeQuery()).andReturn(resultSet);
+ expect(resultSet.next()).andReturn(Boolean.TRUE);
+ expect(resultSet.getInt(1)).andReturn(1);
+ preparedStatement.close();
replay(connection, metaData, statement, preparedStatement, resultSet);
@@ -162,4 +176,30 @@ public class OracleJDBCLockTest extends
verify(connection, metaData, statement, preparedStatement, resultSet);
assertFalse(alive);
}
+
+ @Test
+ public void lockShouldReturnFalseIfTableIsEmpty() throws Exception {
+ initShouldNotCreateTheSchemaIfItAlreadyExists();
+ reset(connection, metaData, statement, preparedStatement, resultSet);
+
+ expect(connection.isClosed()).andReturn(false);
+ expect(connection.prepareStatement("SELECT * FROM " + tableName + " FOR UPDATE")).andReturn(preparedStatement);
+ preparedStatement.setQueryTimeout(10);
+ expect(preparedStatement.execute()).andReturn(true);
+ preparedStatement.close();
+ expect(connection.isClosed()).andReturn(false);
+ expect(connection.prepareStatement("SELECT COUNT(*) FROM " + tableName)).andReturn(preparedStatement);
+ preparedStatement.setQueryTimeout(10);
+ expect(preparedStatement.executeQuery()).andReturn(resultSet);
+ expect(resultSet.next()).andReturn(Boolean.TRUE);
+ expect(resultSet.getInt(1)).andReturn(0);
+ preparedStatement.close();
+
+ replay(connection, metaData, statement, preparedStatement, resultSet);
+
+ boolean lockAquired = lock.lock();
+
+ verify(connection, metaData, statement, preparedStatement, resultSet);
+ assertFalse(lockAquired);
+ }
}