db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r1335423 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/catalog/ testing/org/apache/derbyTesting/functionTests/tests/memory/
Date Tue, 08 May 2012 11:29:58 GMT
Author: kahatlen
Date: Tue May  8 11:29:58 2012
New Revision: 1335423

URL: http://svn.apache.org/viewvc?rev=1335423&view=rev
Log:
DERBY-5730: DataDictionaryImpl leaks references to itself via SYSFUN_AD

Make the AliasDescriptors for SYSFUN functions private to a single
DataDictionaryImpl instance instead of shared between them.

Added:
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/Derby5730Test.java
  (with props)
Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/_Suite.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java?rev=1335423&r1=1335422&r2=1335423&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
Tue May  8 11:29:58 2012
@@ -287,7 +287,7 @@ public final class	DataDictionaryImpl
 	 * Runtime definition of the functions from SYSFUN_FUNCTIONS.
 	 * Populated dynamically as functions are called.
 	 */
-	private static final AliasDescriptor[] SYSFUN_AD =
+	private final AliasDescriptor[] sysfunDescriptors =
 		new AliasDescriptor[SYSFUN_FUNCTIONS.length];
 
 	// the structure that holds all the core table info
@@ -7773,7 +7773,7 @@ public final class	DataDictionaryImpl
 				if (!name.equals(routineName))
 					continue;
 				
-				AliasDescriptor ad = DataDictionaryImpl.SYSFUN_AD[f];
+				AliasDescriptor ad = sysfunDescriptors[f];
 				if (ad == null)
 				{
 					// details[1] Return type
@@ -7810,7 +7810,7 @@ public final class	DataDictionaryImpl
 							AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR,
 							true, ai, null);
 
