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 rh...@apache.org on 2009/08/18 17:25:03 UTC
svn commit: r805448 - in /db/derby/code/trunk/java:
engine/org/apache/derby/impl/io/
testing/org/apache/derbyTesting/functionTests/tests/store/
testing/org/apache/derbyTesting/junit/
Author: rhillegas
Date: Tue Aug 18 15:25:03 2009
New Revision: 805448
URL: http://svn.apache.org/viewvc?rev=805448&view=rev
Log:
DERBY-700: Gracefully handle OverlappingFileLockException if someone attempts to boot a database twice.
Added:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ClassLoaderBootTest.java (with props)
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/io/DirFile4.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/io/DirFile4.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/io/DirFile4.java?rev=805448&r1=805447&r2=805448&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/io/DirFile4.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/io/DirFile4.java Tue Aug 18 15:25:03 2009
@@ -33,6 +33,7 @@
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
/**
* This class implements the StorageFile interface using features of Java 1.4 not available in earlier
@@ -186,7 +187,31 @@
SanityManager.THROWASSERT("Unable to Acquire Exclusive Lock on "
+ getPath(), ioe);
}
- }
+ } catch (OverlappingFileLockException ofle)
+ {
+ //
+ // Under Java 6 and later, this exception is raised if the database
+ // has been opened by another Derby instance in a different
+ // ClassLoader in this VM. See DERBY-700.
+ //
+ // The OverlappingFileLockException is raised by the
+ // lockFileChannel.tryLock() call above.
+ //
+ try {
+ lockFileChannel.close();
+ lockFileOpen.close();
+ } catch (IOException e)
+ {
+ if (SanityManager.DEBUG)
+ {
+ SanityManager.THROWASSERT("Error closing file channel "
+ + getPath(), e);
+ }
+ }
+ lockFileChannel=null;
+ lockFileOpen = null;
+ status = EXCLUSIVE_FILE_LOCK_NOT_AVAILABLE;
+ }
return status;
} // end of getExclusiveFileLock
Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ClassLoaderBootTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ClassLoaderBootTest.java?rev=805448&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ClassLoaderBootTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ClassLoaderBootTest.java Tue Aug 18 15:25:03 2009
@@ -0,0 +1,375 @@
+/*
+
+ Derby - Class org.apache.derbyTesting.functionTests.tests.store.ClassLoaderBootTest
+
+ 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.store;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+import java.sql.*;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.io.File;
+import java.net.MalformedURLException;
+import java.security.CodeSource;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.extensions.TestSetup;
+import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
+import org.apache.derbyTesting.junit.DatabasePropertyTestSetup;
+import org.apache.derbyTesting.junit.JDBC;
+import org.apache.derbyTesting.junit.JDBCDataSource;
+import org.apache.derbyTesting.junit.SecurityManagerSetup;
+import org.apache.derbyTesting.junit.SystemPropertyTestSetup;
+
+
+/*
+ * This class tests a database boots using class loaders. Test cases in this
+ * class checks only one instance of a database can exist evenif database is
+ * booted using different class loader instances.
+ */
+public class ClassLoaderBootTest extends BaseJDBCTestCase {
+
+ private static URL derbyClassLocation;
+ static {
+ // find the location of derby jar file or location
+ // of classes.
+ CodeSource cs;
+ try {
+ Class cls = Class.forName("org.apache.derby.database.Database");
+ cs = cls.getProtectionDomain().getCodeSource();
+ } catch (ClassNotFoundException e) {
+ cs = null;
+ }
+
+ if(cs == null )
+ derbyClassLocation = null;
+ else
+ derbyClassLocation = cs.getLocation();
+ }
+
+
+ private ClassLoader loader_1;
+ private ClassLoader loader_2;
+ private ClassLoader mainLoader;
+
+
+ public ClassLoaderBootTest(String name ) {
+ super(name);
+ }
+
+ /**
+ * Runs the tests in the default embedded configuration and then
+ * the client server configuration.
+ */
+ public static Test suite()
+ {
+ TestSuite suite = new TestSuite(ClassLoaderBootTest.class);
+ Test test = suite;
+ TestSetup setup =
+ new CleanDatabaseTestSetup(test) {
+ protected void decorateSQL(Statement s) throws SQLException {
+ // table used to test export.
+ s.execute("CREATE TABLE BOOKS(id int," +
+ "name varchar(30)," +
+ "content clob, " +
+ "pic blob )");
+ }
+ protected void setUp() throws Exception {
+ super.setUp();
+ //shutdown the database.
+ DataSource ds = JDBCDataSource.getDataSource();
+ JDBCDataSource.shutdownDatabase(ds);
+ }
+ };
+ Properties p = new Properties();
+ p.setProperty("derby.infolog.append", "true");
+
+ setup = new SystemPropertyTestSetup(setup,p);
+ return SecurityManagerSetup.noSecurityManager(setup);
+ }
+
+
+ /**
+ * Simple set up, just setup the loaders.
+ * @throws SQLException
+ */
+ protected void setUp() throws Exception
+ {
+ URL[] urls = new URL[]{derbyClassLocation};
+ mainLoader = java.lang.Thread.currentThread().getContextClassLoader();
+
+ loader_1 = createDerbyClassLoader(urls);
+ loader_2 = createDerbyClassLoader(urls);
+ }
+
+
+ /**
+ * Given a loaded class, this
+ * routine asks the class's class loader for information about where the
+ * class was loaded from. Typically, this is a file, which might be
+ * either a class file or a jar file. The routine figures that out, and
+ * returns the name of the file. If it can't figure it out, it returns null
+ */
+ private DerbyURLClassLoader createDerbyClassLoader(final URL[] urls)
+ throws Exception
+ {
+ try {
+ return (DerbyURLClassLoader)AccessController.doPrivileged(
+ new java.security.PrivilegedExceptionAction(){
+ public Object run()
+ {
+ return new DerbyURLClassLoader(urls);
+ }
+ });
+ }catch(PrivilegedActionException pae) {
+ throw pae.getException();
+ }
+ }
+
+
+ /**
+ * Given a loaded class, this
+ * routine asks the class's class loader for information about where the
+ * class was loaded from. Typically, this is a file, which might be
+ * either a class file or a jar file. The routine figures that out, and
+ * returns the name of the file. If it can't figure it out, it returns null
+ */
+ private static URL getFileWhichLoadedClass(final Class cls) throws Exception
+ {
+ try {
+ return (URL)AccessController.doPrivileged(
+ new java.security.PrivilegedExceptionAction(){
+ public Object run()
+ {
+ CodeSource cs = null;
+ cs = cls.getProtectionDomain().getCodeSource ();
+ if ( cs == null )
+ return null;
+ return cs.getLocation ();
+ }
+ });
+ }catch(PrivilegedActionException pae) {
+ throw pae.getException();
+ }
+ }
+
+ private URL getURL(final File file) throws MalformedURLException
+ {
+ try {
+ return (URL) AccessController.doPrivileged
+ (new java.security.PrivilegedExceptionAction(){
+
+ public Object run() throws MalformedURLException{
+ return file.toURL();
+
+ }
+ }
+ );
+ } catch (PrivilegedActionException e) {
+ throw (MalformedURLException) e.getException();
+ }
+ }
+
+ /*
+ * Test booting a database, that was alreadt booted by another class loader.
+ */
+ public void testBootingAnAlreadyBootedDatabase() throws SQLException
+ {
+ //
+ // This test relies on a bug fix in Java 6. Java 5 does not have this
+ // bug fix and will fail this test. See DERBY-700.
+ //
+ if (!JDBC.vmSupportsJDBC4())
+ {
+ println( "The dual boot test only runs on Java 6 and higher." );
+ return;
+ }
+
+ println( "The dual boot test is running." );
+
+ // first boot the database using one loader and attempt
+ // to boot it using another loader, it should fail to boot.
+ try {
+
+ setThreadLoader(loader_1);
+ DataSource ds_1 = JDBCDataSource.getDataSource();
+ Connection conn1 = ds_1.getConnection();
+ // now attemp to boot using another class loader.
+ setThreadLoader(loader_2);
+ try {
+ DataSource ds_2 = JDBCDataSource.getDataSource();
+ ds_2.getConnection();
+ fail("booted database that was already booted by another CLR");
+ } catch (SQLException e) {
+ SQLException ne = e.getNextException();
+ assertPreventDualBoot(ne);
+ }
+
+ // shutdown the database.
+ setThreadLoader(loader_1);
+ JDBCDataSource.shutdownDatabase(ds_1);
+
+ } catch (SQLException se) {
+ dumpSQLException(se);
+ }finally {
+ // set the thread context loader back to the generic one.
+ setThreadLoader(mainLoader);
+ }
+ }
+
+
+ /*
+ * Test booting a database, that was booted and shutdown
+ * by another class loader.
+ */
+ public void testBootingDatabaseShutdownByAnotherCLR() throws SQLException
+ {
+ // first boot the database using one loader and shutdown and then
+ // attempt to boot it using another loader, it should boot.
+ try {
+
+ setThreadLoader(loader_1);
+ DataSource ds_1 = JDBCDataSource.getDataSource();
+ Connection conn1 = ds_1.getConnection();
+ //shutdown the database.
+ JDBCDataSource.shutdownDatabase(ds_1);
+ // now attemp to boot using another class loader.
+ setThreadLoader(loader_2);
+ DataSource ds_2 = JDBCDataSource.getDataSource();
+ ds_2.getConnection();
+ // shutdown the database.
+ JDBCDataSource.shutdownDatabase(ds_2);
+
+ } catch (SQLException se) {
+ dumpSQLException(se);
+ }finally {
+ // set the thread context loader back to the generic one.
+ setThreadLoader(mainLoader);
+ }
+ }
+
+
+
+ private void setThreadLoader(final ClassLoader which) {
+
+ AccessController.doPrivileged
+ (new java.security.PrivilegedAction(){
+
+ public Object run() {
+ java.lang.Thread.currentThread().setContextClassLoader(which);
+ return null;
+ }
+ });
+ }
+
+
+ private static void dumpSQLException(SQLException se)
+ {
+ while (se != null)
+ {
+ se.printStackTrace();
+ se = se.getNextException();
+ }
+ }
+
+ private static void assertPreventDualBoot(SQLException ne) {
+ assertNotNull(ne);
+ String state = ne.getSQLState();
+ assertTrue("Unexpected SQLState:" + state, state.equals("XSDB6"));
+ }
+
+
+
+ /*
+ * Simple specialized URLClassLoader for Derby.
+ * Filters all derby classes out of parent ClassLoader to ensure
+ * that Derby classes are loaded from the URL specified
+ */
+ public class DerbyURLClassLoader extends URLClassLoader {
+
+ /**
+ * @see java.net.URLClassLoader#URLClassLoader(URL[] urls)
+ */
+ public DerbyURLClassLoader(URL[] urls) {
+ super(urls);
+ }
+
+
+ /**
+ * @see java.net.URLClassLoader#URLClassLoader(URL[] urls,
+ * ClassLoader parent)
+ */
+ public DerbyURLClassLoader(URL[] urls, ClassLoader parent) {
+ super(urls, parent);
+
+ }
+
+ /**
+ *@see java.net.URLClassLoader#URLClassLoader(java.net.URL[],
+ * java.lang.ClassLoader, java.net.URLStreamHandlerFactory)
+ */
+ public DerbyURLClassLoader(URL[] urls, ClassLoader parent,
+ URLStreamHandlerFactory factory) {
+ super(urls, parent, factory);
+
+ }
+
+ /* Override the parent class loader to filter out any derby
+ * jars in the classpath. Any classes that start with
+ * "org.apache.derby" will load from the URLClassLoader
+ *
+ * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
+ */
+ protected synchronized Class loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+
+ Class cl = findLoadedClass(name);
+ if (cl == null) {
+ // cut off delegation to parent for certain classes
+ // to ensure loading from the desired source
+ if (!name.startsWith("org.apache.derby")) {
+ cl = getParent().loadClass(name);
+ }
+ }
+ if (cl == null) cl = findClass(name);
+ if (cl == null) throw new ClassNotFoundException();
+ if (resolve) resolveClass(cl);
+ return cl;
+ }
+
+ /*
+ * @see java.lang.ClassLoader#loadClass(java.lang.String)
+ */
+ public Class loadClass(String name) throws ClassNotFoundException {
+ return loadClass(name, false);
+ }
+
+ }
+}
+
Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ClassLoaderBootTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java?rev=805448&r1=805447&r2=805448&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/_Suite.java Tue Aug 18 15:25:03 2009
@@ -53,6 +53,7 @@
TestSuite suite = new TestSuite("store");
suite.addTest(BootAllTest.suite());
+ suite.addTest(ClassLoaderBootTest.suite());
suite.addTest(StreamingColumnTest.suite());
suite.addTest(Derby3625Test.suite());
suite.addTest(PositionedStoreStreamTest.suite());
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java?rev=805448&r1=805447&r2=805448&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/JDBC.java Tue Aug 18 15:25:03 2009
@@ -1,6 +1,6 @@
/*
*
- * Derby - Class org.apache.derbyTesting.functionTests.util.JDBC
+ * Derby - Class org.apache.derbyTesting.junit.JDBC
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with