ITコンサルの日常

ITコンサル会社に勤務する普通のITエンジニアの日常です。

HsqldbでCREATE TABLEできないことがあるらしい

Hsqldb1.8.0.1での話しですが、CREATE TABLEしたのに、プロセスが終了すると消えてしまうという摩訶不思議(?)な話です。
以下のようなコードがあったとします。Hsqldb的には、

  • In-Process (Standalone) Modeで接続
  • tesutesuという名のMEMORY TABLEを作成

ということになります。

package exam;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class HsqldbTest2 {
    public static void main(String[] args) throws Exception
    {
        Class.forName("org.hsqldb.jdbcDriver");
        Connection con = DriverManager.getConnection("jdbc:hsqldb:dat/test", "sa", "");

        Statement stmt = con.createStatement();
        stmt.executeUpdate("CREATE TABLE tesutesu (id int, name varchar(16))");
        
        con.close();
    }
}

このコードを実際に実行してみると、ごく普通に正常終了するので、何事もなくテーブルが作成されたものと思っていたのですが、何気なくもう一回実行してみると、やっぱり正常終了してしまいます。あれ?テーブルが既に存在するから、もうCREATE TABLE出来なくてエラーってのが筋なような気がするのですが、そうなりませんでした。
で、Hsqldbが作成するファイルに注目してみると、*.logってのがトランザクションログで、*.scriptってのが永続データのなので、CREATE TABLEした直後に、*.logに書き込まれていなければいけないのですが、これが書き込まれていないことが分かりました。
(この辺、Appendix C. Hsqldb Database Files and Recoveryに載ってたりします)
で、もう少し調べてみると、*.scriptの中に、

SET WRITE_DELAY 20

というアヤシイ記述が見つかりました。マニュアル(9. SQL Syntax)を見てみると、

  • ログファイルの同期頻度を制御する
  • デフォルトは20[sec]である
  • システムクラッシュ時の消失データ量をコントロールする
  • 0に設定すると、高負荷時にファイルI/O待ちによって性能的な影響を及ぼす (訳が微妙だ。。)
  • 実際には、100[ms]程度が推奨らしい (1日・1システムあたりの信頼性は99.999%)

というわけで、*.logファイルに書かれなかったのは、20秒後にファイル同期するというオプションがあったからということが分かりました。しかし、上記のコードは20秒もかからず終了してしまいますから、In-Processで動作しているHsqldb自体も終了してしまい、結局ファイル同期されず、作ったテーブルも残らないという結論だったようです。
なんか、デフォルトを100[ms]にすればいいのにと思うのは、僕だけでしょうか。
つべこべいわず、

SET WRITE_DELAY 100 MILLIS

のように設定してみましょう。(100[ms]でもだめなら、10[ms]とか)