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 da...@apache.org on 2013/12/11 23:36:48 UTC
svn commit: r1550299 - in /db/derby/code/trunk/java:
engine/org/apache/derby/impl/sql/execute/
testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: dag
Date: Wed Dec 11 22:36:47 2013
New Revision: 1550299
URL: http://svn.apache.org/r1550299
Log:
DERBY-6419 Make BTree scan honor OPENMODE_LOCK_NOWAIT for row locks
A follow-up patch: derby-6419-followup.
Only short circuit waiting for lock in BTree scan to check duplicates
for a deferred unique/pk constraint if constraint mode is deferred
(i.e. not if immediate).
Added a test case lifted from UniqueConstraintMultiThreadedTest, which
exposed the issue when we run the regressions with default deferrable
by default (see DERBY-532).
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ConstraintCharacteristicsTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UniqueConstraintMultiThreadedTest.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java?rev=1550299&r1=1550298&r2=1550299&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java Wed Dec 11 22:36:47 2013
@@ -464,10 +464,20 @@ class IndexChanger
final DataValueDescriptor [] key =
new DataValueDescriptor[rowArray.length - 1];
System.arraycopy(rowArray, 0, key, 0, key.length);
+
+ // If the constraint mode is deferred, perform the check without
+ // waiting for any locks; we will just presume any lock conflicts
+ // constitute duplicates (not always the case), and check those keys
+ // again at commit time.
+ final boolean deferred =
+ lcc.isEffectivelyDeferred(activation, indexCID);
+
ScanController idxScan = tc.openScan(
indexCID,
false,
- TransactionController.OPENMODE_LOCK_ROW_NOWAIT,
+ (deferred ?
+ TransactionController.OPENMODE_LOCK_ROW_NOWAIT :
+ 0),
TransactionController.MODE_RECORD,
TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK,
(FormatableBitSet)null, // retrieve all fields
@@ -492,7 +502,7 @@ class IndexChanger
} catch (StandardException e) {
if ((e.getSQLState().equals(SQLState.LOCK_TIMEOUT) ||
e.getSQLState().equals(SQLState.DEADLOCK)) &&
- lcc.isEffectivelyDeferred(activation, indexCID)) {
+ deferred) {
// Assume there is a duplicate, so we'll check again at
// commit time.
duplicate = true;
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ConstraintCharacteristicsTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ConstraintCharacteristicsTest.java?rev=1550299&r1=1550298&r2=1550299&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ConstraintCharacteristicsTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/ConstraintCharacteristicsTest.java Wed Dec 11 22:36:47 2013
@@ -100,6 +100,10 @@ public class ConstraintCharacteristicsTe
s.addTest(new ConstraintCharacteristicsTest(
"testLocking"));
s.addTest(new ConstraintCharacteristicsTest(
+ "testLockingWithCommit"));
+ s.addTest(new ConstraintCharacteristicsTest(
+ "testLockingWithRollback"));
+ s.addTest(new ConstraintCharacteristicsTest(
"testDatabaseMetaData"));
s.addTest(new ConstraintCharacteristicsTest(
"testCreateConstraintDictionaryEncodings"));
@@ -1168,6 +1172,146 @@ public class ConstraintCharacteristicsTe
}
}
+ private void setupTab1() throws SQLException {
+ Statement stmt = createStatement();
+ stmt.execute(
+ "create table tab1 (i integer)");
+ stmt.executeUpdate(
+ "alter table tab1 add constraint con1 unique (i) deferrable");
+ PreparedStatement ps = prepareStatement("insert into tab1 " +
+ "values (?)");
+
+ for (int i = 0; i < 10; i++) {
+ ps.setInt(1, i);
+ ps.executeUpdate();
+ }
+
+ ps.close();
+ stmt.close();
+ commit();
+ }
+
+
+ private void dropTab1() throws SQLException {
+ Statement stmt = createStatement();
+ try {
+ stmt.execute("drop table tab1");
+ commit();
+ } catch (SQLException e) {
+ // ignore so we get to see original exception if there is one
+ }
+ }
+
+ /**
+ * Test inserting a duplicate record while original is deleted in a
+ * transaction and later committed.
+ * <p/>
+ * This test was lifted from UniqueConstraintMultiThrededTest
+ * except that here we run it with a deferrable constraint. We
+ * include it her e since it exposed a bug during implementation
+ * of deferrable constraints: we check a deferrable constraint
+ * <em>after</em> the insert (cf. {@code IndexChanger}) by using a
+ * BTree scan. Iff the constraint mode is deferred, we treat any
+ * lock or deadlock timeout as if it were a duplicate, allowing us
+ * to defer the check till commit time, as so possibly gain more
+ * concurrency. To get speed in this case, the scan returns
+ * immediately if it can't get a lock. The error was that, if the
+ * constraint mode is <em>not</em> deferred (i.e. immediate), we
+ * should wait for the lock, and we didn't. This was exposed by
+ * this test since the 2 seconds wait makes it work in the normal
+ * case (the lock would be released), but in the no-wait scan, we
+ * saw a the lock time-out error.
+ */
+ public void testLockingWithCommit () throws Exception {
+ setupTab1();
+
+ try {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ executeThreads(
+ (int)Math.pow(2,i),
+ (int)Math.pow(2,j), true);
+ }
+ }
+ } finally {
+ dropTab1();
+ }
+ }
+
+ /**
+ * Test inserting a duplicate record while original is deleted in
+ * a transaction and later rolled back.
+ * <p/>
+ * See also comment for {@link #testLockingWithCommit() }.
+ */
+ public void testLockingWithRollback () throws Exception {
+ setupTab1();
+
+ try {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ executeThreads(
+ (int)Math.pow(2,i),
+ (int)Math.pow(2,j), false);
+ }
+ }
+ } finally {
+ dropTab1();
+ }
+ }
+
+ /**
+ * Deletes a record in a transaction and tries to insert the same
+ * from a different transaction. Once second transaction goes on wait
+ * first transaction is committed or rolled back based on third
+ * parameter (boolean commit).
+ *
+ * @param isolation1 isolation level for 1st thread
+ * @param isolation2 isolation level for 2nd thread
+ * @param commit whether or not to commit
+ *
+ * (Lifted from UniqueConstraintMultiThrededTest to test with deferrable
+ * constraint.)
+ */
+ private void executeThreads (int isolation1, int isolation2,
+ boolean commit) throws Exception {
+ Connection con1 = openDefaultConnection();
+ con1.setTransactionIsolation(isolation1);
+ Connection con2 = openDefaultConnection();
+ try {
+ con2.setTransactionIsolation(isolation2);
+ DBOperations dbo1 = new DBOperations (con1, 5);
+ DBOperations dbo2 = new DBOperations (con2, 5);
+ dbo1.delete();
+ Thread t = new Thread (dbo2);
+ t.start();
+ //wait for 2 sec should be enough for dbo2 so on wait
+ t.sleep(2000);
+ if (commit) {
+ dbo1.rollback();
+ t.join();
+ assertSQLState("isolation levels: " + isolation1
+ + " " + isolation2, "23505", dbo2.getException());
+ }
+ else {
+ dbo1.commit();
+ t.join();
+ assertNull("isolation levels: " + isolation1
+ + " " + isolation2, dbo2.getException());
+ }
+ assertNull("unexpected failure: " + isolation1
+ + " " + isolation2, dbo2.getUnexpectedException());
+ }
+ finally {
+ con1.commit();
+ con2.commit();
+ con1.close();
+ con2.close();
+ }
+
+ }
+
+
private Xid doXAWork(Statement s, XAResource xar)
throws SQLException, XAException {
Xid xid = XATestUtil.getXid(1,05,32);
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UniqueConstraintMultiThreadedTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UniqueConstraintMultiThreadedTest.java?rev=1550299&r1=1550298&r2=1550299&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UniqueConstraintMultiThreadedTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/UniqueConstraintMultiThreadedTest.java Wed Dec 11 22:36:47 2013
@@ -1,6 +1,6 @@
/*
-Derby - Class org.apache.derbyTesting.functionTests.tests.lang.UniqueConstraintMultiThrededTest
+Derby - Class org.apache.derbyTesting.functionTests.tests.lang.UniqueConstraintMultiThreadedTest
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with