diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCLockManager.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCLockManager.java index 646fbf951..f168688ac 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCLockManager.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCLockManager.java @@ -46,4 +46,9 @@ public interface JDBCLockManager * produced by a FOR UPDATE select. */ public void loadedForUpdate(OpenJPAStateManager sm); + + /** + * Return true if locking is not desired for relation fields. + */ + public boolean skipRelationFieldLock(); } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/MixedLockManager.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/MixedLockManager.java index ba0949ccc..1aaf7fa51 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/MixedLockManager.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/MixedLockManager.java @@ -128,4 +128,8 @@ public class MixedLockManager extends PessimisticLockManager { } } } + + public boolean skipRelationFieldLock() { + return true; + } } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionStrategy.java index 425e44c01..f166edaf8 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionStrategy.java @@ -24,7 +24,6 @@ import java.util.Map; import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.sql.Result; import org.apache.openjpa.jdbc.sql.Select; -import org.apache.openjpa.jdbc.schema.Column; import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.StoreManager; diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java index ddae2f8e5..adc420072 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java @@ -23,6 +23,7 @@ import java.math.BigDecimal; import java.sql.SQLException; import java.util.Comparator; +import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.meta.ClassMapping; import org.apache.openjpa.jdbc.meta.VersionMappingInfo; @@ -34,6 +35,7 @@ import org.apache.openjpa.jdbc.sql.Result; import org.apache.openjpa.jdbc.sql.Row; import org.apache.openjpa.jdbc.sql.RowManager; import org.apache.openjpa.jdbc.sql.Select; +import org.apache.openjpa.kernel.MixedLockLevels; import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.StoreManager; import org.apache.openjpa.lib.util.Localizer; @@ -277,7 +279,13 @@ public abstract class ColumnVersionStrategy sel.select(cols); sel.wherePrimaryKey(sm.getObjectId(), vers.getClassMapping(), store); - Result res = sel.execute(store, null); + // No need to lock version field (i.e. optimistic), except when version update is required (e.g. refresh) + JDBCFetchConfiguration fetch = store.getFetchConfiguration(); + if (!updateVersion && fetch.getReadLockLevel() >= MixedLockLevels.LOCK_PESSIMISTIC_READ) { + fetch = (JDBCFetchConfiguration) fetch.clone(); + fetch.setReadLockLevel(MixedLockLevels.LOCK_NONE); + } + Result res = sel.execute(store, fetch); try { if (!res.next()) return false; diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java index f9428e91b..944d04d46 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/RelationFieldStrategy.java @@ -30,6 +30,7 @@ import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.ReflectingPersistenceCapable; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCStore; +import org.apache.openjpa.jdbc.kernel.MixedLockManager; import org.apache.openjpa.jdbc.meta.ClassMapping; import org.apache.openjpa.jdbc.meta.Embeddable; import org.apache.openjpa.jdbc.meta.FieldMapping; @@ -53,6 +54,7 @@ import org.apache.openjpa.jdbc.sql.SQLBuffer; import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.SelectExecutor; import org.apache.openjpa.jdbc.sql.Union; +import org.apache.openjpa.kernel.LockManager; import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.util.Localizer; @@ -65,6 +67,7 @@ import org.apache.openjpa.util.InternalException; import org.apache.openjpa.util.MetaDataException; import org.apache.openjpa.util.OpenJPAId; import org.apache.openjpa.util.UnsupportedException; + import serp.util.Numbers; /** @@ -699,8 +702,14 @@ public class RelationFieldStrategy } } - sm.storeObject(field.getIndex(), res.load(cls, store, fetch, - eagerJoin(res.newJoins(), cls, false))); + boolean isLocked = res.isLocking(); + try { + res.setLocking(store.getLockManager().skipRelationFieldLock()); + sm.storeObject(field.getIndex(), res.load(cls, store, fetch, + eagerJoin(res.newJoins(), cls, false))); + } finally { + res.setLocking(isLocked); + } // reset mapped by is needed for OneToOne bidirectional relations // having a mapped-by parent to correctly set the parent-child diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java index 2702aab55..2e2b268c3 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java @@ -97,6 +97,10 @@ public class MergedResult _res[i].close(); } + public void setLocking(boolean locking) { + _res[_idx].setLocking(locking); + } + public boolean isLocking() { return _res[_idx].isLocking(); } diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java index 4a9a63c96..a6ae3a920 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java @@ -78,6 +78,11 @@ public interface Result */ public void close(); + /** + * Set to true if row locking has been issued for the row. + */ + public void setLocking(boolean locking); + /** * If true, then any results loaded from this Result * will be locked in the database. diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractLockManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractLockManager.java index 8e14fc093..139b452ee 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractLockManager.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractLockManager.java @@ -57,7 +57,7 @@ public abstract class AbstractLockManager */ public void lockAll(Collection sms, int level, int timeout, Object context) { - for (Iterator itr = sms.iterator(); itr.hasNext();) + for (Iterator itr = sms.iterator(); itr.hasNext();) lock((OpenJPAStateManager) itr.next(), level, timeout, context); } @@ -76,8 +76,14 @@ public abstract class AbstractLockManager /** * Does nothing by default. */ - public void close () - { + public void close () { } + + /** + * Default not to skip relation field to maintain PessimisticLockManager semantics. + */ + public boolean skipRelationFieldLock() { + return false; + } } diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LockScopeTestCase.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LockScopeTestCase.java index 0eb52d18b..4e8cc9b51 100644 --- a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LockScopeTestCase.java +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/LockScopeTestCase.java @@ -68,6 +68,7 @@ public abstract class LockScopeTestCase extends SQLListenerTestCase { protected final String Any = ".*"; protected final String Select = "SELECT.*FROM.*"; + protected final String SelectVersion = "SELECT.*version.*FROM.*"; protected final String Where = ".*WHERE.*"; // protected final String Join = ".*(JOIN){1}.*"; protected final String NoJoin = "(JOIN){0}"; @@ -155,6 +156,15 @@ public abstract class LockScopeTestCase extends SQLListenerTestCase { assertAllSQLAnyOrder(expected); } + public void assertLockTestNoSQLs(String... expected) { + Log log = getDumpSQLLog(); + if( log.isTraceEnabled()) { + log.trace("\r\n" + toString(sql)); + return; + } + assertNoneSQLAnyOrder(expected); + } + protected void logStack(Throwable t) { StringWriter str = new StringWriter(); PrintWriter print = new PrintWriter(str); diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1x1LockScope.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1x1LockScope.java index c31c38c34..0ff371641 100644 --- a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1x1LockScope.java +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lock/extended/Test1x1LockScope.java @@ -43,8 +43,8 @@ public class Test1x1LockScope extends LockScopeTestCase { , LSE1x1LfJT.class , LSE1x1LfJTLzy.class , LSE1x1Rt.class - , "openjpa.LockManager", "mixed", - "openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)" + , "openjpa.LockManager", "mixed" + , "openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true)" ); commonSetUp(LSE1x1Lf.class , LSE1x1LfLzy.class @@ -138,12 +138,18 @@ public class Test1x1LockScope extends LockScopeTestCase { case db2: // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? - // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1111202] + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS + // [params=(int) 1111202] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? - // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1121202] + // -FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS- [params=(int) 1121202] // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? - // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1111202] - assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + // -FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS- [params=(int) 1111202] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock, + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + ); break; case oracle: // TODO: if jpa2, DO NOT lock LSE1x1RT using "FOR UPDATE OF col" // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName @@ -154,20 +160,25 @@ public class Test1x1LockScope extends LockScopeTestCase { assertLockTestSQLs(Select + tableLfName + Any + tableRtName + Where + "\\(\\+\\).*" + ForUpdate); break; - case derby: //TODO: **Non-atomic lock. + case derby: //-TODO: **Non-atomic lock. // The database is unable to lock this query. Each object matching the query will be // locked individually after it is loaded; however, it is technically possible that // another transaction could modify the data before the lock is obtained. // SELECT t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id WHERE t0.id = ? // [params=(int) 1111202] - // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121202] - // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? -FOR UPDATE WITH RR- + // [params=(int) 1121202] // SELECT t0.id FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1111202] - // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1111202] + // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? -FOR UPDATE WITH RR- + // [params=(int) 1111202] assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, Select + NoJoin + Any + tableLfName + Any + NoJoin + Where + ForUpdate, - Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + //-SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121202]- + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate ); break; default: @@ -184,7 +195,12 @@ public class Test1x1LockScope extends LockScopeTestCase { // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%1111201] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] - assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + assertLockTestSQLs(Select + joinTables + Where + DB2Lock, + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + ); break; case oracle: // TODO: if jpa2, DO NOT lock LSE1x1RT using "FOR UPDATE OF col" // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName @@ -196,20 +212,23 @@ public class Test1x1LockScope extends LockScopeTestCase { assertLockTestSQLs(Select + tableLfName + Any + tableRtName + Where + "\\(\\+\\).*" + ForUpdate); break; - case derby: //TODO: **Non-atomic lock. + case derby: //-TODO: **Non-atomic lock. // The database is unable to lock this query. Each object matching the query will be // locked individually after it is loaded; however, it is technically possible that // another transaction could modify the data before the lock is obtained. - //SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 + // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%1111201] - // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121201] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] // SELECT t0.id FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1111201] // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, Select + NoJoin + Any + tableLfName + Any + NoJoin + Where + ForUpdate, - Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + //-SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121201]- + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate ); break; default: @@ -250,7 +269,12 @@ public class Test1x1LockScope extends LockScopeTestCase { // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%1111201] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] - assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + assertLockTestSQLs(Select + joinTables + Where + DB2Lock, + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + ); break; case oracle: // TODO: if jpa2, DO NOT lock LSE1x1RT using "FOR UPDATE OF col" // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName @@ -262,20 +286,23 @@ public class Test1x1LockScope extends LockScopeTestCase { assertLockTestSQLs(Select + tableLfName + Any + tableRtName + Where + "\\(\\+\\).*" + ForUpdate); break; - case derby: //TODO: **Non-atomic lock. + case derby: //-TODO: **Non-atomic lock. // The database is unable to lock this query. Each object matching the query will be // locked individually after it is loaded; however, it is technically possible that // another transaction could modify the data before the lock is obtained. // SELECT t0.id, t0.version, t0.firstName, t1.id, t1.version, t1.lastName FROM LSE1x1Lf t0 // LEFT OUTER JOIN LSE1x1Rt t1 ON t0.UNIRIGHT_ID = t1.id // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%1111201] - // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121201] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1121201] // SELECT t0.id FROM LSE1x1Lf t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1111201] // SELECT t0.version FROM LSE1x1Lf t0 WHERE t0.id = ? [params=(int) 1111201] assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, Select + NoJoin + Any + tableLfName + Any + NoJoin + Where + ForUpdate, - Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + //-SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1121201]- + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate ); break; default: @@ -579,10 +606,18 @@ public class Test1x1LockScope extends LockScopeTestCase { // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName FROM LSE1x1LfJT t0 // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? - // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1112202] - // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1122202] - // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1112202] - assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + // optimize for 1 row FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS + // [params=(int) 1112202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1122202] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? + // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(int) 1112202] + assertLockTestSQLs(Select + joinTables + Where + DB2Lock, + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + ); break; case oracle: // TODO: If jpa2, DO NOT lock LSE1x1RT using "FOR UDPATE OF col" // SELECT t0.version, t0.firstName, t2.id, t2.version, t2.lastName @@ -594,7 +629,7 @@ public class Test1x1LockScope extends LockScopeTestCase { assertLockTestSQLs(Select + tableLfName + Any + tableJTName + Any + tableRtName + Where + "\\(\\+\\).*" + ForUpdate); break; - case derby: //TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT + case derby: //-TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT // DO NOT lock LSE1x1Rt // The database is unable to lock this query. Each object matching the query will be // locked individually after it is loaded; however, it is technically possible that @@ -603,13 +638,18 @@ public class Test1x1LockScope extends LockScopeTestCase { // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id WHERE t0.id = ? // [params=(int) 1112202] - // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122202] - // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122202] + // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? -FOR UPDATE WITH RR- + // [params=(int) 1122202] // SELECT t0.id FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1112202] - // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1112202] + // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? -FOR UPDATE WITH RR- + // [params=(int) 1112202] assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, Select + NoJoin + Any + tableLfName + Any + NoJoin + Where + ForUpdate, - Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + //-SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122202]- + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate ); break; default: @@ -627,7 +667,12 @@ public class Test1x1LockScope extends LockScopeTestCase { // FOR READ ONLY WITH RS USE AND KEEP UPDATE LOCKS [params=(String) firstName%1112201] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] - assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + assertLockTestSQLs(Select + joinTables + Where + DB2Lock, + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + ); break; case oracle: // TODO: If jpa2, DO NOT lock LSE1x1RT using "FOR UDPATE OF col" // SELECT t0.id, t0.version, t0.firstName, t2.id, t2.version, t2.lastName @@ -639,7 +684,7 @@ public class Test1x1LockScope extends LockScopeTestCase { assertLockTestSQLs(Select + tableLfName + Any + tableJTName + Any + tableRtName + Where + "\\(\\+\\).*" + ForUpdate); break; - case derby: //TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT + case derby: //-TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT // DO NOT lock LSE1x1Rt // The database is unable to lock this query. Each object matching the query will be // locked individually after it is loaded; however, it is technically possible that @@ -648,13 +693,16 @@ public class Test1x1LockScope extends LockScopeTestCase { // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%1112201] - // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122201] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] // SELECT t0.id FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1112201] // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, Select + NoJoin + Any + tableLfName + Any + NoJoin + Where + ForUpdate, - Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + //-SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122201]- + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate ); break; default: @@ -699,7 +747,12 @@ public class Test1x1LockScope extends LockScopeTestCase { // FOR READ ONLY WITH RR USE AND KEEP UPDATE LOCKS [params=(String) firstName%1112201] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] - assertLockTestSQLs(Select + joinTables + Where + DB2Lock); + assertLockTestSQLs(Select + joinTables + Where + DB2Lock, + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + ); break; case oracle: // TODO: If jpa2, DO NOT lock LSE1x1RT using "FOR UDPATE OF col" // SELECT t0.id, t0.version, t0.firstName, t2.id, t2.version, t2.lastName @@ -711,7 +764,7 @@ public class Test1x1LockScope extends LockScopeTestCase { assertLockTestSQLs(Select + tableLfName + Any + tableJTName + Any + tableRtName + Where + "\\(\\+\\).*" + ForUpdate); break; - case derby: //TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT + case derby: //-TODO: **Non-atomic lock, if jpa2/extended scope, LOCK Uni1x1LfJT_Uni1x1RT // DO NOT lock LSE1x1Rt // The database is unable to lock this query. Each object matching the query will be // locked individually after it is loaded; however, it is technically possible that @@ -720,13 +773,16 @@ public class Test1x1LockScope extends LockScopeTestCase { // INNER JOIN Uni1x1LfJT_Uni1x1RT t1 ON t0.id = t1.LSE1X1LFJT_ID // LEFT OUTER JOIN LSE1x1Rt t2 ON t1.UNIRIGHTJT_ID = t2.id // WHERE (t0.firstName LIKE ? ESCAPE '\') [params=(String) firstName%1112201] - // SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122201] // SELECT t0.version FROM LSE1x1Rt t0 WHERE t0.id = ? [params=(int) 1122201] // SELECT t0.id FROM LSE1x1LfJT t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1112201] // SELECT t0.version FROM LSE1x1LfJT t0 WHERE t0.id = ? [params=(int) 1112201] assertLockTestSQLs(Select + joinTables + Where + NoForUpdate, Select + NoJoin + Any + tableLfName + Any + NoJoin + Where + ForUpdate, - Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate + SelectVersion + NoJoin + Any + tableLfName + Any + NoJoin + Where + NoForUpdate, + SelectVersion + NoJoin + Any + tableRtName + Any + NoJoin + Where + NoForUpdate + ); + //-SELECT t0.id FROM LSE1x1Rt t0 WHERE t0.id = ? FOR UPDATE WITH RR [params=(int) 1122201] + assertLockTestNoSQLs(Select + NoJoin + Any + tableRtName + Any + NoJoin + Where + ForUpdate ); break; default: diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/SequencedActionsTest.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/SequencedActionsTest.java index bad7ae62c..ba891f919 100644 --- a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/SequencedActionsTest.java +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/SequencedActionsTest.java @@ -573,7 +573,8 @@ public abstract class SequencedActionsTest extends SQLListenerTestCase { waitTime = (Integer) args[2]; } if (waitTime < MinThreadWaitInMs / 2) - waitTime = MinThreadWaitInMs / 2; + waitTime = MinThreadWaitInMs / 2; + log.trace(">> Started wait for " + waitTime + " ms"); if( waitThreadid != 0) { thisThread.wait(waitTime); } else { @@ -581,6 +582,7 @@ public abstract class SequencedActionsTest extends SQLListenerTestCase { wait(waitTime); } } + log.trace("<< Ended wait"); break; case EmployeeNotNull: @@ -725,7 +727,7 @@ public abstract class SequencedActionsTest extends SQLListenerTestCase { new ArrayList(threads); while (proceedThread.size() > 0 && System.currentTimeMillis() < endTime) { - for (Thread thread : proceedThread) { + for (TestThread thread : proceedThread) { if (thread.isAlive()) { log.trace(thread + " is still alive, wait" + " for 500ms and try again."); @@ -739,6 +741,9 @@ public abstract class SequencedActionsTest extends SQLListenerTestCase { continue; } else { deadThreads++; + if(thread.assertError != null){ + throw thread.assertError; + } proceedThread.remove(thread); break; } @@ -823,8 +828,8 @@ public abstract class SequencedActionsTest extends SQLListenerTestCase { logStack(ex); } catch (Error err) { // only remember the first exception caught - if (thisThread.throwable == null) { - thisThread.throwable = err; + if (thisThread.assertError == null) { + thisThread.assertError = err; } log.trace("Caught exception and continue: " + err); logStack(err); @@ -852,11 +857,14 @@ public abstract class SequencedActionsTest extends SQLListenerTestCase { } } em.close(); - Throwable firstThrowable = thisThread.throwable; - if (firstThrowable != null) { - if( firstThrowable instanceof Error ) - throw (Error)firstThrowable; + if (thisThread.assertError != null) { + throw thisThread.assertError; } +// Throwable firstThrowable = thisThread.throwable; +// if (firstThrowable != null) { +// if( firstThrowable instanceof Error ) +// throw (Error)firstThrowable; +// } log.trace("<<<< Sequenced Test: Threads=" + threadToRun + '/' + numThreads); } @@ -927,6 +935,7 @@ public abstract class SequencedActionsTest extends SQLListenerTestCase { private Map employees = null; public Throwable throwable = null; + public Error assertError = null; public boolean systemRolledback = false; public TestThread(int threadToRun, Object[][]... actions) { diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerDeadlock.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerDeadlock.java index d0d931fc1..fcf494bef 100644 --- a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerDeadlock.java +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerDeadlock.java @@ -48,6 +48,7 @@ public class TestMixedLockManagerDeadlock extends SequencedActionsTest { /* ======== Find dead lock exception test ============*/ public void testFindDeadLockException() { + commonFindTest("testFindDeadLockException", LockModeType.READ, null); commonFindTest("testFindDeadLockException", LockModeType.WRITE, dbType == DBType.oracle ? null : ExpectingOptimisticLockExClass); commonFindTest("testFindDeadLockException", LockModeType.PESSIMISTIC_WRITE, ExpectingAnyLockExClass); @@ -73,6 +74,7 @@ public class TestMixedLockManagerDeadlock extends SequencedActionsTest { {Act.WaitAllChildren}, {Act.TestException, 1, t1Exceptions}, + {Act.RollbackTx} }; Object[][] thread1 = { {Act.CreateEm}, @@ -81,6 +83,7 @@ public class TestMixedLockManagerDeadlock extends SequencedActionsTest { {Act.Flush}, {Act.Notify, 0}, + {Act.Sleep, 1000}, {Act.FindWithLock, 1, t1Lock}, {Act.RollbackTx}, @@ -90,10 +93,11 @@ public class TestMixedLockManagerDeadlock extends SequencedActionsTest { /* ======== named query dead lock exception test ============*/ public void testNamedQueryDeadLockException() { + commonNamedQueryTest("testNamedQueryDeadLockException", LockModeType.READ, null); commonNamedQueryTest("testNamedQueryDeadLockException", LockModeType.WRITE, dbType == DBType.oracle ? null : ExpectingOptimisticLockExClass); - commonNamedQueryTest("testNamedQueryDeadLockException", LockModeType.PESSIMISTIC_FORCE_INCREMENT, - ExpectingAnyLockExClass); +// commonNamedQueryTest("testNamedQueryDeadLockException", LockModeType.PESSIMISTIC_FORCE_INCREMENT, +// ExpectingAnyLockExClass); } private void commonNamedQueryTest( String testName, @@ -116,6 +120,8 @@ public class TestMixedLockManagerDeadlock extends SequencedActionsTest { {Act.WaitAllChildren}, {Act.TestException, 1, t1Exceptions}, + + {Act.RollbackTx} }; Object[][] thread1 = { {Act.CreateEm}, @@ -124,6 +130,7 @@ public class TestMixedLockManagerDeadlock extends SequencedActionsTest { {Act.Flush}, {Act.Notify, 0}, + {Act.Sleep, 1000}, {Act.NamedQueryWithLock, "findEmployeeById", 1, t1Lock, "openjpa.hint.IgnorePreparedQuery", true}, {Act.RollbackTx}, diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerFindPermutation.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerFindPermutation.java index c581cc8f0..f19be88af 100644 --- a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerFindPermutation.java +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerFindPermutation.java @@ -38,7 +38,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(Read,Commit/Read,Commit)", LockModeType.READ, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(Read,Commit/Read,Rollback)", LockModeType.READ, Act.CommitTx, 1, null, @@ -49,8 +49,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(Read,Commit/Write,Commit)", LockModeType.READ, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(Read,Commit/Write,Rollback)", LockModeType.READ, Act.CommitTx, 1, null, @@ -95,7 +94,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(Write,Commit/Read,Commit)", LockModeType.WRITE, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(Write,Commit/Read,Rollback)", LockModeType.WRITE, Act.CommitTx, 1, null, @@ -106,8 +105,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(Write,Commit/Write,Commit)", LockModeType.WRITE, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(Write,Commit/Write,Rollback)", LockModeType.WRITE, Act.CommitTx, 1, null, @@ -139,8 +137,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { public void testFindWritePessimisticForceInc() { commonFindTest( "testFind(Write,Commit/PessimisticForceInc,Commit)", - LockModeType.WRITE, Act.CommitTx, 1, - ExpectingOptimisticLockExClass, + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass, LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null); commonFindTest( "testFind(Write,Commit/PessimisticForceInc,Rollback)", @@ -153,7 +150,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(PessimisticRead,Commit/Read,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(PessimisticRead,Commit/Read,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, @@ -164,8 +161,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(PessimisticRead,Commit/Write,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(PessimisticRead,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, @@ -177,12 +173,10 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { "testFind(PessimisticRead,Commit/PessimisticRead,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, LockModeType.PESSIMISTIC_READ, Act.CommitTx, 0, null); -// ExpectingOptimisticLockExClass); commonFindTest( "testFind(PessimisticRead,Commit/PessimisticRead,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, LockModeType.PESSIMISTIC_READ, Act.RollbackTx, 0, null); -// ExpectingOptimisticLockExClass); } public void testFindPessimisticReadPessimisticWrite() { @@ -212,7 +206,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(PessimsiticWrite,Commit/Read,Commit)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(PessimsiticWrite,Commit/Read,Rollback)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, @@ -223,8 +217,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(PessimsiticWrite,Commit/Write,Commit)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(PessimsiticWrite,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, @@ -269,7 +262,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(PessimsiticForceInc,Commit/Read,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(PessimsiticForceInc,Commit/Read,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, @@ -280,8 +273,7 @@ public class TestMixedLockManagerFindPermutation extends SequencedActionsTest { commonFindTest( "testFind(PessimsiticForceInc,Commit/Write,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonFindTest( "testFind(PessimsiticForceInc,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerLockPermutation.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerLockPermutation.java index 2efe714d4..5f72d6c2f 100644 --- a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerLockPermutation.java +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerLockPermutation.java @@ -38,7 +38,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(Read,Commit/Read,Commit)", LockModeType.READ, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(Read,Commit/Read,Rollback)", LockModeType.READ, Act.CommitTx, 1, null, @@ -49,8 +49,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(Read,Commit/Write,Commit)", LockModeType.READ, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(Read,Commit/Write,Rollback)", LockModeType.READ, Act.CommitTx, 1, null, @@ -95,7 +94,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(Write,Commit/Read,Commit)", LockModeType.WRITE, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(Write,Commit/Read,Rollback)", LockModeType.WRITE, Act.CommitTx, 1, null, @@ -106,8 +105,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(Write,Commit/Write,Commit)", LockModeType.WRITE, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(Write,Commit/Write,Rollback)", LockModeType.WRITE, Act.CommitTx, 1, null, @@ -139,8 +137,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { public void testLockWritePessimisticForceInc() { commonLockTest( "testLock(Write,Commit/PessimisticForceInc,Commit)", - LockModeType.WRITE, Act.CommitTx, 1, - ExpectingOptimisticLockExClass, + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass, LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null); commonLockTest( "testLock(Write,Commit/PessimisticForceInc,Rollback)", @@ -153,7 +150,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimisticRead,Commit/Read,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimisticRead,Commit/Read,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, @@ -164,8 +161,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimisticRead,Commit/Write,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimisticRead,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, @@ -176,39 +172,33 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimisticRead,Commit/PessimisticRead,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimisticRead,Commit/PessimisticRead,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_READ, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_READ, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } public void testLockPessimisticReadPessimisticWrite() { commonLockTest( "testLock(PessimisticRead,Commit/PessimisticWrite,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimisticRead,Commit/PessimisticWrite,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_WRITE, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_WRITE, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } public void testLockPessimisticReadPessimisticForceInc() { commonLockTest( "testLock(PessimisticRead,Commit/PessimisticForceInc,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimisticRead,Commit/PessimisticForceInc,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } /* ======== Thread 1 : Pessimsitic Write Lock ============*/ @@ -216,7 +206,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimsiticWrite,Commit/Read,Commit)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticWrite,Commit/Read,Rollback)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, @@ -227,8 +217,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimsiticWrite,Commit/Write,Commit)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticWrite,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, @@ -239,39 +228,33 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimsiticWrite,Commit/PessimisticRead,Commit)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticWrite,Commit/PessimisticRead,Rollback)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_READ, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_READ, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } public void testLockPessimsiticWritePessimisticWrite() { commonLockTest( "testLock(PessimsiticWrite,Commit/PessimisticWrite,Commit)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticWrite,Commit/PessimisticWrite,Rollback)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_WRITE, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_WRITE, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } public void testLockPessimsiticWritePessimisticForceInc() { commonLockTest( "testLock(PessimsiticWrite,Commit/PessimisticForceInc,Commit)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticWrite,Commit/PessimisticForceInc,Rollback)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } /* ======== Thread 1 : Pessimsitic Force Increment Lock ============*/ @@ -279,7 +262,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimsiticForceInc,Commit/Read,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticForceInc,Commit/Read,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, @@ -290,8 +273,7 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimsiticForceInc,Commit/Write,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticForceInc,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, @@ -302,39 +284,33 @@ public class TestMixedLockManagerLockPermutation extends SequencedActionsTest { commonLockTest( "testLock(PessimsiticForceInc,Commit/PessimisticRead,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_READ, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticForceInc,Commit/PessimisticRead,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_READ, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_READ, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } public void testLockPessimsiticForceIncPessimisticWrite() { commonLockTest( "testLock(PessimsiticForceInc,Commit/PessimisticWrite,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticForceInc,Commit/PessimisticWrite,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_WRITE, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_WRITE, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } public void testLockPessimsiticForceIncPessimisticForceInc() { commonLockTest( "testLock(PessimsiticForceInc,Commit/PessimisticForceInc,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, ExpectingOptimisticLockExClass); commonLockTest( "testLock(PessimsiticForceInc,Commit/PessimisticForceInc,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 1, null, - LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.RollbackTx, 1, - ExpectingOptimisticLockExClass); + LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.RollbackTx, 1, ExpectingOptimisticLockExClass); } private void commonLockTest( String testName, diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerRefreshPermutation.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerRefreshPermutation.java index 4ff542a89..5a5527c25 100644 --- a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerRefreshPermutation.java +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestMixedLockManagerRefreshPermutation.java @@ -107,8 +107,7 @@ public class TestMixedLockManagerRefreshPermutation commonRefreshTest( "testRefresh(Write,Commit/Write,Commit)", LockModeType.WRITE, Act.CommitTx, 2, null, - LockModeType.WRITE, Act.CommitTx, 2, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 2, ExpectingOptimisticLockExClass); commonRefreshTest( "testRefresh(Write,Commit/Write,Rollback)", LockModeType.WRITE, Act.CommitTx, 2, null, @@ -140,8 +139,7 @@ public class TestMixedLockManagerRefreshPermutation public void testRefreshWritePessimisticForceInc() { commonRefreshTest( "testRefresh(Write,Commit/PessimisticForceInc,Commit)", - LockModeType.WRITE, Act.CommitTx, 2, - ExpectingOptimisticLockExClass, + LockModeType.WRITE, Act.CommitTx, 2, ExpectingOptimisticLockExClass, LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, null); commonRefreshTest( "testRefresh(Write,Commit/PessimisticForceInc,Rollback)", @@ -165,8 +163,7 @@ public class TestMixedLockManagerRefreshPermutation commonRefreshTest( "testRefresh(PessimisticRead,Commit/Write,Commit)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 2, null, - LockModeType.WRITE, Act.CommitTx, 2, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 2, ExpectingOptimisticLockExClass); commonRefreshTest( "testRefresh(PessimisticRead,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_READ, Act.CommitTx, 2, null, @@ -206,7 +203,7 @@ public class TestMixedLockManagerRefreshPermutation LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.RollbackTx, 2, null); } - /* ======== Thread 1 : Pessimsitic Write Lock ============*/ + /* ======== Thread 1 : Pessimistic Write Lock ============*/ public void testRefreshPessimsiticWriteRead() { commonRefreshTest( "testRefresh(PessimsiticWrite,Commit/Read,Commit)", @@ -222,8 +219,7 @@ public class TestMixedLockManagerRefreshPermutation commonRefreshTest( "testRefresh(PessimsiticWrite,Commit/Write,Commit)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 2, null, - LockModeType.WRITE, Act.CommitTx, 2, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 2, ExpectingOptimisticLockExClass); commonRefreshTest( "testRefresh(PessimsiticWrite,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_WRITE, Act.CommitTx, 2, null, @@ -268,7 +264,7 @@ public class TestMixedLockManagerRefreshPermutation commonRefreshTest( "testRefresh(PessimsiticForceInc,Commit/Read,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, null, - LockModeType.READ, Act.CommitTx, 0, ExpectingOptimisticLockExClass); + LockModeType.READ, Act.CommitTx, 2, ExpectingOptimisticLockExClass); commonRefreshTest( "testRefresh(PessimsiticForceInc,Commit/Read,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, null, @@ -279,8 +275,7 @@ public class TestMixedLockManagerRefreshPermutation commonRefreshTest( "testRefresh(PessimsiticForceInc,Commit/Write,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, null, - LockModeType.WRITE, Act.CommitTx, 0, - ExpectingOptimisticLockExClass); + LockModeType.WRITE, Act.CommitTx, 2, ExpectingOptimisticLockExClass); commonRefreshTest( "testRefresh(PessimsiticForceInc,Commit/Write,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, null, @@ -311,13 +306,11 @@ public class TestMixedLockManagerRefreshPermutation public void testRefreshPessimsiticForceIncPessimisticForceInc() { commonRefreshTest( - "testRefresh(PessimsiticForceInc,Commit/" - + "PessimisticForceInc,Commit)", + "testRefresh(PessimsiticForceInc,Commit/PessimisticForceInc,Commit)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 3, null, LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 3, null); commonRefreshTest( - "testRefresh(PessimsiticForceInc,Commit/" - + "PessimisticForceInc,Rollback)", + "testRefresh(PessimsiticForceInc,Commit/PessimisticForceInc,Rollback)", LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.CommitTx, 2, null, LockModeType.PESSIMISTIC_FORCE_INCREMENT, Act.RollbackTx, 2, null); } diff --git a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java index cacfd05b0..f213d1917 100644 --- a/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java +++ b/openjpa-persistence-locking/src/test/java/org/apache/openjpa/persistence/lockmgr/TestPessimisticLocks.java @@ -28,6 +28,8 @@ import javax.persistence.PessimisticLockException; import javax.persistence.Query; import javax.persistence.QueryTimeoutException; +import org.apache.openjpa.jdbc.conf.JDBCConfiguration; +import org.apache.openjpa.jdbc.sql.DBDictionary; import org.apache.openjpa.persistence.test.SQLListenerTestCase; /** @@ -35,9 +37,11 @@ import org.apache.openjpa.persistence.test.SQLListenerTestCase; */ public class TestPessimisticLocks extends SQLListenerTestCase { + private DBDictionary dict = null; + public void setUp() { setSupportedDatabases( -// org.apache.openjpa.jdbc.sql.DerbyDictionary.class, + org.apache.openjpa.jdbc.sql.DerbyDictionary.class, // org.apache.openjpa.jdbc.sql.OracleDictionary.class, org.apache.openjpa.jdbc.sql.DB2Dictionary.class); if (isTestsDisabled()) { @@ -48,6 +52,8 @@ public class TestPessimisticLocks extends SQLListenerTestCase { String empTable = getMapping(Employee.class).getTable().getFullName(); String deptTable = getMapping(Department.class).getTable().getFullName(); + dict= ((JDBCConfiguration)emf.getConfiguration()).getDBDictionaryInstance(); + EntityManager em = null; try { em = emf.createEntityManager(); @@ -96,25 +102,27 @@ public class TestPessimisticLocks extends SQLListenerTestCase { } /* - * Test a find with pessimistic lock after a query with pessimistic lock and expect PessimisticLockException. + * Test find with pessimistic lock after a query with pessimistic lock. */ - public void testFindWithLockTimeoutAfterQueryWithPessimisticLocks() { + public void testFindAfterQueryWithPessimisticLocks() { EntityManager em1 = emf.createEntityManager(); EntityManager em2 = emf.createEntityManager(); try { em1.getTransaction().begin(); - Query query = em1.createQuery( - "select e from Employee e where e.id < 10 order by e.id").setFirstResult(1); + "select e from Employee e where e.id < 10").setFirstResult(1); + // Lock all selected Employees, skip the first one, i.e should lock Employee(2) query.setLockMode(LockModeType.PESSIMISTIC_READ); + query.setHint("javax.persistence.query.timeout", 2000); List q = query.getResultList(); assertEquals("Expected 1 element with emplyee id=2", q.size(), 1); - assertEquals("Test Employee first name = 'first.2'", q.get(0).getFirstName(), "first.2"); + assertTrue("Test Employee first name = 'first.2'", q.get(0).getFirstName().equals("first.1") + || q.get(0).getFirstName().equals("first.2")); em2.getTransaction().begin(); - Map map = new HashMap(); map.put("javax.persistence.lock.timeout", 2000); + // find Employee(2) with a lock, should block and expected a PessimisticLockException em2.find(Employee.class, 2, LockModeType.PESSIMISTIC_READ, map); fail("Unexcpected find succeeded. Should throw a PessimisticLockException."); } catch (QueryTimeoutException e) { @@ -135,23 +143,193 @@ public class TestPessimisticLocks extends SQLListenerTestCase { try { em1.getTransaction().begin(); + Query query = em1.createQuery( + "select e.department from Employee e where e.id < 10").setFirstResult(1); + // Lock all selected Departments, skip the first one, i.e should lock Department(20) + query.setLockMode(LockModeType.PESSIMISTIC_READ); + query.setHint("javax.persistence.query.timeout", 2000); + List q = query.getResultList(); + assertEquals("Expected 1 element with department id=20", q.size(), 1); + assertTrue("Test department name = 'D20'", q.get(0).getName().equals("D10") + || q.get(0).getName().equals("D20")); + em2.getTransaction().begin(); + Map map = new HashMap(); + map.put("javax.persistence.lock.timeout", 2000); + // find Employee(2) with a lock, no block since only department was locked + Employee emp = em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map); + assertNotNull("Query locks department only, therefore should find Employee.", emp); + assertEquals("Test Employee first name = 'first.1'", emp.getFirstName(), "first.1"); + } catch (QueryTimeoutException e) { + // TODO: DB2: This is the current unexpected exception due to OPENJPA-991. + // Remove this when the problem is fixed +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + if( !(dict instanceof org.apache.openjpa.jdbc.sql.DB2Dictionary)) { + fail("Caught unexpected " + e.getClass().getName() + ":" + e.getMessage()); + } + } catch (PessimisticLockException e) { + // TODO: This is the expected exception but will be fixed under OPENJPA-991 +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + if( !(dict instanceof org.apache.openjpa.jdbc.sql.DB2Dictionary)) { + fail("Caught unexpected " + e.getClass().getName() + ":" + e.getMessage()); + } + } catch (Exception ex) { + fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage()); + } finally { + if( em1.getTransaction().isActive()) + em1.getTransaction().rollback(); + if( em2.getTransaction().isActive()) + em2.getTransaction().rollback(); + } + em1.close(); + em2.close(); + } + + /* + * Test find with pessimistic lock after a query with pessimistic lock. + */ + public void testFindAfterQueryOrderByWithPessimisticLocks() { + EntityManager em1 = emf.createEntityManager(); + EntityManager em2 = emf.createEntityManager(); + try { + em1.getTransaction().begin(); + Query query = em1.createQuery( + "select e from Employee e where e.id < 10 order by e.id").setFirstResult(1); + // Lock all selected Employees, skip the first one, i.e should lock Employee(2) + query.setLockMode(LockModeType.PESSIMISTIC_READ); + query.setHint("javax.persistence.query.timeout", 2000); + List q = query.getResultList(); + assertEquals("Expected 1 element with emplyee id=2", q.size(), 1); + assertEquals("Test Employee first name = 'first.2'", q.get(0).getFirstName(), "first.2"); + + em2.getTransaction().begin(); + Map map = new HashMap(); + map.put("javax.persistence.lock.timeout", 2000); + // find Employee(2) with a lock, should block and expected a PessimisticLockException + em2.find(Employee.class, 2, LockModeType.PESSIMISTIC_READ, map); + fail("Unexcpected find succeeded. Should throw a PessimisticLockException."); + } catch (QueryTimeoutException e) { + // TODO: DB2: This is the current unexpected exception due to OPENJPA-991. + // Remove this when the problem is fixed +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + } catch (PessimisticLockException e) { + // TODO: This is the expected exception but will be fixed under OPENJPA-991 +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + } catch (Exception ex) { + fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage()); + } finally { + if( em1.getTransaction().isActive()) + em1.getTransaction().rollback(); + if( em2.getTransaction().isActive()) + em2.getTransaction().rollback(); + } + + try { + em1.getTransaction().begin(); Query query = em1.createQuery( "select e.department from Employee e where e.id < 10 order by e.department.id").setFirstResult(1); + // Lock all selected Departments, skip the first one, i.e should lock Department(20) query.setLockMode(LockModeType.PESSIMISTIC_READ); + query.setHint("javax.persistence.query.timeout", 2000); List q = query.getResultList(); assertEquals("Expected 1 element with department id=20", q.size(), 1); assertEquals("Test department name = 'D20'", q.get(0).getName(), "D20"); + em2.getTransaction().begin(); + Map map = new HashMap(); + map.put("javax.persistence.lock.timeout", 2000); + // find Employee(2) with a lock, no block since only department was locked + Employee emp = em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map); + assertNotNull("Query locks department only, therefore should find Employee.", emp); + assertEquals("Test Employee first name = 'first.1'", emp.getFirstName(), "first.1"); + } catch (QueryTimeoutException e) { + // TODO: DB2: This is the current unexpected exception due to OPENJPA-991. + // Remove this when the problem is fixed +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + if( !(dict instanceof org.apache.openjpa.jdbc.sql.DB2Dictionary)) { + fail("Caught unexpected " + e.getClass().getName() + ":" + e.getMessage()); + } + } catch (PessimisticLockException e) { + // TODO: This is the expected exception but will be fixed under OPENJPA-991 +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + if( !(dict instanceof org.apache.openjpa.jdbc.sql.DB2Dictionary)) { + fail("Caught unexpected " + e.getClass().getName() + ":" + e.getMessage()); + } + } catch (Exception ex) { + fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage()); + } finally { + if( em1.getTransaction().isActive()) + em1.getTransaction().rollback(); + if( em2.getTransaction().isActive()) + em2.getTransaction().rollback(); + } + em1.close(); + em2.close(); + } + + /* + * Test query with pessimistic lock after a find with pessimistic lock. + */ + public void testQueryAfterFindWithPessimisticLocks() { + EntityManager em1 = emf.createEntityManager(); + EntityManager em2 = emf.createEntityManager(); + try { + em2.getTransaction().begin(); + Map map = new HashMap(); + map.put("javax.persistence.lock.timeout", 2000); + // Lock Emplyee(1), no department should be locked + em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map); + + em1.getTransaction().begin(); + Query query = em1.createQuery( + "select e.department from Employee e where e.id < 10").setFirstResult(1); + query.setLockMode(LockModeType.PESSIMISTIC_READ); + query.setHint("javax.persistence.query.timeout", 2000); + // Lock all selected Department but skip the first, i.e. lock Department(20), should query successfully. + List q = query.getResultList(); + assertEquals("Expected 1 element with department id=20", q.size(), 1); + assertTrue("Test department name = 'D20'", q.get(0).getName().equals("D10") + || q.get(0).getName().equals("D20")); + } catch (QueryTimeoutException e) { + // TODO: DB2: This is the current unexpected exception due to OPENJPA-991. + // Remove this when the problem is fixed +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + if( !(dict instanceof org.apache.openjpa.jdbc.sql.DB2Dictionary)) { + fail("Caught unexpected " + e.getClass().getName() + ":" + e.getMessage()); + } + } catch (PessimisticLockException e) { + // TODO: This is the expected exception but will be fixed under OPENJPA-991 +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + if( !(dict instanceof org.apache.openjpa.jdbc.sql.DB2Dictionary)) { + fail("Caught unexpected " + e.getClass().getName() + ":" + e.getMessage()); + } + } catch (Exception ex) { + fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage()); + } finally { + if( em1.getTransaction().isActive()) + em1.getTransaction().rollback(); + if (em2.getTransaction().isActive()) + em2.getTransaction().rollback(); + } + + try { em2.getTransaction().begin(); Map map = new HashMap(); map.put("javax.persistence.lock.timeout", 2000); - Employee emp = em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map); - assertNotNull("Query locks department but find locks Employee.", emp); - fail("Unexcpected find succeeded. Should throw a PessimisticLockException."); + // Lock Emplyee(2), no department should be locked + em2.find(Employee.class, 2, LockModeType.PESSIMISTIC_READ, map); + + em1.getTransaction().begin(); + Query query = em1.createQuery( + "select e from Employee e where e.id < 10").setFirstResult(1); + // Lock all selected Employees, skip the first one, i.e should lock Employee(2) + query.setLockMode(LockModeType.PESSIMISTIC_READ); + query.setHint("javax.persistence.query.timeout", 2000); + List q = query.getResultList(); + fail("Unexcpected find succeeded. Should throw a QueryLockException."); } catch (QueryTimeoutException e) { - // TODO: This is the current unexpected exception due to OPENJPA-991. Remove this when the problem is fixed + // This is the expected exception. // System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); } catch (PessimisticLockException e) { // TODO: This is the expected exception but will be fixed under OPENJPA-991 @@ -169,28 +347,40 @@ public class TestPessimisticLocks extends SQLListenerTestCase { } /* - * Test a query with pessimistic lock after a find with pessimistic lock and expect PessimisticLockException. + * Test query with pessimistic lock after a find with pessimistic lock. */ - public void testQueryAfterFindWithPessimisticLocks() { + public void testQueryOrderByAfterFindWithPessimisticLocks() { EntityManager em1 = emf.createEntityManager(); EntityManager em2 = emf.createEntityManager(); try { em2.getTransaction().begin(); - Map map = new HashMap(); map.put("javax.persistence.lock.timeout", 2000); + // Lock Emplyee(1), no department should be locked em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map); em1.getTransaction().begin(); - Query query = em1.createQuery( "select e.department from Employee e where e.id < 10 order by e.department.id").setFirstResult(1); query.setLockMode(LockModeType.PESSIMISTIC_READ); + query.setHint("javax.persistence.query.timeout", 2000); + // Lock all selected Department but skip the first, i.e. lock Department(20), should query successfully. List q = query.getResultList(); - - fail("Unexcpected find succeeded. Should throw a PessimisticLockException."); + assertEquals("Expected 1 element with department id=20", q.size(), 1); + assertEquals("Test department name = 'D20'", q.get(0).getName(), "D20"); + } catch (QueryTimeoutException e) { + // TODO: DB2: This is the current unexpected exception due to OPENJPA-991. + // Remove this when the problem is fixed +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + if( !(dict instanceof org.apache.openjpa.jdbc.sql.DB2Dictionary)) { + fail("Caught unexpected " + e.getClass().getName() + ":" + e.getMessage()); + } } catch (PessimisticLockException e) { - // This is the expected exception. + // TODO: This is the expected exception but will be fixed under OPENJPA-991 +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + if( !(dict instanceof org.apache.openjpa.jdbc.sql.DB2Dictionary)) { + fail("Caught unexpected " + e.getClass().getName() + ":" + e.getMessage()); + } } catch (Exception ex) { fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage()); } finally { @@ -199,35 +389,29 @@ public class TestPessimisticLocks extends SQLListenerTestCase { if (em2.getTransaction().isActive()) em2.getTransaction().rollback(); } - em1.close(); - em2.close(); - } - - /* - * Test a query with pessimistic lock with query timeout set after a find - * with pessimistic lock and expect QueryTimeoutException. - */ - public void testQueryWithQueryTimeoutAfterFindWithPessimisticLocks() { - EntityManager em1 = emf.createEntityManager(); - EntityManager em2 = emf.createEntityManager(); + try { em2.getTransaction().begin(); Map map = new HashMap(); map.put("javax.persistence.lock.timeout", 2000); - em2.find(Employee.class, 1, LockModeType.PESSIMISTIC_READ, map); + // Lock Emplyee(2), no department should be locked + em2.find(Employee.class, 2, LockModeType.PESSIMISTIC_READ, map); em1.getTransaction().begin(); - Query query = em1.createQuery( - "select e.department from Employee e where e.id < 10 order by e.department.id").setFirstResult(1); + "select e from Employee e where e.id < 10 order by e.department.id").setFirstResult(1); + // Lock all selected Employees, skip the first one, i.e should lock Employee(2) query.setLockMode(LockModeType.PESSIMISTIC_READ); query.setHint("javax.persistence.query.timeout", 2000); - List q = query.getResultList(); - - fail("Unexcpected find succeeded. Should throw a PessimisticLockException."); + List q = query.getResultList(); + fail("Unexcpected find succeeded. Should throw a QueryLockException."); } catch (QueryTimeoutException e) { // This is the expected exception. +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); + } catch (PessimisticLockException e) { + // TODO: This is the expected exception but will be fixed under OPENJPA-991 +// System.out.println("Caught " + e.getClass().getName() + ":" + e.getMessage()); } catch (Exception ex) { fail("Caught unexpected " + ex.getClass().getName() + ":" + ex.getMessage()); } finally {