-					DataDictionaryImpl.SYSFUN_AD[f] = ad;
+					sysfunDescriptors[f] = ad;
 				}
 				list.add(ad);
 			}

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/Derby5730Test.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/Derby5730Test.java?rev=1335423&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/Derby5730Test.java
(added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/Derby5730Test.java
Tue May  8 11:29:58 2012
@@ -0,0 +1,165 @@
+/*
+ * Derby - Class org.apache.derbyTesting.functionTests.tests.memory.Derby5730Test
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.derbyTesting.functionTests.tests.memory;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.BaseTestCase;
+import org.apache.derbyTesting.junit.JDBC;
+import org.apache.derbyTesting.junit.SpawnedProcess;
+
+/**
+ * Regression test for DERBY-5730. Repeatedly boot and shut down a database.
+ * In between call a function in the SYSFUN schema, a different one each time.
+ * Without the fix, a reference to the currently running database instance will
+ * be leaked for each iteration, and eventually an OutOfMemoryError is raised.
+ */
+public class Derby5730Test extends BaseTestCase {
+
+    public Derby5730Test(String name) {
+        super(name);
+    }
+
+    public static Test suite() {
+        // The test case uses DriverManager, so require JDBC 3.0 or higher.
+        if (JDBC.vmSupportsJDBC3()) {
+            return new TestSuite(Derby5730Test.class);
+        }
+        return new TestSuite("Derby5730Test - skipped");
+    }
+
+    /**
+     * Test case for DERBY-5730. The memory leak is only reproduced if the
+     * test case runs with capped heap size and the SYSFUN functions have not
+     * been called previously in the same JVM process. Spawn a new process to
+     * satisfy those requirements.
+     */
+    public void testLeak() throws IOException {
+        String[] cmd = {"-Xmx16M", getClass().getName()};
+        SpawnedProcess sp = new SpawnedProcess(execJavaCmd(cmd), "DERBY-5730");
+        if (sp.complete() != 0) {
+            fail(sp.getFailMessage("Process failed"));
+        }
+    }
+
+    private final static Integer ZERO = Integer.valueOf("0");
+    private final static Integer ONE = Integer.valueOf("1");
+    private final static Integer TWO = Integer.valueOf("2");
+
+    /**
+     * These are the functions in the SYSFUN schema. The second value in each
+     * row tells how many arguments the function takes.
+     */
+    private final static Object[][] FUNCTIONS = {
+        {"ACOS", ONE},
+        {"ASIN", ONE},
+        {"ATAN", ONE},
+        {"ATAN2", TWO},
+        {"COS", ONE},
+        {"SIN", ONE},
+        {"TAN", ONE},
+        {"PI", ZERO},
+        {"DEGREES", ONE},
+        {"RADIANS", ONE},
+        {"LN", ONE},
+        {"LOG", ONE},
+        {"LOG10", ONE},
+        {"EXP", ONE},
+        {"CEIL", ONE},
+        {"CEILING", ONE},
+        {"FLOOR", ONE},
+        {"SIGN", ONE},
+        {"RANDOM", ZERO},
+        {"RAND", ONE},
+        {"COT", ONE},
+        {"COSH", ONE},
+        {"SINH", ONE},
+        {"TANH", ONE},
+    };
+
+    /**
+     * Boot and repeatedly reboot a database, calling SYSFUN functions in
+     * between. Eventually runs out of memory if DERBY-5730 is not fixed.
+     * Must run with capped memory size (-Xmx16M) to expose the memory leak.
+     */
+    public static void main(String[] args) throws SQLException {
+        for (int i = 0; i < FUNCTIONS.length; i++) {
+            Connection c = DriverManager.getConnection(
+                    "jdbc:derby:memory:derby5730;create=true");
+            prepareFunction(c,
+                            (String) FUNCTIONS[i][0],
+                            ((Integer) FUNCTIONS[i][1]).intValue());
+            growDatabaseFootprint(c);
+            c.close();
+            try {
+                DriverManager.getConnection(
+                    "jdbc:derby:memory:derby5730;shutdown=true");
+                fail("Shutdown should throw exception");
+            } catch (SQLException sqle) {
+                BaseJDBCTestCase.assertSQLState("08006", sqle);
+            }
+        }
+    }
+
+    /**
+     * Prepare a call to a function. Close the statement once it is prepared.
+     * Before the bug was fixed, preparing a call to a function in SYSFUN that
+     * hadn't been prepared in the same JVM process, would leak a reference to
+     * the current database instance.
+     */
+    private static void prepareFunction(Connection c, String name, int args)
+            throws SQLException {
+        StringBuffer sql = new StringBuffer("VALUES ");
+        sql.append(name);
+        sql.append('(');
+        for (int i = 0; i < args; i++) {
+            if (i > 0) sql.append(',');
+            sql.append('?');
+        }
+        sql.append(')');
+
+        String sqlText = sql.toString();
+
+        System.out.println(sqlText);
+        PreparedStatement ps = c.prepareStatement(sqlText);
+        ps.close();
+    }
+
+    /**
+     * Perform some database operations so that the internal structures of
+     * the database instance (caches, for example) are filled, and the memory
+     * footprint of the database instance grows. This is done to make the
+     * test case run out of memory faster.
+     */
+    private static void growDatabaseFootprint(Connection c)
+            throws SQLException {
+        DatabaseMetaData dmd = c.getMetaData();
+        JDBC.assertDrainResults(dmd.getColumns(null, "%", "%", "%"));
+        JDBC.assertDrainResults(dmd.getTables(null, "%", "%", null));
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/Derby5730Test.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/_Suite.java?rev=1335423&r1=1335422&r2=1335423&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/_Suite.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/_Suite.java
Tue May  8 11:29:58 2012
@@ -41,6 +41,7 @@ public class _Suite extends BaseJDBCTest
         suite.addTest(MultiByteClobTest.suite());
         suite.addTest(RolesDependencyTest.suite());
         suite.addTest(Derby3009Test.suite());
+        suite.addTest(Derby5730Test.suite());
         suite.addTest(MemoryLeakFixesTest.suite());
 
         // DERBY-5394: Let this test run as the last test - it eats up memory.



Mime
View raw message