Ruben Laguna’s blog

OpenJPA, HSQLDB and Proper Shutdown

I’m starting to get tired of OpenJPA/HSQLDB setup that I’ve trying: it seems to give more problems than it solves. Now I discovered that the HSQL db wasn’t been properly shutdown and for reasons that I’m investigating, if the HSQL db is not propertly closed (SHUTDOWN command) it’s impossible to reopen it again. It fails with a IndexOutOfBoundsException.

1
2
3
4
5
6
7
8
9
10
11
12
13

1
2
3
4
5
6
7
8
9
10
11
12
13
<span class='line'>Caused by: org.hsqldb.HsqlException: error in script file line: 33 java.io.IOException: java.lang.IndexOutOfBoundsException in statement [SET TABLE PUBLIC.NOTES INDEX '2883070']
</span><span class='line'>at org.hsqldb.Error.error(Error.java:111)
</span><span class='line'>at org.hsqldb.scriptio.ScriptReaderText.readDDL(ScriptReaderText.java:132)
</span><span class='line'>at org.hsqldb.scriptio.ScriptReaderBase.readAll(ScriptReaderBase.java:88)
</span><span class='line'>at org.hsqldb.persist.Log.processScript(Log.java:721)
</span><span class='line'>at org.hsqldb.persist.Log.open(Log.java:187)
</span><span class='line'>at org.hsqldb.persist.Logger.openPersistence(Logger.java:209)
</span><span class='line'>at org.hsqldb.Database.reopen(Database.java:265)
</span><span class='line'>at org.hsqldb.Database.open(Database.java:235)
</span><span class='line'>at org.hsqldb.DatabaseManager.getDatabase(DatabaseManager.java:222)
</span><span class='line'>at org.hsqldb.DatabaseManager.newSession(DatabaseManager.java:145)
</span><span class='line'>at org.hsqldb.jdbc.JDBCConnection.&lt;init>(JDBCConnection.java:3219)
</span><span class='line'>... 59 more</span>

Annoying. This is not OpenJPA fault, but it gets complicated to actually solve it.

The obvious solution was to add a “;shutdown=true” to the openjpa.ConnectionURL property. That works but it makes the database access unbearable slow. Presumably because it makes HSQL to perform a SHUTDOWN each time OpenJPA closes the connection, and I guess that OpenJPA is closing the connection every couple of INSERTs. This is a guess, I couldn’t confirm it but I see a lot of GC (garbage collection) going on between INSERT and INSERT and I though that I could be that.

UPDATE: Now I’m sure that OpenJPA is closing the connection, I can see it in the HSQL logs. There is a way to enable connection pooling in OpenJPA although is non-trivial.

So “;shutdown=true” is not feasible right now, unless there is something that I could do to raise HSQLDB performance to an acceptable level while using this option.

I was forced to issue the SHUTDOWN myself. In my case in close() in a Netbean’s ModuleInstaller. Which I still don’t like because if the application is not propertly closed itself, the DB won’t be SHUTDOWN and the database will be unreadable again.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<span class='line'>public class Installer extends ModuleInstall {
</span><span class='line'>
</span><span class='line'>    private static EntityManagerFactory EMF = null;
</span><span class='line'>    private static EntityManager EM = null;
</span><span class='line'>    private static String connectionURL = null;
</span><span class='line'>    private static final Logger LOG = Logger.getLogger(Installer.class.getName());
</span><span class='line'>
</span><span class='line'>    @Override
</span><span class='line'>    public void close() {
</span><span class='line'>        if (null != EM) {
</span><span class='line'>            //things get cumbersome. We must syncronize access to EM.
</span><span class='line'>            //here and anywhere else where it's used
</span><span class='line'>            synchronized (EM) {
</span><span class='line'>                EM.close();  //we know that there is no active transaction
</span><span class='line'>                             //running because we synchronized the access
</span><span class='line'>                             //and all the other synchonized blocks
</span><span class='line'>                             //never leave the transaction open
</span><span class='line'>                LOG.info("closed EntityManager " + EM);
</span><span class='line'>
</span><span class='line'>                //Issue a SHUTDOWN command via JPA Native Query
</span><span class='line'>                final EntityManager emanager = EMF.createEntityManager();
</span><span class='line'>                LOG.info("JPA Native Query shutdown");                
</span><span class='line'>                emanager.getTransaction().begin();
</span><span class='line'>                emanager.createNativeQuery("SHUTDOWN").executeUpdate();
</span><span class='line'>                emanager.getTransaction().commit();
</span><span class='line'>                emanager.close();
</span><span class='line'>            }
</span><span class='line'>        }
</span><span class='line'>        if (null != EMF) {
</span><span class='line'>            LOG.info("closing EntityManagerFactory " + EMF);
</span><span class='line'>            EMF.close();
</span><span class='line'>        }
</span><span class='line'>
</span><span class='line'>    }
</span><span class='line'>
</span><span class='line'>    public static EntityManager getEntityManager() {
</span><span class='line'>        if (EMF == null) {
</span><span class='line'>            Map properties = new HashMap();
</span><span class='line'>            connectionURL = "jdbc:hsqldb:file:" + System.getProperty("netbeans.user") + "/en4j/db";
</span><span class='line'>            properties.put("openjpa.ConnectionURL", connectionURL);
</span><span class='line'>            EMF = javax.persistence.Persistence.createEntityManagerFactory("JpaEntitiesClassLibraryPU", properties);
</span><span class='line'>        }
</span><span class='line'>
</span><span class='line'>        if (null == EM) {
</span><span class='line'>            EM = EMF.createEntityManager();
</span><span class='line'>        }
</span><span class='line'>        synchronized (EM) {
</span><span class='line'>            return java.beans.Beans.isDesignTime() ? null : EM;
</span><span class='line'>        }
</span><span class='line'>    }
</span><span class='line'>}</span>

As I said the everything gets more complicated because know the entityManager could be accessed simultaneosly by two different threads. The ModuleInstall.close() get invoked from a different thread and suddenly we have to use synchronize blocks arround the EntityManager and check that the EntityManager is still open (with EntityManager.isOpen()) everywhere.

Comments

Copyright © 2015 - Ruben Laguna - Powered by Octopress