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 mi...@apache.org on 2012/02/07 03:53:30 UTC

svn commit: r1241335 - /db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java

Author: mikem
Date: Tue Feb  7 02:53:30 2012
New Revision: 1241335

URL: http://svn.apache.org/viewvc?rev=1241335&view=rev
Log:
DERBY-3740 BlobClob4BlobTest.testLockingWithLongRowBlob fails with .AssertionFailedError: FAIL - statement should timeout

backported change #1240521 from trunk to 10.4 branch

The 2 tests that were failing intermittently (testLockingWithLongRowBlob
and testLockingBlob) would both select a target blob known to be returned
as a stream, and assign it to a variable.  The expectation was that until
the end of the routine Derby would maintain a read lock on the blob.  The
problem was that it looks like some JVMs/JITs would recognize that the variable
was never used and call finalize before the test executed the code to
get an expected lock timeout on updating the blob in another connection.
Fixed by adding references to the variable in code executed after the
expected timeout.  Before the fix test was failing about 1/2 time in my
environment, after the fix the test ran 100 times without a failure.


Modified:
    db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java

Modified: db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java?rev=1241335&r1=1241334&r2=1241335&view=diff
==============================================================================
--- db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java (original)
+++ db/derby/code/branches/10.4/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/BlobClob4BlobTest.java Tue Feb  7 02:53:30 2012
@@ -69,10 +69,16 @@ public class BlobClob4BlobTest extends B
         stmt.executeUpdate("CREATE TABLE testClob (b INT, c INT)");
         stmt.executeUpdate("ALTER TABLE testClob ADD COLUMN a CLOB(300K)");
 
+        // multiple tests depend on small page size, make sure size is 4k
+        checkSmallPageSize(stmt, "TESTCLOB");
+
         stmt.executeUpdate("CREATE TABLE testBlob (b INT)");
         stmt.executeUpdate("ALTER TABLE testBlob ADD COLUMN a blob(300k)");
         stmt.executeUpdate("ALTER TABLE testBlob ADD COLUMN crc32 BIGINT");
 
+        // multiple tests depend on small page size, make sure size is 4k
+        checkSmallPageSize(stmt, "TESTBLOB");
+
         stmt.close();
         commit();
     }
@@ -1272,6 +1278,11 @@ public class BlobClob4BlobTest extends B
         } catch (SQLException se) {
             checkException(LOCK_TIMEOUT, se);
         }
+
+        // DERBY-3740, the reference below to clob must remain after the above
+        // expected lock timeout, otherwise GC might run on the clob and
+        // cause intermittent problems if the GC causes lock to be released
+        // early.
         assertEquals("FAIL: clob length changed", 10000, clob.length());
         
         // Test that update goes through after the transaction is committed
@@ -2375,9 +2386,17 @@ public class BlobClob4BlobTest extends B
      * test locking
      */
     public void testLockingBlob() throws Exception {
-        insertDefaultData();
 
         Statement stmt = createStatement();
+
+        insertDefaultData();
+
+        // for blob lock to remain, autocommit must be false.
+        assertFalse(getConnection().getAutoCommit());
+
+        // test depends on small page size, make sure size is 4k
+        checkSmallPageSize(stmt, "TESTBLOB");
+
         ResultSet rs = stmt.executeQuery("select a,b from testBlob");
         // fetch row back, get the column as a blob.
         Blob blob = null, shortBlob = null;
@@ -2391,6 +2410,7 @@ public class BlobClob4BlobTest extends B
         }
         rs.close();
 
+
         Connection conn2 = openDefaultConnection();
         // turn off autocommit, otherwise blobs/clobs cannot hang around
         // until end of transaction
@@ -2414,6 +2434,21 @@ public class BlobClob4BlobTest extends B
         } catch (SQLException se) {
             checkException(LOCK_TIMEOUT, se);
         }
+
+        // DERBY-3740, add a reference to the retrieved blobs that is used
+        // after the expected lock timeout in conn2.  Before this change 
+        // this test would intermittently fail.  I believe that a smart
+        // JVM/JIT recognized that the blob reference was no longer used
+        // after the above while loop, and allowed gc on it before the routine
+        // could get to the expected conflicting lock.  Upon GC the blob's
+        // finalize code closes the internal stream and releases the lock in
+        // read committed mode.
+
+        // make sure we got the 10000 byte blob which should be a stream.
+        assertTrue(blob != null);
+
+        // make sure we got the 26 byte blob which should be materialized.
+        assertTrue(shortBlob != null);
         
         // Test that update goes through after the transaction is committed
         commit();
@@ -2432,7 +2467,15 @@ public class BlobClob4BlobTest extends B
     {
         ResultSet rs;
         Statement stmt, stmt2;
+
+        // for blob lock to remain, autocommit must be false.
+        assertFalse(getConnection().getAutoCommit());
+
         stmt = createStatement();
+
+        // test depends on small page size, make sure size is 4k
+        checkSmallPageSize(stmt, "TESTBLOB");
+
         stmt.execute("alter table testBlob add column al varchar(2000)");
         stmt.execute("alter table testBlob add column bl varchar(3000)");
         stmt.execute("alter table testBlob add column cl varchar(2000)");
@@ -2480,6 +2523,18 @@ public class BlobClob4BlobTest extends B
         }
         // Test that update goes through after the transaction is committed
         commit();
+
+        // DERBY-3740, add a reference to the retrieved blobs that is used
+        // after the expected lock timeout in conn2.  Before this change 
+        // this test would intermittently fail.  I believe that a smart
+        // JVM/JIT recognized that the blob reference was no longer used
+        // after the above while loop, and allowed gc on it before the routine
+        // could get to the expected conflicting lock.  Upon GC the blob's
+        // finalize code closes the internal stream and releases the lock in
+        // read committed mode.
+        assertTrue(
+            "FAIL - blob is null after expected lock timeout", blob != null);
+
         stmt2.executeUpdate("update testBlob set el = null where b = 1");
         
         stmt2.close();
@@ -3507,6 +3562,22 @@ public class BlobClob4BlobTest extends B
 
 
 
+
+    private void checkSmallPageSize(Statement st, String tblName)
+        throws SQLException
+    {
+        ResultSet rs = st.executeQuery(
+            "select * from TABLE(SYSCS_DIAG.SPACE_TABLE('"+tblName+"')) T");
+
+        int found_rows = 0;
+        while (rs.next())
+        {
+            found_rows++;
+            assertEquals(4096, rs.getInt("pagesize"));
+        }
+        assertTrue(found_rows == 1);
+        rs.close();
+    }
         
     
     private static final String BLOB_BAD_POSITION = "XJ070";