sagarswathi / h2database

Automatically exported from code.google.com/p/h2database
0 stars 1 forks source link

Reproducible MVStore corruption when killing with running select #613

Open cstenac opened 7 years ago

cstenac commented 7 years ago

H2 1.4.196

It is possible to reproducibly corrupt a H2 DB on MVStore (single process, single thread) when killing the process while it is executing a statement. This appears to only happen if the statement's result set spills to disk (from the stack, it looks like spilling is now done within the MVStore itself ?)

Reproduction code:

package test;

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

public class H2Test {
    public static void main(String[] args) throws Exception {
        Class.forName("org.h2.Driver");

        final String SHORT_STRING = "a quite short string";

        final Connection c = DriverManager.getConnection("jdbc:h2:/tmp/stuff");

        System.out.println("Creating DB");
        try (Statement st = c.createStatement()) {
            st.execute("create table stuff (a varchar)");
            for (int i = 0; i < 40001; i++) {
                st.execute("insert into stuff values ('" + SHORT_STRING + "')");
            }
        }
        c.commit();
        System.out.println("DB created");

        while (true) {
            try (Statement st = c.createStatement()) {
                long before = System.currentTimeMillis();
                System.out.println("Start query");
                st.executeQuery("select * from stuff where a = '" + SHORT_STRING + "' order by a desc");
                System.out.println("Query done in " + (System.currentTimeMillis() - before));
            }
        }
    }
}

Compile and run with java -cp h2-1.4.196.jar:. -Xmx1g test.H2Test

The Xmx1g + 40001 records + order by ensure that the result set spills

While the program is running, kill it abruptly (kill -9)

Then try to reopen /tmp/stuff:

Exception in thread "main" org.h2.jdbc.JdbcSQLException: General error: "java.lang.NullPointerException" [50000-196]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
    at org.h2.message.DbException.get(DbException.java:168)
    at org.h2.message.DbException.convert(DbException.java:295)
    at org.h2.engine.Database.openDatabase(Database.java:307)
    at org.h2.engine.Database.<init>(Database.java:270)
    at org.h2.engine.Engine.openSession(Engine.java:64)
    at org.h2.engine.Engine.openSession(Engine.java:176)
    at org.h2.engine.Engine.createSessionAndValidate(Engine.java:154)
    at org.h2.engine.Engine.createSession(Engine.java:137)
    at org.h2.engine.Engine.createSession(Engine.java:27)
    at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:354)
    at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:116)
    at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:100)
    at org.h2.Driver.connect(Driver.java:69)
    at java.sql.DriverManager.getConnection(DriverManager.java:664)
    at java.sql.DriverManager.getConnection(DriverManager.java:247)
    at org.h2.tools.Shell.runTool(Shell.java:148)
    at org.h2.tools.Shell.main(Shell.java:81)
Caused by: java.lang.NullPointerException
    at org.h2.mvstore.db.ValueDataType.compare(ValueDataType.java:104)
    at org.h2.mvstore.MVMap.compare(MVMap.java:713)
    at org.h2.mvstore.Page.binarySearch(Page.java:334)
    at org.h2.mvstore.MVMap.binarySearch(MVMap.java:466)
    at org.h2.mvstore.MVMap.get(MVMap.java:455)
    at org.h2.mvstore.db.TransactionStore.commit(TransactionStore.java:349)
    at org.h2.mvstore.db.TransactionStore$Transaction.commit(TransactionStore.java:783)
    at org.h2.mvstore.db.MVTableEngine$Store.initTransactions(MVTableEngine.java:254)
    at org.h2.engine.Database.open(Database.java:767)
    at org.h2.engine.Database.openDatabase(Database.java:276)
    ... 14 more

The corruption is reproducible around 80% of times

cstenac commented 7 years ago

Sorry sent it to the wrong repository