db-derby-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Trejkaz <trej...@trypticon.org>
Subject Thread-safe shutdown while other threads might try to reopen
Date Tue, 01 Oct 2013 09:57:53 GMT
Hi all.

We have an application where there are multiple different contexts and
each is isolated from the others (like a webapp). Individual users
close and open databases at will. They're opening their own database
instance rather than sharing an instance directly, in an attempt to
improve the isolation.

When all users have disconnected from the database, the admin expects
to be able to move the database files aside, so we have to shut the
database down when nobody is connected to it.

To try and achieve that, we keep our own static reference count. This
is done somewhat like this (only the real version uses ConcurrentMap,
so there is a lot more boilerplate):

    public class Database {
        private static final Map<String, Integer> connectionCountMap =
            new HashMap<String, Integer>();
        private static final Object connectionCountLock = new Object();

        private final String path;
        private final Connection conn;

        public Database(String path) throws SQLException {
            this.path = path;
            conn = DriverManager.getConnection("jdbc:derby:" + path);
        }

        public void close() throws SQLException {
            conn.close();
            decConnectionCount(path);
        }

        public void incConnectionCount(String path) {
            Integer count = connectionCountMap.get(path);
            if (count == null) {
                count = 1;
            }
            connectionCountMap.put(path, count + 1);
        }

        public void decConnectionCount(String path) {
            Integer count = connectionCountMap.get(path);
            int countAfterDec = count - 1;
            if (countAfterDec > 0) {
                connectionCountMap.put(path, countAfterDec);
            } else {
                connectionCountMap.remove(path);
                try {
                    DriverManager.getConnection("jdbc:derby:" + path +
                         ";shutdown=true");
                } catch (SQLException e) { /* expected */ }
            }
        }
    }

What we are finding is that if multiple threads are accessing the same
database like this, sometimes one of them will be in the middle of
opening a connection while another thread is shutting down the
database. I ended up debugging this into Derby and found that the
thread opening the database would get a null database reference. Derby
would then throw an exception saying the database not found.

So the end result is that despite the database files existing on disk,
Derby would report that the database was not found, which is wrong in
itself...

Anyway, setting the incorrect exception message aside, it seems like
Derby is thread-hostile in this regard. The docs do say only to
shutdown when you know the JVM won't open the database again. The
problem with this is that you never know that, so you can never shut
it down--so the files never get unlocked.

I know I can just slap a synchronized block around these two methods
to make it bulletproof, but there are two problems with this:
  (1) synchronized is slow and Derby's shutdown is not fast at all...
  (2) I don't know what other apps might be open in the same JVM at the same.

So I wonder if anyone with experience in this sort of thing has any
good tips on how to get around the problem.

Also, we're on Derby 10.8, so if anything has been improved in this
regard in the later releases, that would be good to know - it might
just be enough impetus to switch.

TX

Mime
View raw message