db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From krist...@apache.org
Subject svn commit: r834418 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java testing/org/apache/derbyTesting/functionTests/tests/memory/ConnectionHandlingJunit.java
Date Tue, 10 Nov 2009 10:43:14 GMT
Author: kristwaa
Date: Tue Nov 10 10:43:14 2009
New Revision: 834418

URL: http://svn.apache.org/viewvc?rev=834418&view=rev
Log:
DERBY-4432: Memory leak when attempting to boot non-existing database with the in-memory back
end.
Fixed memory leak happening when trying to boot non-existing databases by using a dummy store
to handle operations that don't require a proper store.
Added a regression test (must be run with a small Java heap).
Also changed the existing test by using a discarding log writer to avoid writing a huge log
file to disk (a message is logged for each failed boot).

Patch file: derby-4432-1a-mem_leak_fix.diff


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/ConnectionHandlingJunit.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java?rev=834418&r1=834417&r2=834418&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/io/VFMemoryStorageFactory.java Tue
Nov 10 10:43:14 2009
@@ -47,6 +47,13 @@
     private static final Map DATABASES = new HashMap();
 
     /**
+     * Dummy store used to carry out frequent operations that don't
+     * require a "proper store", for instance getting the canonical name
+     * of the data store.
+     */
+    private static final DataStore DUMMY_STORE = new DataStore("::DUMMY::");
+
+    /**
      * Deletes the database if it exists.
      *
      * @param dbName the database name
@@ -114,10 +121,16 @@
                 if (DATABASES.containsKey(canonicalName)) {
                     // Fetch the existing data store.
                     this.dbData = (DataStore)DATABASES.get(canonicalName);
-                } else {
+                } else if (uniqueName != null) {
                     // Create a new data store.
                     this.dbData = new DataStore(canonicalName);
                     DATABASES.put(canonicalName, dbData);
+                } else {
+                    // We have a database name, but no unique name.
+                    // Assume that the client only wants to do some
+                    // "book-keeping" operations, like getting the
+                    // canonical name.
+                    this.dbData = DUMMY_STORE;
                 }
             }
             // Specify the data directory and the temp directory.
@@ -128,17 +141,13 @@
         // Handle cases where the database name is null, but a system home
         // directory has been specified.
         } else if (home != null) {
-            // Return the "system home directory" and create a temporary
-            // directory for it.
+            // Return the "system home directory" and specify a temporary
+            // directory for it (may never by used).
+            // As databases are created, the dummy will contain the
+            // directory names of the database locations, but the
+            // databases themselves will be stored in separate stores.
             final String absHome = new File(home).getCanonicalPath();
-            synchronized (DATABASES) {
-                dbData = (DataStore)DATABASES.get(absHome);
-                if (dbData == null) {
-                    // Create a new data store for the specified home.
-                    dbData = new DataStore(absHome);
-                    DATABASES.put(absHome, dbData);
-                }
-            }
+            dbData = DUMMY_STORE;
             dataDirectory = new VirtualFile(absHome, dbData);
             tempDir = new VirtualFile(getSeparator() + "tmp", dbData);
         }

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/ConnectionHandlingJunit.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/ConnectionHandlingJunit.java?rev=834418&r1=834417&r2=834418&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/ConnectionHandlingJunit.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/memory/ConnectionHandlingJunit.java
Tue Nov 10 10:43:14 2009
@@ -20,6 +20,7 @@
  */
 package org.apache.derbyTesting.functionTests.tests.memory;
 
+import java.io.Writer;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
@@ -36,7 +37,29 @@
  *  see for example DERBY-2480.
  */
 public class ConnectionHandlingJunit extends BaseJDBCTestCase {
-    
+
+    /**
+     * Returns a log writer that discards all the data written to it.
+     *
+     * @return Writer discarding the log.
+     */
+    public static Writer getLogDiscarder() {
+        // Writer discarding all data written to it.
+        return new Writer() {
+            public void write(char[] cbuf, int off, int len) {
+                // Do nothing.
+            }
+
+            public void flush() {
+                // Do nothing.
+            }
+
+            public void close() {
+                // Do nothing.
+            }
+        };
+    }
+
     /** Creates a new instance of this test class 
      *  @param name The name of this test instance; may determine which test
      *         fixture to run.
@@ -71,6 +94,8 @@
 
             TestCase nonExistentDbTest = new ConnectionHandlingJunit(
                     "driverMgrTestConnectionsToNonexistentDb");
+            TestCase nonExistentDbTestInMem = new ConnectionHandlingJunit(
+                    "driverMgrTestConnectionsToNonexistentDbInMemory");
             
             /* run "driverMgrTestConnectionsToNonexistentDb" in embedded mode only
              * by default, since it is not very useful to continue running in
@@ -78,6 +103,7 @@
              * resources are <i>almost</i> exhausted from the embedded test.
              */
             suite.addTest(nonExistentDbTest);
+            suite.addTest(nonExistentDbTestInMem);
             // to run the test in client/server mode, comment the above line,
             // uncomment the next and recompile.
             //suite.addTest(TestConfiguration.clientServerDecorator(nonExistentDbTest));
@@ -116,10 +142,18 @@
      *         examined using assertions.
      */
     public void driverMgrTestConnectionsToNonexistentDb() throws SQLException {
+        String url = getTestConfiguration().getJDBCUrl("nonexistentDatabase");
+        driverMgrConnectionInitiator(url, false);
+    }
 
+    public void driverMgrTestConnectionsToNonexistentDbInMemory()
+            throws SQLException {
+        driverMgrConnectionInitiator("jdbc:derby:memory:noDbHere", true);
+    }
+
+    private void driverMgrConnectionInitiator(String url, boolean appendId)
+            throws SQLException {
         Connection myInvalidConn = null;
-        
-        String url = getTestConfiguration().getJDBCUrl("nonexistentDatabase");
         // Not using the regular helper methods in super class because
         // we don't want to actually create a database, or connect to an
         // existing one (current helper classes add ";create=true" if the DB
@@ -142,7 +176,8 @@
                 try {
                     // We are expecting an exception here because we are trying to 
                     // connect to a DB that does not exist.
-                    myInvalidConn = DriverManager.getConnection(url);
+                    myInvalidConn = DriverManager.getConnection(
+                            appendId ? url + count : url);
                     // The following may happen because of changes to helper methods
                     // such as TestConfiguration.getJDBCUrl(dbName).
                     fail("Got connection to a DB that should not exist");
@@ -211,6 +246,13 @@
      * @throws SQLException if an unexpected exception is thrown
      */
     private void loadDriver(String url) throws SQLException {
+        // Attempt to make Derby discard the log, as a log message will be
+        // written for every failed connection attempt.
+        // To take effect, the property must be set before the driver is
+        // loaded, which means this test should be run separately.
+        setSystemProperty("derby.stream.error.method",
+                "org.apache.derbyTesting.functionTests.tests.memory." +
+                "ConnectionHandlingJunit.getLogDiscarder");
         try {
             DriverManager.getDriver(url);
         } catch (SQLException e) {



Mime
View raw message