/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.unit;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Properties;
import org.h2.constant.ErrorCode;
import org.h2.engine.ConnectionInfo;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.message.DbException;
import org.h2.store.fs.FilePathRec;
import org.h2.store.fs.FileUtils;
import org.h2.store.fs.Recorder;
import org.h2.test.TestBase;
import org.h2.tools.Recover;
import org.h2.util.New;
import org.h2.util.Profiler;
import org.h2.util.Utils;
/**
* A test that calls another test, and after each write operation to the
* database file, it copies the file, and tries to reopen it.
*/
public class TestReopen extends TestBase implements Recorder {
// TODO this is largely a copy of org.h2.util.RecoverTester
private String testDatabase = "memFS:" + TestBase.BASE_TEST_DIR + "/reopen";
private int writeCount = Utils.getProperty("h2.reopenOffset", 0);
private int testEvery = 1 << Utils.getProperty("h2.reopenShift", 6);
private long maxFileSize = Utils.getProperty("h2.reopenMaxFileSize", Integer.MAX_VALUE) * 1024L * 1024;
private int verifyCount;
private HashSet<String> knownErrors = New.hashSet();
private volatile boolean testing;
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
public void test() throws Exception {
System.setProperty("h2.delayWrongPasswordMin", "0");
FilePathRec.register();
FilePathRec.setRecorder(this);
config.reopen = true;
long time = System.currentTimeMillis();
Profiler p = new Profiler();
p.startCollecting();
new TestPageStoreCoverage().init(config).test();
System.out.println(p.getTop(3));
System.out.println(System.currentTimeMillis() - time);
System.out.println("counter: " + writeCount);
}
public void log(int op, String fileName, byte[] data, long x) {
if (op != Recorder.WRITE && op != Recorder.TRUNCATE) {
return;
}
if (!fileName.endsWith(Constants.SUFFIX_PAGE_FILE)) {
return;
}
if (testing) {
// avoid deadlocks
return;
}
testing = true;
try {
logDb(fileName);
} finally {
testing = false;
}
}
private synchronized void logDb(String fileName) {
writeCount++;
if ((writeCount & (testEvery - 1)) != 0) {
return;
}
if (FileUtils.size(fileName) > maxFileSize) {
// System.out.println(fileName + " " + IOUtils.length(fileName));
return;
}
System.out.println("+ write #" + writeCount + " verify #" + verifyCount);
try {
FileUtils.copy(fileName, testDatabase + Constants.SUFFIX_PAGE_FILE);
verifyCount++;
// avoid using the Engine class to avoid deadlocks
Properties p = new Properties();
String userName = getUser();
p.setProperty("user", userName);
p.setProperty("password", getPassword());
ConnectionInfo ci = new ConnectionInfo("jdbc:h2:" + testDatabase + ";FILE_LOCK=NO;TRACE_LEVEL_FILE=0", p);
Database database = new Database(ci, null);
// close the database
Session session = database.getSystemSession();
session.prepare("script to '" + testDatabase + ".sql'").query(0);
session.prepare("shutdown immediately").update();
database.removeSession(null);
// everything OK - return
return;
} catch (DbException e) {
SQLException e2 = DbException.toSQLException(e);
int errorCode = e2.getErrorCode();
if (errorCode == ErrorCode.WRONG_USER_OR_PASSWORD) {
return;
} else if (errorCode == ErrorCode.FILE_ENCRYPTION_ERROR_1) {
return;
}
e.printStackTrace(System.out);
throw e;
} catch (Exception e) {
// failed
int errorCode = 0;
if (e instanceof SQLException) {
errorCode = ((SQLException) e).getErrorCode();
}
if (errorCode == ErrorCode.WRONG_USER_OR_PASSWORD) {
return;
} else if (errorCode == ErrorCode.FILE_ENCRYPTION_ERROR_1) {
return;
}
e.printStackTrace(System.out);
}
System.out.println("begin ------------------------------ " + writeCount);
try {
Recover.execute(fileName.substring(0, fileName.lastIndexOf('/')), null);
} catch (SQLException e) {
// ignore
}
testDatabase += "X";
try {
FileUtils.copy(fileName, testDatabase + Constants.SUFFIX_PAGE_FILE);
// avoid using the Engine class to avoid deadlocks
Properties p = new Properties();
ConnectionInfo ci = new ConnectionInfo("jdbc:h2:" + testDatabase + ";FILE_LOCK=NO", p);
Database database = new Database(ci, null);
// close the database
database.removeSession(null);
} catch (Exception e) {
int errorCode = 0;
if (e instanceof DbException) {
e = ((DbException) e).getSQLException();
errorCode = ((SQLException) e).getErrorCode();
}
if (errorCode == ErrorCode.WRONG_USER_OR_PASSWORD) {
return;
} else if (errorCode == ErrorCode.FILE_ENCRYPTION_ERROR_1) {
return;
}
StringBuilder buff = new StringBuilder();
StackTraceElement[] list = e.getStackTrace();
for (int i = 0; i < 10 && i < list.length; i++) {
buff.append(list[i].toString()).append('\n');
}
String s = buff.toString();
if (!knownErrors.contains(s)) {
System.out.println(writeCount + " code: " + errorCode + " " + e.toString());
e.printStackTrace(System.out);
knownErrors.add(s);
} else {
System.out.println(writeCount + " code: " + errorCode);
}
}
}
}