提交 56737a34 authored 作者: Thomas Mueller's avatar Thomas Mueller

When killing the process while the database was writing a checkpoint or while it…

When killing the process while the database was writing a checkpoint or while it was closing, the database could become corrupt. (improved tests)
上级 cd7f1007
...@@ -465,6 +465,8 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -465,6 +465,8 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Indexes of temporary tables are currently kept in-memory. Is this how it should be? </li><li>Indexes of temporary tables are currently kept in-memory. Is this how it should be?
</li><li>The Shell tool should support the same built-in commands as the H2 Console. </li><li>The Shell tool should support the same built-in commands as the H2 Console.
</li><li>Maybe use PhantomReference instead of finalize. </li><li>Maybe use PhantomReference instead of finalize.
</li><li>Database file name suffix: a way to use no or a different suffix (for example using a slash).
</li><li>Database file name suffix: should only have one dot by default. Example: .h2db
</li></ul> </li></ul>
<h2>Not Planned</h2> <h2>Not Planned</h2>
......
...@@ -9,7 +9,6 @@ package org.h2.test; ...@@ -9,7 +9,6 @@ package org.h2.test;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Properties; import java.util.Properties;
import org.h2.Driver; import org.h2.Driver;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.store.fs.FileSystemDisk; import org.h2.store.fs.FileSystemDisk;
import org.h2.test.bench.TestPerformance; import org.h2.test.bench.TestPerformance;
...@@ -298,27 +297,12 @@ java org.h2.test.TestAll timer ...@@ -298,27 +297,12 @@ java org.h2.test.TestAll timer
test.printSystem(); test.printSystem();
System.setProperty("h2.maxMemoryRowsDistinct", "128"); System.setProperty("h2.maxMemoryRowsDistinct", "128");
System.setProperty("h2.check2", "true"); System.setProperty("h2.check2", "true");
int testingRecovery;
System.setProperty("h2.delayWrongPasswordMin", "0");
System.setProperty("h2.check2", "false");
System.setProperty("h2.lobInDatabase", "true");
System.setProperty("h2.analyzeAuto", "100");
int testingRecovery2;
RecordingFileSystem.register();
// System.setProperty("h2.pageSize", "64");
/* /*
logFlush (& sync?) before writeBack
no commit in compact; logFlush - writeBack - switchLog
special file system with update log
test with small freeList pages, page size 64 test with small freeList pages, page size 64
comparative sql tests
power failure test power failure test
power failure test: MULTI_THREADED=TRUE power failure test: MULTI_THREADED=TRUE
power failure test: larger binaries and additional index. power failure test: larger binaries and additional index.
...@@ -344,7 +328,18 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -344,7 +328,18 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
*/ */
if (args.length > 0) { if (args.length > 0) {
if ("crash".equals(args[0])) { if ("reopen".equals(args[0])) {
System.setProperty("h2.delayWrongPasswordMin", "0");
System.setProperty("h2.check2", "false");
System.setProperty("h2.lobInDatabase", "true");
System.setProperty("h2.analyzeAuto", "100");
// System.setProperty("h2.pageSize", "64");
RecordingFileSystem.register();
test.record = true;
TestReopen reopen = new TestReopen();
RecordingFileSystem.setRecorder(reopen);
test.runTests();
} else if ("crash".equals(args[0])) {
test.endless = true; test.endless = true;
new TestCrashAPI().runTest(test); new TestCrashAPI().runTest(test);
} else if ("synth".equals(args[0])) { } else if ("synth".equals(args[0])) {
...@@ -419,16 +414,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -419,16 +414,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
* Run the tests with a number of different settings. * Run the tests with a number of different settings.
*/ */
private void runTests() throws SQLException { private void runTests() throws SQLException {
int test;
//this.record=true;
if(record) {
System.setProperty("h2.delayWrongPasswordMin", "0");
RecordingFileSystem.register();
TestReopen reopen = new TestReopen();
RecordingFileSystem.setRecorder(reopen);
}
jdk14 = true; jdk14 = true;
smallLog = big = networked = memory = ssl = false; smallLog = big = networked = memory = ssl = false;
diskResult = traceSystemOut = diskUndo = false; diskResult = traceSystemOut = diskUndo = false;
...@@ -673,7 +658,7 @@ if(record) { ...@@ -673,7 +658,7 @@ if(record) {
} }
} }
private void afterTest() throws SQLException { private void afterTest() {
FileSystemDisk.getInstance().deleteRecursive("trace.db", false); FileSystemDisk.getInstance().deleteRecursive("trace.db", false);
if (networked && server != null) { if (networked && server != null) {
server.stop(); server.stop();
......
...@@ -205,14 +205,7 @@ public abstract class TestBase { ...@@ -205,14 +205,7 @@ public abstract class TestBase {
*/ */
protected String getBaseDir() { protected String getBaseDir() {
if (config != null && config.record) { if (config != null && config.record) {
int test;
// return "memFS:" + baseDir;
return RecordingFileSystem.PREFIX + "memFS:" + baseDir; return RecordingFileSystem.PREFIX + "memFS:" + baseDir;
//return RecordingFileSystem.PREFIX + baseDir;
} }
return baseDir; return baseDir;
} }
......
...@@ -33,6 +33,10 @@ public class TestMemoryUsage extends TestBase { ...@@ -33,6 +33,10 @@ public class TestMemoryUsage extends TestBase {
} }
public void test() throws SQLException { public void test() throws SQLException {
if (getBaseDir().indexOf(':') >= 0) {
// can't test in-memory databases
return;
}
testCreateDropLoop(); testCreateDropLoop();
testCreateIndex(); testCreateIndex();
testClob(); testClob();
......
...@@ -13,12 +13,14 @@ import org.h2.constant.ErrorCode; ...@@ -13,12 +13,14 @@ import org.h2.constant.ErrorCode;
import org.h2.engine.ConnectionInfo; import org.h2.engine.ConnectionInfo;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.store.fs.FileSystem; import org.h2.store.fs.FileSystem;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.test.utils.Recorder; import org.h2.test.utils.Recorder;
import org.h2.test.utils.RecordingFileSystem; import org.h2.test.utils.RecordingFileSystem;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.Profiler;
/** /**
* A test that calls another test, and after each write operation to the * A test that calls another test, and after each write operation to the
...@@ -28,10 +30,11 @@ public class TestReopen extends TestBase implements Recorder { ...@@ -28,10 +30,11 @@ public class TestReopen extends TestBase implements Recorder {
private String testDatabase = "memFS:" + TestBase.BASE_TEST_DIR + "/reopen"; private String testDatabase = "memFS:" + TestBase.BASE_TEST_DIR + "/reopen";
private long lastCheck; private long lastCheck;
private int counter; private int writeCount = Integer.parseInt(System.getProperty("reopenOffset", "0"));
private int testEvery = 1 << 4; private int testEvery = 1 << Integer.parseInt(System.getProperty("reopenShift", "8"));
private int verifyCount;
private HashSet<String> knownErrors = New.hashSet(); private HashSet<String> knownErrors = New.hashSet();
private int max = 103128; private volatile boolean testing;
/** /**
* Run just this test. * Run just this test.
...@@ -48,41 +51,59 @@ public class TestReopen extends TestBase implements Recorder { ...@@ -48,41 +51,59 @@ public class TestReopen extends TestBase implements Recorder {
RecordingFileSystem.setRecorder(this); RecordingFileSystem.setRecorder(this);
config.record = true; config.record = true;
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
// Profiler p = new Profiler(); Profiler p = new Profiler();
// p.startCollecting(); p.startCollecting();
new TestPageStoreCoverage().init(config).test(); new TestPageStoreCoverage().init(config).test();
// System.out.println(p.getTop(3)); System.out.println(p.getTop(3));
System.out.println(System.currentTimeMillis() - time); System.out.println(System.currentTimeMillis() - time);
System.out.println("counter: " + counter); System.out.println("counter: " + writeCount);
} }
public synchronized void log(int op, String fileName, byte[] data, long x) { public void log(int op, String fileName, byte[] data, long x) {
if (op != Recorder.WRITE) { if (op != Recorder.WRITE && op != Recorder.SET_LENGTH) {
return; return;
} }
if (!fileName.endsWith(Constants.SUFFIX_PAGE_FILE)) { if (!fileName.endsWith(Constants.SUFFIX_PAGE_FILE)) {
return; return;
} }
counter++; if (testing) {
if ((counter & 1023) == 0) { // avoid deadlocks
return;
}
testing = true;
try {
logDb(fileName);
} finally {
testing = false;
}
}
private synchronized void logDb(String fileName) {
writeCount++;
if ((writeCount & 1023) == 0) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (now > lastCheck + 5000) { if (now > lastCheck + 5000) {
System.out.println(" at " + counter + " of " + max + " " + (100. / max * counter)); System.out.println("+ write #" + writeCount + " verify #" + verifyCount);
//new Exception("currentPosition").printStackTrace(System.out);
lastCheck = now; lastCheck = now;
} }
} }
if ((counter & (testEvery - 1)) != 0) { if ((writeCount & (testEvery - 1)) != 0) {
return; return;
} }
FileSystem.getInstance(fileName).copy(fileName, testDatabase + Constants.SUFFIX_PAGE_FILE); FileSystem.getInstance(fileName).copy(fileName, testDatabase + Constants.SUFFIX_PAGE_FILE);
try { try {
verifyCount++;
// avoid using the Engine class to avoid deadlocks // avoid using the Engine class to avoid deadlocks
Properties p = new Properties(); Properties p = new Properties();
ConnectionInfo ci = new ConnectionInfo("jdbc:h2:" + testDatabase + ";FILE_LOCK=NO", p); 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); Database database = new Database(ci, null);
// close the database // close the database
Session session = database.getSystemSession();
session.prepare("shutdown immediately").update();
database.removeSession(null); database.removeSession(null);
// everything OK - return // everything OK - return
return; return;
...@@ -108,7 +129,7 @@ System.out.println(System.currentTimeMillis() - time); ...@@ -108,7 +129,7 @@ System.out.println(System.currentTimeMillis() - time);
} }
e.printStackTrace(System.out); e.printStackTrace(System.out);
} }
System.out.println("begin ------------------------------ " + counter); System.out.println("begin ------------------------------ " + writeCount);
testDatabase += "X"; testDatabase += "X";
FileSystem.getInstance(fileName).copy(fileName, testDatabase + Constants.SUFFIX_PAGE_FILE); FileSystem.getInstance(fileName).copy(fileName, testDatabase + Constants.SUFFIX_PAGE_FILE);
try { try {
...@@ -135,11 +156,11 @@ System.out.println(System.currentTimeMillis() - time); ...@@ -135,11 +156,11 @@ System.out.println(System.currentTimeMillis() - time);
} }
String s = buff.toString(); String s = buff.toString();
if (!knownErrors.contains(s)) { if (!knownErrors.contains(s)) {
System.out.println(counter + " code: " + errorCode + " " + e.toString()); System.out.println(writeCount + " code: " + errorCode + " " + e.toString());
e.printStackTrace(System.out); e.printStackTrace(System.out);
knownErrors.add(s); knownErrors.add(s);
} else { } else {
System.out.println(counter + " code: " + errorCode); System.out.println(writeCount + " code: " + errorCode);
} }
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论