提交 6dd1a3f4 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. (work in progress)
上级 77cc7372
......@@ -22,9 +22,9 @@ Change Log
</li><li>Translation: Lubomir Grajciar translated the H2 Console as well as all error message to Slovensky. Thanks a lot!
</li><li>There was a possible Java level deadlock when opening an uninitialized database and using
a file system that also opened a database.
</li><li>When killing the process while the database was writing a checkpoint or while it was closing,
the database could become corrupt. A new test case has been implemented to ensure such
problems can not occur in the future.
</li><li>When killing the process while the database was writing a checkpoint, while it was closing,
or while running recovery (while removing temporary tables from a previous run), the database could become corrupt.
A new test case has been implemented to ensure such problems can not occur in the future.
</li><li>File system: new method FileSystem.setReadOnly.
</li><li>The page size for new databases can now be set in the database URL using ;PAGE_SIZE=512.
Currently this feature is only used to simplify testing.
......
......@@ -464,6 +464,7 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
(don't store / read it). This may increase write / read performance depending on the file system.
</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>Maybe use PhantomReference instead of finalize.
</li></ul>
<h2>Not Planned</h2>
......
......@@ -305,6 +305,10 @@ public class PageDataLeaf extends PageData {
* @return the row
*/
Row getRowAt(int at) {
int test;
if (rows == null || rows.length == 0) {
System.out.println("stop " + getPos());
}
Row r = rows[at];
if (r == null) {
if (firstOverflowPageId == 0) {
......@@ -372,6 +376,10 @@ public class PageDataLeaf extends PageData {
return null;
}
PageDataNode next = (PageDataNode) index.getPage(parentPageId, -1);
int test;
if (next == null || keys == null) {
System.out.println("stop " + getPos());
}
return next.getNextPage(keys[entryCount - 1]);
}
......
......@@ -179,6 +179,7 @@ public class PageStore implements CacheWriter {
private PageDataIndex metaIndex;
private IntIntHashMap metaRootPageId = new IntIntHashMap();
private HashMap<Integer, PageIndex> metaObjects = New.hashMap();
private ArrayList<PageIndex> tempIndexes = New.arrayList();
/**
* The map of reserved pages, to ensure index head pages
......@@ -316,9 +317,23 @@ int test;
log.openForWriting(logFirstTrunkPage, false);
recoveryRunning = false;
checkpoint();
removeOldTempIndexes();
}
}
private void removeOldTempIndexes() {
for (PageIndex index: tempIndexes) {
index.truncate(systemSession);
index.remove(systemSession);
}
if (tempIndexes.size() > 0) {
systemSession.commit(true);
}
metaObjects.clear();
metaObjects.put(-1, metaIndex);
tempIndexes = null;
}
private void writeIndexRowCounts() {
for (PageIndex index: metaObjects.values()) {
index.writeRowCount();
......@@ -1114,29 +1129,52 @@ log.checkpoint();
setReadOnly = true;
}
}
// remove temp tables
// PageDataIndex systemTable = (PageDataIndex) metaObjects.get(0);
// isNew = systemTable == null;
// for (Iterator<PageIndex> it = metaObjects.values().iterator(); it.hasNext();) {
// Index openIndex = it.next();
// if (openIndex.getTable().isTemporary()) {
// openIndex.truncate(systemSession);
// openIndex.remove(systemSession);
// removeMetaIndex(openIndex, systemSession);
// it.remove();
// } else {
// openIndex.close(systemSession);
// }
// }
PageDataIndex systemTable = (PageDataIndex) metaObjects.get(0);
isNew = systemTable == null;
for (Iterator<PageIndex> it = metaObjects.values().iterator(); it.hasNext();) {
Index openIndex = it.next();
PageIndex openIndex = it.next();
if (openIndex.getTable().isTemporary()) {
openIndex.truncate(systemSession);
openIndex.remove(systemSession);
removeMetaIndex(openIndex, systemSession);
it.remove();
tempIndexes.add(openIndex);
// System.out.println("temp: " + openIndex);
} else {
openIndex.close(systemSession);
}
int test;
}
allocatePage(PAGE_ID_META_ROOT);
writeIndexRowCounts();
recoveryRunning = false;
reservedPages = null;
writeBack();
// clear the cache because it contains pages with closed indexes
cache.clear();
freeLists.clear();
metaObjects.clear();
metaObjects.put(-1, metaIndex);
int test;
for (PageIndex index : tempIndexes) {
metaObjects.put(index.getId(), index);
}
if (setReadOnly) {
database.setReadOnly(true);
}
......@@ -1318,14 +1356,17 @@ log.checkpoint();
PageIndex index = metaObjects.get(id);
int rootPageId = index.getRootPageId();
index.getTable().removeIndex(index);
if (index instanceof PageBtreeIndex) {
int test;
// if (index instanceof PageBtreeIndex) {
if (index instanceof PageBtreeIndex || index instanceof PageDelegateIndex) {
if (index.isTemporary()) {
systemSession.removeLocalTempTableIndex(index);
} else {
index.getSchema().remove(index);
}
} else if (index instanceof PageDelegateIndex) {
index.getSchema().remove(index);
// } else if (index instanceof PageDelegateIndex) {
// index.getSchema().remove(index);
}
index.remove(systemSession);
metaObjects.remove(id);
......
......@@ -39,11 +39,11 @@ public class TestPageStoreCoverage extends TestBase {
return;
}
deleteDb("pageStore");
// testMoveRoot();
// testBasic();
// testReadOnly();
// testIncompleteCreate();
// testBackupRestore();
testMoveRoot();
testBasic();
testReadOnly();
testIncompleteCreate();
testBackupRestore();
testTrim();
testLongTransaction();
testRecoverTemp();
......
......@@ -6,8 +6,6 @@
*/
package org.h2.test.unit;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Properties;
......@@ -15,11 +13,11 @@ import org.h2.constant.ErrorCode;
import org.h2.engine.ConnectionInfo;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.message.DbException;
import org.h2.store.fs.FileSystem;
import org.h2.test.TestBase;
import org.h2.test.utils.Recorder;
import org.h2.test.utils.RecordingFileSystem;
import org.h2.util.JdbcUtils;
import org.h2.util.New;
/**
......@@ -31,7 +29,7 @@ public class TestReopen extends TestBase implements Recorder {
private String testDatabase = "memFS:" + TestBase.BASE_TEST_DIR + "/reopen";
private long lastCheck;
private int counter;
private int testEvery = 1 << 10;
private int testEvery = 1 << 4;
private HashSet<String> knownErrors = New.hashSet();
private int max = 103128;
......@@ -88,6 +86,15 @@ System.out.println(System.currentTimeMillis() - time);
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);
} catch (Exception e) {
// failed
int errorCode = 0;
......
......@@ -63,8 +63,8 @@ public class RecordingFileObject implements FileObject {
buff = new byte[len];
System.arraycopy(b, off, buff, 0, len);
}
fs.log(Recorder.WRITE, name, buff, file.getFilePointer());
file.write(b, off, len);
fs.log(Recorder.WRITE, name, buff, file.getFilePointer());
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论