db-derby-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andreas Fredriksson <andreas.fredriks...@digitalroute.com>
Subject Re: Class loading deadlock
Date Tue, 13 Sep 2005 14:55:46 GMT
Replying to myself here because I got curious of wheter a testcase would
reproduce the problem, so I wrote one.

This self-contained test class produces the deadlock in a matter of
seconds on my 2-CPU workstation box; you might need to tweak it a bit to
get the bug on other machines. Sending -QUIT yields:

Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x09fbd2c4 (object 0xabf7d448, a deadlocktest
$TestCL),  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x09fbd4f4 (object 0xabf18b08, a
org.apache.derby.impl.services.reflect.ReflectClassesJava2),
  which is held by "Thread-1"

I noticed the key was to change the second query (with a random item in
the query string itself) so that the query cannot be cached.

Enjoy,
Andreas


deadlocktest.java:

import java.sql.*;

public class deadlocktest {

    public static final String URL = "jdbc:derby:deadlockdb";

    private class TestCL extends ClassLoader {
        protected Class findClass(String name) throws
ClassNotFoundException {
            issueFindQuery();
            return super.findClass(name);
        }
    }

    private class ThreadA implements Runnable {
        public void run() {
            for (;;) {
                String pkg = "nonexistent.package.foo_" +
                    System.currentTimeMillis();
                try {

Thread.currentThread().getContextClassLoader().loadClass(pkg);
                } catch (ClassNotFoundException ignored) {}
            }
        }
    }

    private class ThreadB implements Runnable {
        public void run() {
            for (;;) {
                issueSlowQuery();
            }
        }
    }

    public void issueSlowQuery() {
        try {
            PreparedStatement ps = conn_b.prepareStatement
                ("SELECT id, bar FROM foo WHERE id > 50 AND bar
LIKE ?");
            ps.setString(1, "%1%");
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
            }
            rs.close();
            ps.close();
            try { Thread.sleep(1); } catch (InterruptedException
ignored) {}
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public void issueFindQuery() {
        try {
            PreparedStatement ps = conn_a.prepareStatement
                ("SELECT bar||'" + System.currentTimeMillis() + "' FROM
foo WHERE bar LIKE ?");
            ps.setString(1, "%2%");
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                try { Thread.sleep(1); } catch (InterruptedException
ignored) {}
            }
            rs.close();
            ps.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public void executeNoThrow(Statement s, String sql) {
        try {
            s.execute(sql);
        } catch (SQLException ignored) {}
    }

    public void populate(Connection conn) throws Exception {
        System.out.println("populating");
        Statement s = conn.createStatement();

        // create the table
        executeNoThrow(s, "DROP TABLE foo");
        s.execute("CREATE TABLE foo (id int, bar varchar(60))");
        s.close();

        // populate it
        PreparedStatement ps = conn_a.prepareStatement
            ("INSERT INTO foo VALUES (?, ?)");
        for (int i=0; i<100; ++i) {
            ps.setInt(1, i);
            ps.setString(2, "foobar" + System.currentTimeMillis());
            ps.executeUpdate();
        }
        ps.close();
    }

    private Connection conn_a, conn_b;

    public deadlocktest() throws Exception {
        Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
        conn_a = DriverManager.getConnection(URL + ";create=true");
        populate(conn_a);
        conn_b = DriverManager.getConnection(URL);
        System.out.println("starting threads");
        Thread a = new Thread(new ThreadA());
        Thread b = new Thread(new ThreadB());
        ClassLoader foo = new TestCL();
        a.setContextClassLoader(foo);
        b.setContextClassLoader(foo);
        a.start();
        try { Thread.sleep(2000); } catch (InterruptedException ignored)
{}
        b.start();
    }

    public static void main(String[] args) {
        try {
            new deadlocktest();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

}



Mime
View raw message