提交 cf291f53 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 6fad76b1
...@@ -196,4 +196,3 @@ td.content { ...@@ -196,4 +196,3 @@ td.content {
.compareN { .compareN {
color: #800; color: #800;
} }
\ No newline at end of file
...@@ -291,6 +291,19 @@ public class SysProperties { ...@@ -291,6 +291,19 @@ public class SysProperties {
*/ */
public static final int REDO_BUFFER_SIZE = getIntSetting("h2.redoBufferSize", 256 * 1024); public static final int REDO_BUFFER_SIZE = getIntSetting("h2.redoBufferSize", 256 * 1024);
/**
* System property <code>h2.reuseSpaceAfter</code> (default: 16).<br />
* Reuse space in database files after this many pages are free.
*/
public static final int REUSE_SPACE_AFTER = getIntSetting("h2.reuseSpaceAfter", 1);
/**
* System property <code>h2.reuseSpaceQuickly</code> (default: true).<br />
* Reuse space in database files quickly.
*/
private int test;
public static final boolean REUSE_SPACE_QUICKLY = getBooleanSetting("h2.reuseSpaceQuickly", true);
/** /**
* System property <code>h2.runFinalize</code> (default: true).<br /> * System property <code>h2.runFinalize</code> (default: true).<br />
* Run finalizers to detect unclosed connections. * Run finalizers to detect unclosed connections.
......
...@@ -33,6 +33,7 @@ import org.h2.util.CacheObject; ...@@ -33,6 +33,7 @@ import org.h2.util.CacheObject;
import org.h2.util.CacheWriter; import org.h2.util.CacheWriter;
import org.h2.util.FileUtils; import org.h2.util.FileUtils;
import org.h2.util.IntArray; import org.h2.util.IntArray;
import org.h2.util.IntHashMap;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.ObjectUtils; import org.h2.util.ObjectUtils;
...@@ -79,6 +80,8 @@ public class DiskFile implements CacheWriter { ...@@ -79,6 +80,8 @@ public class DiskFile implements CacheWriter {
private HashSet potentiallyFreePages; private HashSet potentiallyFreePages;
private int fileBlockCount; private int fileBlockCount;
private IntArray pageOwners; private IntArray pageOwners;
// the latest delete in a page
private IntArray pageDelete; private IntArray pageDelete;
private Cache cache; private Cache cache;
private LogSystem log; private LogSystem log;
...@@ -92,8 +95,7 @@ public class DiskFile implements CacheWriter { ...@@ -92,8 +95,7 @@ public class DiskFile implements CacheWriter {
private int redoBufferSize; private int redoBufferSize;
private int readCount, writeCount; private int readCount, writeCount;
private String mode; private String mode;
private int nextDeleteId = 1;
private int nextDeleteId;
public DiskFile(Database database, String fileName, String mode, boolean dataFile, boolean logChanges, int cacheSize) throws SQLException { public DiskFile(Database database, String fileName, String mode, boolean dataFile, boolean logChanges, int cacheSize) throws SQLException {
reset(); reset();
...@@ -531,6 +533,7 @@ public class DiskFile implements CacheWriter { ...@@ -531,6 +533,7 @@ public class DiskFile implements CacheWriter {
} }
int allocate(Storage storage, int blockCount) throws SQLException { int allocate(Storage storage, int blockCount) throws SQLException {
reuseSpace();
synchronized (database) { synchronized (database) {
if (file == null) { if (file == null) {
throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF); throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF);
...@@ -598,57 +601,62 @@ public class DiskFile implements CacheWriter { ...@@ -598,57 +601,62 @@ public class DiskFile implements CacheWriter {
if (pos + blockCount > fileBlockCount) { if (pos + blockCount > fileBlockCount) {
setBlockCount(pos + blockCount); setBlockCount(pos + blockCount);
} }
int deleteId = 0; uncommittedDelete(session);
if (session != null) {
deleteId = nextDeleteId++;
setUncommittedDelete(session, getPage(pos), deleteId);
}
for (int i = pos; i < pos + blockCount; i++) { for (int i = pos; i < pos + blockCount; i++) {
used.clear(i); used.clear(i);
if ((i % BLOCKS_PER_PAGE == 0) && (pos + blockCount >= i + BLOCKS_PER_PAGE)) { if ((i % BLOCKS_PER_PAGE == 0) && (pos + blockCount >= i + BLOCKS_PER_PAGE)) {
// if this is the first page of a block and if the whole page is free // if this is the first page of a block and if the whole page is free
if (session != null && logChanges) { freePage(getPage(i));
setUncommittedDelete(session, getPage(i), deleteId); }
} else { }
setPageOwner(getPage(i), FREE_PAGE); int start = getPage(pos), end = getPage(pos + blockCount);
for (int i = start; i <= end; i++) {
pageDelete.set(i, nextDeleteId);
}
}
void reuseSpace() throws SQLException {
if (SysProperties.REUSE_SPACE_QUICKLY) {
if (potentiallyFreePages.size() >= SysProperties.REUSE_SPACE_AFTER) {
Session[] sessions = database.getSessions();
int oldest = 0;
for (int i = 0; i < sessions.length; i++) {
int deleteId = sessions[i].getLastUncommittedDelete();
if (oldest == 0 || deleteId < oldest) {
oldest = deleteId;
}
}
for (Iterator it = potentiallyFreePages.iterator(); it.hasNext();) {
int p = ((Integer) it.next()).intValue();
int testingReallyCareful;
if (oldest == 0 /*|| oldest > pageDelete.get(p)*/) {
setPageOwner(p, FREE_PAGE);
it.remove();
}
}
} }
} }
} }
void uncommittedDelete(Session session) throws SQLException {
if (session != null && logChanges && SysProperties.REUSE_SPACE_QUICKLY) {
int deleteId = session.getLastUncommittedDelete();
if (deleteId == 0 || deleteId < nextDeleteId) {
deleteId = ++nextDeleteId;
session.setLastUncommittedDelete(deleteId);
}
}
} }
void freePage(int page) throws SQLException { void freePage(int page) throws SQLException {
if (!logChanges) { if (!logChanges) {
setPageOwner(page, FREE_PAGE); setPageOwner(page, FREE_PAGE);
} else { } else {
int todoTestThis; if (SysProperties.REUSE_SPACE_QUICKLY) {
// synchronized (potentiallyFreePages) { potentiallyFreePages.add(ObjectUtils.getInteger(page));
// potentiallyFreePages.add(ObjectUtils.getInteger(page)); reuseSpace();
// if (potentiallyFreePages.size() > 20) {
// Session[] sessions = database.getSessions();
// int oldest = 0;
// for (int i = 0; i < sessions.length; i++) {
// int deleteId = sessions[i].getLastUncommittedDelete();
// if (oldest == 0 || deleteId < oldest) {
// oldest = deleteId;
// }
// }
// for (Iterator it = potentiallyFreePages.iterator(); it.hasNext();) {
// int p = ((Integer) it.next()).intValue();
// if (oldest == 0 || oldest > pageDelete.get(p)) {
// setPageOwner(p, FREE_PAGE);
////int testing;
////System.out.println("free page " + p);
// it.remove();
// }
// }
// }
// }
} }
} }
private void setUncommittedDelete(Session session, int page, int deleteId) {
session.setLastUncommittedDelete(deleteId);
pageDelete.set(page, deleteId);
} }
int getPage(int pos) { int getPage(int pos) {
...@@ -688,6 +696,10 @@ public class DiskFile implements CacheWriter { ...@@ -688,6 +696,10 @@ public class DiskFile implements CacheWriter {
} }
if (storageId >= 0) { if (storageId >= 0) {
database.getStorage(storageId, this).addPage(page); database.getStorage(storageId, this).addPage(page);
if (SysProperties.REUSE_SPACE_QUICKLY) {
potentiallyFreePages.remove(ObjectUtils.getInteger(page));
pageDelete.set(page, 0);
}
} }
pageOwners.set(page, storageId); pageOwners.set(page, storageId);
} }
......
...@@ -153,15 +153,14 @@ java org.h2.test.TestAll timer ...@@ -153,15 +153,14 @@ java org.h2.test.TestAll timer
/* /*
Extend tests that simulate power off (multiple connections, truncate table, drop table, rename objects,...) Test space re-use
REUSE_SPACE_AFTER=20 or so
sourceDocs.html: move
Automate real power off tests Automate real power off tests
timer test timer test
Test space re-use
enforce javadoc comments for constants
Can sometimes not delete log file? need test case Can sometimes not delete log file? need test case
link to new changelog and roadmap, remove pages from google groups link to new changelog and roadmap, remove pages from google groups
...@@ -175,6 +174,7 @@ Adjust cache memory usage ...@@ -175,6 +174,7 @@ Adjust cache memory usage
Test Recovery with MAX_LOG_FILE_SIZE=1; test with various log file sizes Test Recovery with MAX_LOG_FILE_SIZE=1; test with various log file sizes
History: History:
Empty space is re-used less agressively because this could cause database corruption in some cases.
CSV tool now support lineSeparator CSV tool now support lineSeparator
...@@ -412,10 +412,7 @@ DROP TABLE MY_TEST; ...@@ -412,10 +412,7 @@ DROP TABLE MY_TEST;
new TestLinkedTable().runTest(this); new TestLinkedTable().runTest(this);
new TestListener().runTest(this); new TestListener().runTest(this);
new TestLob().runTest(this); new TestLob().runTest(this);
new TestLogFile().runTest(this);
int todo;
// new TestLogFile().runTest(this);
new TestMemoryUsage().runTest(this); new TestMemoryUsage().runTest(this);
new TestMultiConn().runTest(this); new TestMultiConn().runTest(this);
new TestMultiDimension().runTest(this); new TestMultiDimension().runTest(this);
...@@ -431,7 +428,7 @@ DROP TABLE MY_TEST; ...@@ -431,7 +428,7 @@ DROP TABLE MY_TEST;
new TestSequence().runTest(this); new TestSequence().runTest(this);
int todo2; int todo2;
// new TestSpaceReuse().runTest(this); new TestSpaceReuse().runTest(this);
new TestSpeed().runTest(this); new TestSpeed().runTest(this);
new TestTempTables().runTest(this); new TestTempTables().runTest(this);
...@@ -472,6 +469,8 @@ DROP TABLE MY_TEST; ...@@ -472,6 +469,8 @@ DROP TABLE MY_TEST;
// synth // synth
new TestCrashAPI().runTest(this); new TestCrashAPI().runTest(this);
new TestRandomSQL().runTest(this); new TestRandomSQL().runTest(this);
int test3;
new TestKillRestart().runTest(this); new TestKillRestart().runTest(this);
new TestKillRestartMulti().runTest(this); new TestKillRestartMulti().runTest(this);
......
...@@ -53,7 +53,7 @@ public class TestLogFile extends TestBase { ...@@ -53,7 +53,7 @@ public class TestLogFile extends TestBase {
long length = reconnect(maxFiles); long length = reconnect(maxFiles);
insert(); insert();
long l2 = reconnect(maxFiles); long l2 = reconnect(maxFiles);
trace("l2=" + l2); trace("length:" + length + " l2:" + l2);
check(l2 <= length * 2); check(l2 <= length * 2);
} }
conn.close(); conn.close();
...@@ -90,6 +90,7 @@ public class TestLogFile extends TestBase { ...@@ -90,6 +90,7 @@ public class TestLogFile extends TestBase {
} }
} }
checkLogSize(); checkLogSize();
// stat.execute("TRUNCATE TABLE TEST");
} }
} }
...@@ -137,17 +137,20 @@ public class Doclet { ...@@ -137,17 +137,20 @@ public class Doclet {
int fieldId = 0; int fieldId = 0;
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
FieldDoc field = fields[i]; FieldDoc field = fields[i];
if (!field.isFinal() || !field.isStatic() || !field.isPublic()) { if (skipField(clazz, field)) {
continue; continue;
} }
String name = field.name();
String text = field.commentText(); String text = field.commentText();
if (text == null || text.trim().length() == 0) {
throw new Error("undocumented field? " + clazz.name() + "." + name + " " + field);
}
if (text.startsWith("INTERNAL")) { if (text.startsWith("INTERNAL")) {
continue; continue;
} }
if (fieldId == 0) { if (fieldId == 0) {
writer.println("<br /><table><tr><th colspan=\"2\">Fields</th></tr>"); writer.println("<br /><table><tr><th colspan=\"2\">Fields</th></tr>");
} }
String name = field.name();
String type = getTypeName(true, field.type()); String type = getTypeName(true, field.type());
writer.println("<tr><td class=\"return\">" + type + "</td><td class=\"method\">"); writer.println("<tr><td class=\"return\">" + type + "</td><td class=\"method\">");
String constant = field.constantValueExpression(); String constant = field.constantValueExpression();
...@@ -260,7 +263,7 @@ public class Doclet { ...@@ -260,7 +263,7 @@ public class Doclet {
}); });
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
FieldDoc field = fields[i]; FieldDoc field = fields[i];
if (!field.isFinal() || !field.isStatic() || !field.isPublic()) { if (skipField(clazz, field)) {
continue; continue;
} }
String text = field.commentText(); String text = field.commentText();
...@@ -314,6 +317,13 @@ public class Doclet { ...@@ -314,6 +317,13 @@ public class Doclet {
return text; return text;
} }
private static boolean skipField(ClassDoc clazz, FieldDoc field) {
if (!field.isFinal() || !field.isStatic() || !field.isPublic() || field.containingClass() != clazz) {
return true;
}
return false;
}
private static boolean skipMethod(MethodDoc method) { private static boolean skipMethod(MethodDoc method) {
ClassDoc clazz = method.containingClass(); ClassDoc clazz = method.containingClass();
if (INTERFACES_ONLY && (!clazz.isAbstract() || !method.isAbstract()) && !clazz.isInterface()) { if (INTERFACES_ONLY && (!clazz.isAbstract() || !method.isAbstract()) && !clazz.isInterface()) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论