"Dag H. Wanvik" <[email protected]> writes: > Hi, > > I don't believe this situation has changed since 10.8. I agree this > situation could be improved, so I suggest filing an improvement > request in JIRA. It would also help if you could supply a self > contained repro (not strictly necessary, as I believe the description > is clear enough, but it might just increase the chance of some > developer looking at it...)
There's already a JIRA issue tracking such an improvement: https://issues.apache.org/jira/browse/DERBY-4447 Work on the issue seems to have stalled, though. > > Thanks, > Dag > > On 01. okt. 2013 11:57, Trejkaz wrote: >> 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
