Nice work on creating the test case!

Interesting, this is a genuine bug somewhere in the LOB code, and it manifests even with MVCC=false.

The only short-term fix I can see is to set your transaction isolation to TRANSACTION_REPEATABLE_READ.

Thomas, I further reduced the test-case, and I'm including it here.
Note that (for me) it did not fail every single time. I normally let it run for about 15 seconds, and then terminate and try again.
I get a failure rate of about 50%.


package test.TestCase1;

import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestCase1 {
private static final String URL = "jdbc:h2:db/test01;MVCC=TRUE;MULTI_THREADED=0;LOCK_MODE=3;LOCK_TIMEOUT=20000;";

private static final String LONG_STRING = "1111111111111111111111111111111111111111111111111111111111111111111" + "1111111111111111111111111111111111111111111111111111111111111111111".replace("1", "1234567890");

    public TestCase1() {
    }

    /**
* Test case start. After about 10s the exceptions will go to the stdout.
     */
    public void start() throws Exception {
        final Connection conn = connect();

// Create initial schema (will fail on the second time run unless the db
        // file is deleted)
        Statement st = null;
        try {
            st = conn.createStatement();
st.executeUpdate("CREATE TABLE IF NOT EXISTS TestInstance (Id BIGINT generated by default as identity, " + "Description TEXT NOT NULL, Dummy VARCHAR(255) NOT NULL, PRIMARY KEY (Id));");
            conn.commit();
        } catch (Exception e) {
            conn.rollback();
            e.printStackTrace();
        }

        // Add initial row
PreparedStatement pst = conn.prepareStatement("INSERT INTO TestInstance (Description, Dummy) VALUES (?, ?)");
        pst.setString(1, LONG_STRING);
        pst.setString(2, "dummy");
        pst.execute();
        conn.commit();

        if (st != null) {
            st.close();
        }

        // Start the updater thread
        new Thread("updater") {
            @Override
            public void run() {
                try {
                    doUpdates(connect());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();

        // Do the reading in the current thread
        doReads(conn);

        if (!conn.isClosed()) {
            conn.close();
        }
        System.out.println("Closed the database");
    }

    /**
     * Reads all rows from the target table.
     */
    private void doReads(Connection conn) throws Exception {
        while (true) {
            try {
                final Statement st = conn.createStatement();
final ResultSet rs = st.executeQuery("SELECT * FROM TestInstance");

                while (rs.next()) {
                    rs.getInt(1);
                    rs.getString(2);
                    rs.getString(3);
                }

                rs.close();
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

            conn.commit();
            Thread.sleep(50);
        }
    }

    /**
     * Reads the 1st row & then updates it.
     */
    private void doUpdates(Connection conn) throws Exception {
        final PreparedStatement pst = conn
.prepareStatement("UPDATE TestInstance set Description=?, Dummy=? WHERE id=1");

        int i = 0;
        while (true) {
            // Read the instance
            Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM TestInstance WHERE Id=1");

            while (rs.next()) {
                rs.getInt(1);
                rs.getString(2);
                rs.getString(3);
            }
            rs.close();
            st.close();

            // Update the instance
            pst.setString(1, LONG_STRING + i++);
            pst.setString(2, "Dummy");
            pst.execute();

            conn.commit();
            Thread.sleep(50);
        }
    }

    /**
     * Connects to the db.
     */
    private Connection connect() throws Exception {
        Class.forName("org.h2.Driver");

        System.out.println("Connecting to database");

        Connection conn = DriverManager.getConnection(URL);
        conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

        return conn;
    }

    public static void main(String[] args) throws Exception {
        new File("db/test01.h2.db").delete();
        new File("db/test01.lock.db").delete();
        new File("db/test01.trace.db").delete();
        TestCase1 tc1 = new TestCase1();
        tc1.start();
    }
}





--
You received this message because you are subscribed to the Google Groups "H2 
Database" group.
To post to this group, send email to h2-database@googlegroups.com.
To unsubscribe from this group, send email to 
h2-database+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/h2-database?hl=en.

Reply via email to