You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2011/07/06 13:41:42 UTC

svn commit: r1143356 - in /db/derby/code/branches/10.8: ./ java/engine/org/apache/derby/impl/sql/execute/ java/testing/org/apache/derbyTesting/functionTests/tests/lang/

Author: kahatlen
Date: Wed Jul  6 11:41:41 2011
New Revision: 1143356

URL: http://svn.apache.org/viewvc?rev=1143356&view=rev
Log:
DERBY-4275: Query executions fail when compressing a table using SYSCS_UTIL.SYSCS_COMPRESS_TABLE

Merged fix from trunk (revision 1142583).

Modified:
    db/derby/code/branches/10.8/   (props changed)
    db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java
    db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CompressTableTest.java
    db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TruncateTableTest.java

Propchange: db/derby/code/branches/10.8/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Jul  6 11:41:41 2011
@@ -1,2 +1,2 @@
 /db/derby/code/branches/10.7:1061570,1061578,1082235
-/db/derby/code/trunk:1063809,1088633,1091000,1091221,1091285,1092067,1092795,1094315,1094572,1094728,1096741,1096890,1097247,1097249,1097460,1097469,1097471,1101059,1101839,1102620,1102826,1103681,1103718,1103742,1125305,1126358,1126468,1127825,1127883,1129136,1129764,1129797,1130077,1130084,1130632,1130895,1131030,1131272,1132546,1132664,1132860,1132928,1133304,1133317,1133741,1133752,1136363,1136371,1136397,1136844,1138201,1138341,1138444,1138787,1138795,1139449,1139451,1141924,1142635
+/db/derby/code/trunk:1063809,1088633,1091000,1091221,1091285,1092067,1092795,1094315,1094572,1094728,1096741,1096890,1097247,1097249,1097460,1097469,1097471,1101059,1101839,1102620,1102826,1103681,1103718,1103742,1125305,1126358,1126468,1127825,1127883,1129136,1129764,1129797,1130077,1130084,1130632,1130895,1131030,1131272,1132546,1132664,1132860,1132928,1133304,1133317,1133741,1133752,1136363,1136371,1136397,1136844,1138201,1138341,1138444,1138787,1138795,1139449,1139451,1141924,1142583,1142635

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java?rev=1143356&r1=1143355&r2=1143356&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java (original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java Wed Jul  6 11:41:41 2011
@@ -388,7 +388,7 @@ class AlterTableConstantAction extends D
 			sd = getAndCheckSchemaDescriptor(dd, schemaId, "ALTER TABLE");
 		}
 		
-		/* Prepare all dependents to invalidate.  (This is there chance
+		/* Prepare all dependents to invalidate.  (This is their chance
 		 * to say that they can't be invalidated.  For example, an open
 		 * cursor referencing a table/view that the user is attempting to
 		 * alter.) If no one objects, then invalidate any dependent objects.
@@ -2090,14 +2090,6 @@ class AlterTableConstantAction extends D
                 TransactionController.MODE_TABLE,
                 TransactionController.ISOLATION_SERIALIZABLE);
 
-		// invalidate any prepared statements that depended on this table 
-        // (including this one), this fixes problem with threads that start up 
-        // and block on our lock, but do not see they have to recompile their 
-        // plan.  We now invalidate earlier however they still might recompile
-        // using the old conglomerate id before we commit our DD changes.
-		//
-		dm.invalidateFor(td, DependencyManager.COMPRESS_TABLE, lcc);
-
 		rl = compressHeapCC.newRowLocationTemplate();
 
 		// Get the properties on the old heap
@@ -2221,6 +2213,10 @@ class AlterTableConstantAction extends D
 		// Update sys.sysconglomerates with new conglomerate #
 		dd.updateConglomerateDescriptor(cd, newHeapConglom, tc);
 
+        // Now that the updated information is available in the system tables,
+        // we should invalidate all statements that use the old conglomerates
+        dm.invalidateFor(td, DependencyManager.COMPRESS_TABLE, lcc);
+
 		// Drop the old conglomerate
 		tc.dropConglomerate(oldHeapConglom);
 		cleanUp();
@@ -2305,15 +2301,6 @@ class AlterTableConstantAction extends D
                                 TransactionController.MODE_TABLE,
                                 TransactionController.ISOLATION_SERIALIZABLE);
 
-		// invalidate any prepared statements that
-		// depended on this table (including this one)
-		// bug 3653 has threads that start up and block on our lock, but do
-		// not see they have to recompile their plan.    We now invalidate earlier
-		// however they still might recompile using the old conglomerate id before we
-		// commit our DD changes.
-		//
-		dm.invalidateFor(td, DependencyManager.TRUNCATE_TABLE, lcc);
-
 		rl = compressHeapCC.newRowLocationTemplate();
 		// Get the properties on the old heap
 		compressHeapCC.getInternalTablePropertySet(properties);
@@ -2399,6 +2386,11 @@ class AlterTableConstantAction extends D
 
 		// Update sys.sysconglomerates with new conglomerate #
 		dd.updateConglomerateDescriptor(cd, newHeapConglom, tc);
+
+        // Now that the updated information is available in the system tables,
+        // we should invalidate all statements that use the old conglomerates
+        dm.invalidateFor(td, DependencyManager.TRUNCATE_TABLE, lcc);
+
 		// Drop the old conglomerate
 		tc.dropConglomerate(oldHeapConglom);
 		cleanUp();

Modified: db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CompressTableTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CompressTableTest.java?rev=1143356&r1=1143355&r2=1143356&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CompressTableTest.java (original)
+++ db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CompressTableTest.java Wed Jul  6 11:41:41 2011
@@ -21,10 +21,17 @@ limitations under the License.
 
 package org.apache.derbyTesting.functionTests.tests.lang;
 
+import java.sql.Connection;
+import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import junit.framework.Test;
 import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
+import org.apache.derbyTesting.junit.JDBC;
 import org.apache.derbyTesting.junit.TestConfiguration;
 
 /**
@@ -38,7 +45,8 @@ public class CompressTableTest extends B
 
     public static Test suite() {
         // compress table is an embedded feature, no need to run network tests
-        return TestConfiguration.embeddedSuite(CompressTableTest.class);
+        return new CleanDatabaseTestSetup(
+                TestConfiguration.embeddedSuite(CompressTableTest.class));
     }
 
     /**
@@ -54,4 +62,67 @@ public class CompressTableTest extends B
                   "'abc\"def', 1, 1, 1)");
         s.execute("drop table app.\"abc\"\"def\"");
     }
+
+    /**
+     * Test that statement invalidation works when SYSCS_COMPRESS_TABLE calls
+     * and other statements accessing the same table execute concurrently.
+     * DERBY-4275.
+     */
+    public void testConcurrentInvalidation() throws Exception {
+        Statement s = createStatement();
+        s.execute("create table d4275(x int)");
+        s.execute("insert into d4275 values 1");
+
+        // Object used by the main thread to tell the helper thread to stop.
+        // The helper thread stops once the list is non-empty.
+        final List stop = Collections.synchronizedList(new ArrayList());
+
+        // Holder for anything thrown by the run() method in the helper thread.
+        final Throwable[] error = new Throwable[1];
+
+        // Set up a helper thread that executes a query against the table
+        // until the main thread tells it to stop.
+        Connection c2 = openDefaultConnection();
+        final PreparedStatement ps = c2.prepareStatement("select * from d4275");
+
+        Thread t = new Thread() {
+            public void run() {
+                try {
+                    while (stop.isEmpty()) {
+                        JDBC.assertSingleValueResultSet(ps.executeQuery(), "1");
+                    }
+                } catch (Throwable t) {
+                    error[0] = t;
+                }
+            }
+        };
+
+        t.start();
+
+        // Compress the table while a query is being executed against the
+        // same table to force invalidation of the running statement. Since
+        // the problem we try to reproduce is timing-dependent, do it 100
+        // times to increase the chance of hitting the bug.
+        try {
+            for (int i = 0; i < 100; i++) {
+                s.execute(
+                    "call syscs_util.syscs_compress_table('APP', 'D4275', 1)");
+            }
+        } finally {
+            // We're done, so tell the helper thread to stop.
+            stop.add(Boolean.TRUE);
+        }
+
+        t.join();
+
+        // Before DERBY-4275, the helper thread used to fail with an error
+        // saying the container was not found.
+        if (error[0] != null) {
+            fail("Helper thread failed", error[0]);
+        }
+
+        // Cleanup.
+        ps.close();
+        c2.close();
+    }
 }

Modified: db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TruncateTableTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TruncateTableTest.java?rev=1143356&r1=1143355&r2=1143356&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TruncateTableTest.java (original)
+++ db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TruncateTableTest.java Wed Jul  6 11:41:41 2011
@@ -26,6 +26,9 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import junit.framework.Test;
 import org.apache.derbyTesting.junit.BaseJDBCTestCase;
 import org.apache.derbyTesting.junit.DatabasePropertyTestSetup;
@@ -300,4 +303,64 @@ public class TruncateTableTest extends B
         truncatorStatement.close();
     }
     
+    /**
+     * Test that statement invalidation works when TRUNCATE TABLE statements
+     * and other statements accessing the same table execute concurrently.
+     * DERBY-4275.
+     */
+    public void testConcurrentInvalidation() throws Exception {
+        Statement s = createStatement();
+        s.execute("create table d4275(x int)");
+
+        // Object used by the main thread to tell the helper thread to stop.
+        // The helper thread stops once the list is non-empty.
+        final List stop = Collections.synchronizedList(new ArrayList());
+
+        // Holder for anything thrown by the run() method in the helper thread.
+        final Throwable[] error = new Throwable[1];
+
+        // Set up a helper thread that executes a query against the table
+        // until the main thread tells it to stop.
+        Connection c2 = openDefaultConnection();
+        final PreparedStatement ps = c2.prepareStatement("select * from d4275");
+
+        Thread t = new Thread() {
+            public void run() {
+                try {
+                    while (stop.isEmpty()) {
+                        JDBC.assertEmpty(ps.executeQuery());
+                    }
+                } catch (Throwable t) {
+                    error[0] = t;
+                }
+            }
+        };
+
+        t.start();
+
+        // Truncate the table while a query is being executed against the
+        // same table to force invalidation of the running statement. Since
+        // the problem we try to reproduce is timing-dependent, do it 100
+        // times to increase the chance of hitting the bug.
+        try {
+            for (int i = 0; i < 100; i++) {
+                s.execute("truncate table d4275");
+            }
+        } finally {
+            // We're done, so tell the helper thread to stop.
+            stop.add(Boolean.TRUE);
+        }
+
+        t.join();
+
+        // Before DERBY-4275, the helper thread used to fail with an error
+        // saying the container was not found.
+        if (error[0] != null) {
+            fail("Helper thread failed", error[0]);
+        }
+
+        // Cleanup.
+        ps.close();
+        c2.close();
+    }
 }